Merge "Added BUGREPORT_OPTION_TELEPHONY."
diff --git a/Android.mk b/Android.mk
index ef97549..8e8b95a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -262,8 +262,9 @@
 	core/java/android/os/storage/IObbActionListener.aidl \
 	core/java/android/security/IKeystoreService.aidl \
 	core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl \
-	core/java/android/service/autofill/IAutoFillCallback.aidl \
+	core/java/android/service/autofill/IAutoFillAppCallback.aidl \
 	core/java/android/service/autofill/IAutoFillManagerService.aidl \
+	core/java/android/service/autofill/IAutoFillServerCallback.aidl \
 	core/java/android/service/autofill/IAutoFillService.aidl \
 	core/java/android/service/carrier/ICarrierService.aidl \
 	core/java/android/service/carrier/ICarrierMessagingCallback.aidl \
diff --git a/api/current.txt b/api/current.txt
index a4402bb..9f6d358 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6368,7 +6368,8 @@
 
   public static class AssistStructure.ViewNode {
     method public float getAlpha();
-    method public int getAutoFillId();
+    method public android.view.autofill.AutoFillId getAutoFillId();
+    method public android.view.autofill.AutoFillType getAutoFillType();
     method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
     method public int getChildCount();
     method public java.lang.String getClassName();
@@ -6784,6 +6785,7 @@
     method protected android.view.View getErrorView();
     method protected void prepareView(android.view.View);
     method public void setAppWidget(int, android.appwidget.AppWidgetProviderInfo);
+    method public void setAsyncExecutor(java.util.concurrent.Executor);
     method public void updateAppWidget(android.widget.RemoteViews);
     method public void updateAppWidgetOptions(android.os.Bundle);
     method public void updateAppWidgetSize(android.os.Bundle, int, int, int, int);
@@ -23999,11 +24001,8 @@
     method public boolean requestBandwidthUpdate(android.net.Network);
     method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
     method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent);
-    method public deprecated boolean requestRouteToHost(int, int);
     method public deprecated void setNetworkPreference(int);
     method public static deprecated boolean setProcessDefaultNetwork(android.net.Network);
-    method public deprecated int startUsingNetworkFeature(int, java.lang.String);
-    method public deprecated int stopUsingNetworkFeature(int, java.lang.String);
     method public void unregisterNetworkCallback(android.net.ConnectivityManager.NetworkCallback);
     method public void unregisterNetworkCallback(android.app.PendingIntent);
     field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
@@ -28580,7 +28579,7 @@
     method public void surfaceChanged(android.view.SurfaceHolder, int, int, int);
     method public void surfaceCreated(android.view.SurfaceHolder);
     method public void surfaceDestroyed(android.view.SurfaceHolder);
-    method public void surfaceRedrawNeeded(android.view.SurfaceHolder);
+    method public deprecated void surfaceRedrawNeeded(android.view.SurfaceHolder);
     field public static final int DEBUG_CHECK_GL_ERROR = 1; // 0x1
     field public static final int DEBUG_LOG_GL_CALLS = 2; // 0x2
     field public static final int RENDERMODE_CONTINUOUSLY = 1; // 0x1
@@ -35042,26 +35041,19 @@
     method public void onDisconnected();
     method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback);
     method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.SaveCallback);
+    field public static final java.lang.String EXTRA_DATASET_EXTRAS = "android.service.autofill.extra.DATASET_EXTRAS";
+    field public static final java.lang.String EXTRA_RESPONSE_EXTRAS = "android.service.autofill.extra.RESPONSE_EXTRAS";
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
   }
 
   public final class FillCallback {
     method public void onFailure(java.lang.CharSequence);
-    method public void onSuccess(android.service.autofill.FillCallback.FillData);
-  }
-
-  public static final class FillCallback.FillData {
-  }
-
-  public static class FillCallback.FillData.Builder {
-    ctor public FillCallback.FillData.Builder();
-    method public android.service.autofill.FillCallback.FillData build();
-    method public android.service.autofill.FillCallback.FillData.Builder setTextField(int, java.lang.String);
+    method public void onSuccess(android.view.autofill.FillResponse);
   }
 
   public final class SaveCallback {
     method public void onFailure(java.lang.CharSequence);
-    method public void onSuccess(int[]);
+    method public void onSuccess(android.view.autofill.AutoFillId[]);
   }
 
 }
@@ -36726,6 +36718,7 @@
     method public void unhold();
     method public void unregisterCallback(android.telecom.Call.Callback);
     field public static final java.lang.String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts";
+    field public static final java.lang.String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS = "android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS";
     field public static final int STATE_ACTIVE = 4; // 0x4
     field public static final int STATE_CONNECTING = 9; // 0x9
     field public static final int STATE_DIALING = 1; // 0x1
@@ -39459,6 +39452,7 @@
     method public android.text.StaticLayout.Builder setHyphenationFrequency(int);
     method public android.text.StaticLayout.Builder setIncludePad(boolean);
     method public android.text.StaticLayout.Builder setIndents(int[], int[]);
+    method public android.text.StaticLayout.Builder setJustify(boolean);
     method public android.text.StaticLayout.Builder setLineSpacing(float, float);
     method public android.text.StaticLayout.Builder setMaxLines(int);
     method public android.text.StaticLayout.Builder setText(java.lang.CharSequence);
@@ -43067,6 +43061,7 @@
 
   public static abstract interface SurfaceHolder.Callback2 implements android.view.SurfaceHolder.Callback {
     method public abstract void surfaceRedrawNeeded(android.view.SurfaceHolder);
+    method public default void surfaceRedrawNeededAsync(android.view.SurfaceHolder, java.lang.Runnable);
   }
 
   public class SurfaceView extends android.view.View {
@@ -43147,6 +43142,7 @@
     method public void addTouchables(java.util.ArrayList<android.view.View>);
     method public android.view.ViewPropertyAnimator animate();
     method public void announceForAccessibility(java.lang.CharSequence);
+    method public void autoFill(android.view.autofill.AutoFillValue);
     method protected boolean awakenScrollBars();
     method protected boolean awakenScrollBars(int);
     method protected boolean awakenScrollBars(int, boolean);
@@ -43198,8 +43194,8 @@
     method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
     method public boolean dispatchNestedScroll(int, int, int, int, int[]);
     method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public deprecated void dispatchProvideStructure(android.view.ViewStructure);
-    method public void dispatchProvideStructure(android.view.ViewStructure, int);
+    method public void dispatchProvideAutoFillStructure(android.view.ViewStructure, int);
+    method public void dispatchProvideStructure(android.view.ViewStructure);
     method protected void dispatchRestoreInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSaveInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSetActivated(boolean);
@@ -43234,6 +43230,8 @@
     method public float getAlpha();
     method public android.view.animation.Animation getAnimation();
     method public android.os.IBinder getApplicationWindowToken();
+    method public android.view.autofill.AutoFillType getAutoFillType();
+    method public android.view.autofill.VirtualViewDelegate getAutoFillVirtualViewDelegate(android.view.autofill.VirtualViewDelegate.Callback);
     method public android.graphics.drawable.Drawable getBackground();
     method public android.content.res.ColorStateList getBackgroundTintList();
     method public android.graphics.PorterDuff.Mode getBackgroundTintMode();
@@ -43470,10 +43468,10 @@
     method protected void onMeasure(int, int);
     method protected void onOverScrolled(int, int, boolean, boolean);
     method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public deprecated void onProvideStructure(android.view.ViewStructure);
-    method public void onProvideStructure(android.view.ViewStructure, int);
-    method public deprecated void onProvideVirtualStructure(android.view.ViewStructure);
-    method public void onProvideVirtualStructure(android.view.ViewStructure, int);
+    method public void onProvideAutoFillStructure(android.view.ViewStructure, int);
+    method public void onProvideAutoFillVirtualStructure(android.view.ViewStructure, int);
+    method public void onProvideStructure(android.view.ViewStructure);
+    method public void onProvideVirtualStructure(android.view.ViewStructure);
     method public android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int);
     method protected void onRestoreInstanceState(android.os.Parcelable);
     method public void onRtlPropertiesChanged(int);
@@ -43680,8 +43678,8 @@
     field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
     field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
     field public static final android.util.Property<android.view.View, java.lang.Float> ALPHA;
-    field public static final int ASSIST_FLAG_NON_SANITIZED_TEXT = 2; // 0x2
-    field public static final int ASSIST_FLAG_SANITIZED_TEXT = 1; // 0x1
+    field public static final int AUTO_FILL_FLAG_TYPE_FILL = 1; // 0x1
+    field public static final int AUTO_FILL_FLAG_TYPE_SAVE = 2; // 0x2
     field public static final int DRAG_FLAG_GLOBAL = 256; // 0x100
     field public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 64; // 0x40
     field public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 128; // 0x80
@@ -44311,6 +44309,7 @@
     method public abstract int addChildCount(int);
     method public abstract void asyncCommit();
     method public abstract android.view.ViewStructure asyncNewChild(int);
+    method public abstract android.view.ViewStructure asyncNewChild(int, int);
     method public abstract int getChildCount();
     method public abstract android.os.Bundle getExtras();
     method public abstract java.lang.CharSequence getHint();
@@ -44319,9 +44318,11 @@
     method public abstract int getTextSelectionStart();
     method public abstract boolean hasExtras();
     method public abstract android.view.ViewStructure newChild(int);
+    method public abstract android.view.ViewStructure newChild(int, int);
     method public abstract void setAccessibilityFocused(boolean);
     method public abstract void setActivated(boolean);
     method public abstract void setAlpha(float);
+    method public abstract void setAutoFillType(android.view.autofill.AutoFillType);
     method public abstract void setCheckable(boolean);
     method public abstract void setChecked(boolean);
     method public abstract void setChildCount(int);
@@ -45542,6 +45543,80 @@
 
 }
 
+package android.view.autofill {
+
+  public final class AutoFillId implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillId> CREATOR;
+  }
+
+  public final class AutoFillType implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.view.autofill.AutoFillType forList();
+    method public static android.view.autofill.AutoFillType forText(int);
+    method public static android.view.autofill.AutoFillType forToggle();
+    method public int getSubType();
+    method public boolean isList();
+    method public boolean isText();
+    method public boolean isToggle();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillType> CREATOR;
+  }
+
+  public final class AutoFillValue implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.view.autofill.AutoFillValue forList(int);
+    method public static android.view.autofill.AutoFillValue forText(java.lang.CharSequence);
+    method public static android.view.autofill.AutoFillValue forToggle(boolean);
+    method public int getListValue();
+    method public java.lang.CharSequence getTextValue();
+    method public boolean getToggleValue();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillValue> CREATOR;
+  }
+
+  public final class Dataset implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.Dataset> CREATOR;
+  }
+
+  public static final class Dataset.Builder {
+    ctor public Dataset.Builder(java.lang.CharSequence);
+    method public android.view.autofill.Dataset build();
+    method public android.view.autofill.Dataset.Builder setExtras(android.os.Bundle);
+    method public android.view.autofill.Dataset.Builder setValue(android.view.autofill.AutoFillId, android.view.autofill.AutoFillValue);
+  }
+
+  public final class FillResponse implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.FillResponse> CREATOR;
+  }
+
+  public static final class FillResponse.Builder {
+    ctor public FillResponse.Builder();
+    method public android.view.autofill.FillResponse.Builder addDataset(android.view.autofill.Dataset);
+    method public android.view.autofill.FillResponse.Builder addSavableFields(android.view.autofill.AutoFillId...);
+    method public android.view.autofill.FillResponse build();
+    method public android.view.autofill.FillResponse.Builder setExtras(android.os.Bundle);
+  }
+
+  public abstract class VirtualViewDelegate {
+    ctor public VirtualViewDelegate();
+    method public abstract void autoFill(int, android.view.autofill.AutoFillValue);
+  }
+
+  public static abstract class VirtualViewDelegate.Callback {
+    ctor public VirtualViewDelegate.Callback();
+    method public void onFocusChanged(int, boolean);
+    method public void onNodeRemoved(int...);
+    method public void onValueChanged(int);
+  }
+
+}
+
 package android.view.inputmethod {
 
   public class BaseInputConnection implements android.view.inputmethod.InputConnection {
@@ -48987,6 +49062,7 @@
     method public boolean getIncludeFontPadding();
     method public android.os.Bundle getInputExtras(boolean);
     method public int getInputType();
+    method public boolean getJustify();
     method public final android.text.method.KeyListener getKeyListener();
     method public final android.text.Layout getLayout();
     method public float getLetterSpacing();
@@ -49095,6 +49171,7 @@
     method public void setIncludeFontPadding(boolean);
     method public void setInputExtras(int) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public void setInputType(int);
+    method public void setJustify(boolean);
     method public void setKeyListener(android.text.method.KeyListener);
     method public void setLetterSpacing(float);
     method public void setLineSpacing(float, float);
diff --git a/api/removed.txt b/api/removed.txt
index d7a8bce..ab22b6e 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -126,6 +126,12 @@
 
 package android.net {
 
+  public class ConnectivityManager {
+    method public deprecated boolean requestRouteToHost(int, int);
+    method public deprecated int startUsingNetworkFeature(int, java.lang.String);
+    method public deprecated int stopUsingNetworkFeature(int, java.lang.String);
+  }
+
   public abstract class PskKeyManager {
     ctor public PskKeyManager();
     field public static final int MAX_IDENTITY_HINT_LENGTH_BYTES = 128; // 0x80
diff --git a/api/system-current.txt b/api/system-current.txt
index 2ec5643..f2b0eae 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6423,6 +6423,8 @@
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL";
     field public static final deprecated java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM";
     field public static final java.lang.String EXTRA_PROVISIONING_DISCLAIMERS = "android.app.extra.PROVISIONING_DISCLAIMERS";
@@ -6435,8 +6437,10 @@
     field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
     field public static final java.lang.String EXTRA_PROVISIONING_LOGO_URI = "android.app.extra.PROVISIONING_LOGO_URI";
     field public static final java.lang.String EXTRA_PROVISIONING_MAIN_COLOR = "android.app.extra.PROVISIONING_MAIN_COLOR";
+    field public static final java.lang.String EXTRA_PROVISIONING_ORGANIZATION_NAME = "android.app.extra.PROVISIONING_ORGANIZATION_NAME";
     field public static final java.lang.String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
     field public static final java.lang.String EXTRA_PROVISIONING_SKIP_USER_CONSENT = "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
+    field public static final java.lang.String EXTRA_PROVISIONING_SUPPORT_URL = "android.app.extra.PROVISIONING_SUPPORT_URL";
     field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
     field public static final java.lang.String EXTRA_PROVISIONING_WIFI_HIDDEN = "android.app.extra.PROVISIONING_WIFI_HIDDEN";
     field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PAC_URL = "android.app.extra.PROVISIONING_WIFI_PAC_URL";
@@ -6571,7 +6575,8 @@
 
   public static class AssistStructure.ViewNode {
     method public float getAlpha();
-    method public int getAutoFillId();
+    method public android.view.autofill.AutoFillId getAutoFillId();
+    method public android.view.autofill.AutoFillType getAutoFillType();
     method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
     method public int getChildCount();
     method public java.lang.String getClassName();
@@ -7098,6 +7103,7 @@
     method protected android.view.View getErrorView();
     method protected void prepareView(android.view.View);
     method public void setAppWidget(int, android.appwidget.AppWidgetProviderInfo);
+    method public void setAsyncExecutor(java.util.concurrent.Executor);
     method public void updateAppWidget(android.widget.RemoteViews);
     method public void updateAppWidgetOptions(android.os.Bundle);
     method public void updateAppWidgetSize(android.os.Bundle, int, int, int, int);
@@ -25791,14 +25797,11 @@
     method public boolean requestBandwidthUpdate(android.net.Network);
     method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
     method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent);
-    method public deprecated boolean requestRouteToHost(int, int);
     method public deprecated void setNetworkPreference(int);
     method public static deprecated boolean setProcessDefaultNetwork(android.net.Network);
     method public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
     method public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
-    method public deprecated int startUsingNetworkFeature(int, java.lang.String);
     method public void stopTethering(int);
-    method public deprecated int stopUsingNetworkFeature(int, java.lang.String);
     method public void unregisterNetworkCallback(android.net.ConnectivityManager.NetworkCallback);
     method public void unregisterNetworkCallback(android.app.PendingIntent);
     field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
@@ -31144,7 +31147,7 @@
     method public void surfaceChanged(android.view.SurfaceHolder, int, int, int);
     method public void surfaceCreated(android.view.SurfaceHolder);
     method public void surfaceDestroyed(android.view.SurfaceHolder);
-    method public void surfaceRedrawNeeded(android.view.SurfaceHolder);
+    method public deprecated void surfaceRedrawNeeded(android.view.SurfaceHolder);
     field public static final int DEBUG_CHECK_GL_ERROR = 1; // 0x1
     field public static final int DEBUG_LOG_GL_CALLS = 2; // 0x2
     field public static final int RENDERMODE_CONTINUOUSLY = 1; // 0x1
@@ -37905,26 +37908,19 @@
     method public void onDisconnected();
     method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback);
     method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.SaveCallback);
+    field public static final java.lang.String EXTRA_DATASET_EXTRAS = "android.service.autofill.extra.DATASET_EXTRAS";
+    field public static final java.lang.String EXTRA_RESPONSE_EXTRAS = "android.service.autofill.extra.RESPONSE_EXTRAS";
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
   }
 
   public final class FillCallback {
     method public void onFailure(java.lang.CharSequence);
-    method public void onSuccess(android.service.autofill.FillCallback.FillData);
-  }
-
-  public static final class FillCallback.FillData {
-  }
-
-  public static class FillCallback.FillData.Builder {
-    ctor public FillCallback.FillData.Builder();
-    method public android.service.autofill.FillCallback.FillData build();
-    method public android.service.autofill.FillCallback.FillData.Builder setTextField(int, java.lang.String);
+    method public void onSuccess(android.view.autofill.FillResponse);
   }
 
   public final class SaveCallback {
     method public void onFailure(java.lang.CharSequence);
-    method public void onSuccess(int[]);
+    method public void onSuccess(android.view.autofill.AutoFillId[]);
   }
 
 }
@@ -39660,6 +39656,7 @@
     method public void unhold();
     method public void unregisterCallback(android.telecom.Call.Callback);
     field public static final java.lang.String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts";
+    field public static final java.lang.String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS = "android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS";
     field public static final int STATE_ACTIVE = 4; // 0x4
     field public static final int STATE_CONNECTING = 9; // 0x9
     field public static final int STATE_DIALING = 1; // 0x1
@@ -42677,6 +42674,7 @@
     method public android.text.StaticLayout.Builder setHyphenationFrequency(int);
     method public android.text.StaticLayout.Builder setIncludePad(boolean);
     method public android.text.StaticLayout.Builder setIndents(int[], int[]);
+    method public android.text.StaticLayout.Builder setJustify(boolean);
     method public android.text.StaticLayout.Builder setLineSpacing(float, float);
     method public android.text.StaticLayout.Builder setMaxLines(int);
     method public android.text.StaticLayout.Builder setText(java.lang.CharSequence);
@@ -46285,6 +46283,7 @@
 
   public static abstract interface SurfaceHolder.Callback2 implements android.view.SurfaceHolder.Callback {
     method public abstract void surfaceRedrawNeeded(android.view.SurfaceHolder);
+    method public default void surfaceRedrawNeededAsync(android.view.SurfaceHolder, java.lang.Runnable);
   }
 
   public class SurfaceView extends android.view.View {
@@ -46365,6 +46364,7 @@
     method public void addTouchables(java.util.ArrayList<android.view.View>);
     method public android.view.ViewPropertyAnimator animate();
     method public void announceForAccessibility(java.lang.CharSequence);
+    method public void autoFill(android.view.autofill.AutoFillValue);
     method protected boolean awakenScrollBars();
     method protected boolean awakenScrollBars(int);
     method protected boolean awakenScrollBars(int, boolean);
@@ -46416,8 +46416,8 @@
     method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
     method public boolean dispatchNestedScroll(int, int, int, int, int[]);
     method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public deprecated void dispatchProvideStructure(android.view.ViewStructure);
-    method public void dispatchProvideStructure(android.view.ViewStructure, int);
+    method public void dispatchProvideAutoFillStructure(android.view.ViewStructure, int);
+    method public void dispatchProvideStructure(android.view.ViewStructure);
     method protected void dispatchRestoreInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSaveInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSetActivated(boolean);
@@ -46452,6 +46452,8 @@
     method public float getAlpha();
     method public android.view.animation.Animation getAnimation();
     method public android.os.IBinder getApplicationWindowToken();
+    method public android.view.autofill.AutoFillType getAutoFillType();
+    method public android.view.autofill.VirtualViewDelegate getAutoFillVirtualViewDelegate(android.view.autofill.VirtualViewDelegate.Callback);
     method public android.graphics.drawable.Drawable getBackground();
     method public android.content.res.ColorStateList getBackgroundTintList();
     method public android.graphics.PorterDuff.Mode getBackgroundTintMode();
@@ -46688,10 +46690,10 @@
     method protected void onMeasure(int, int);
     method protected void onOverScrolled(int, int, boolean, boolean);
     method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public deprecated void onProvideStructure(android.view.ViewStructure);
-    method public void onProvideStructure(android.view.ViewStructure, int);
-    method public deprecated void onProvideVirtualStructure(android.view.ViewStructure);
-    method public void onProvideVirtualStructure(android.view.ViewStructure, int);
+    method public void onProvideAutoFillStructure(android.view.ViewStructure, int);
+    method public void onProvideAutoFillVirtualStructure(android.view.ViewStructure, int);
+    method public void onProvideStructure(android.view.ViewStructure);
+    method public void onProvideVirtualStructure(android.view.ViewStructure);
     method public android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int);
     method protected void onRestoreInstanceState(android.os.Parcelable);
     method public void onRtlPropertiesChanged(int);
@@ -46898,8 +46900,8 @@
     field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
     field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
     field public static final android.util.Property<android.view.View, java.lang.Float> ALPHA;
-    field public static final int ASSIST_FLAG_NON_SANITIZED_TEXT = 2; // 0x2
-    field public static final int ASSIST_FLAG_SANITIZED_TEXT = 1; // 0x1
+    field public static final int AUTO_FILL_FLAG_TYPE_FILL = 1; // 0x1
+    field public static final int AUTO_FILL_FLAG_TYPE_SAVE = 2; // 0x2
     field public static final int DRAG_FLAG_GLOBAL = 256; // 0x100
     field public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 64; // 0x40
     field public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 128; // 0x80
@@ -47529,6 +47531,7 @@
     method public abstract int addChildCount(int);
     method public abstract void asyncCommit();
     method public abstract android.view.ViewStructure asyncNewChild(int);
+    method public abstract android.view.ViewStructure asyncNewChild(int, int);
     method public abstract int getChildCount();
     method public abstract android.os.Bundle getExtras();
     method public abstract java.lang.CharSequence getHint();
@@ -47537,9 +47540,11 @@
     method public abstract int getTextSelectionStart();
     method public abstract boolean hasExtras();
     method public abstract android.view.ViewStructure newChild(int);
+    method public abstract android.view.ViewStructure newChild(int, int);
     method public abstract void setAccessibilityFocused(boolean);
     method public abstract void setActivated(boolean);
     method public abstract void setAlpha(float);
+    method public abstract void setAutoFillType(android.view.autofill.AutoFillType);
     method public abstract void setCheckable(boolean);
     method public abstract void setChecked(boolean);
     method public abstract void setChildCount(int);
@@ -48763,6 +48768,80 @@
 
 }
 
+package android.view.autofill {
+
+  public final class AutoFillId implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillId> CREATOR;
+  }
+
+  public final class AutoFillType implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.view.autofill.AutoFillType forList();
+    method public static android.view.autofill.AutoFillType forText(int);
+    method public static android.view.autofill.AutoFillType forToggle();
+    method public int getSubType();
+    method public boolean isList();
+    method public boolean isText();
+    method public boolean isToggle();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillType> CREATOR;
+  }
+
+  public final class AutoFillValue implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.view.autofill.AutoFillValue forList(int);
+    method public static android.view.autofill.AutoFillValue forText(java.lang.CharSequence);
+    method public static android.view.autofill.AutoFillValue forToggle(boolean);
+    method public int getListValue();
+    method public java.lang.CharSequence getTextValue();
+    method public boolean getToggleValue();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillValue> CREATOR;
+  }
+
+  public final class Dataset implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.Dataset> CREATOR;
+  }
+
+  public static final class Dataset.Builder {
+    ctor public Dataset.Builder(java.lang.CharSequence);
+    method public android.view.autofill.Dataset build();
+    method public android.view.autofill.Dataset.Builder setExtras(android.os.Bundle);
+    method public android.view.autofill.Dataset.Builder setValue(android.view.autofill.AutoFillId, android.view.autofill.AutoFillValue);
+  }
+
+  public final class FillResponse implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.FillResponse> CREATOR;
+  }
+
+  public static final class FillResponse.Builder {
+    ctor public FillResponse.Builder();
+    method public android.view.autofill.FillResponse.Builder addDataset(android.view.autofill.Dataset);
+    method public android.view.autofill.FillResponse.Builder addSavableFields(android.view.autofill.AutoFillId...);
+    method public android.view.autofill.FillResponse build();
+    method public android.view.autofill.FillResponse.Builder setExtras(android.os.Bundle);
+  }
+
+  public abstract class VirtualViewDelegate {
+    ctor public VirtualViewDelegate();
+    method public abstract void autoFill(int, android.view.autofill.AutoFillValue);
+  }
+
+  public static abstract class VirtualViewDelegate.Callback {
+    ctor public VirtualViewDelegate.Callback();
+    method public void onFocusChanged(int, boolean);
+    method public void onNodeRemoved(int...);
+    method public void onValueChanged(int);
+  }
+
+}
+
 package android.view.inputmethod {
 
   public class BaseInputConnection implements android.view.inputmethod.InputConnection {
@@ -50278,8 +50357,8 @@
     method public abstract boolean onKeyUp(int, android.view.KeyEvent);
     method public abstract void onMeasure(int, int);
     method public abstract void onOverScrolled(int, int, boolean, boolean);
+    method public default void onProvideAutoFillVirtualStructure(android.view.ViewStructure, int);
     method public abstract void onProvideVirtualStructure(android.view.ViewStructure);
-    method public default void onProvideVirtualStructure(android.view.ViewStructure, int);
     method public abstract void onScrollChanged(int, int, int, int);
     method public abstract void onSizeChanged(int, int, int, int);
     method public abstract void onStartTemporaryDetach();
@@ -52565,6 +52644,7 @@
     method public boolean getIncludeFontPadding();
     method public android.os.Bundle getInputExtras(boolean);
     method public int getInputType();
+    method public boolean getJustify();
     method public final android.text.method.KeyListener getKeyListener();
     method public final android.text.Layout getLayout();
     method public float getLetterSpacing();
@@ -52673,6 +52753,7 @@
     method public void setIncludeFontPadding(boolean);
     method public void setInputExtras(int) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public void setInputType(int);
+    method public void setJustify(boolean);
     method public void setKeyListener(android.text.method.KeyListener);
     method public void setLetterSpacing(float);
     method public void setLineSpacing(float, float);
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 7ba88bd..1ba26f5 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -124,6 +124,12 @@
 
 package android.net {
 
+  public class ConnectivityManager {
+    method public deprecated boolean requestRouteToHost(int, int);
+    method public deprecated int startUsingNetworkFeature(int, java.lang.String);
+    method public deprecated int stopUsingNetworkFeature(int, java.lang.String);
+  }
+
   public abstract class PskKeyManager {
     ctor public PskKeyManager();
     field public static final int MAX_IDENTITY_HINT_LENGTH_BYTES = 128; // 0x80
diff --git a/api/test-current.txt b/api/test-current.txt
index 7e05b78..c1ec21d 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -6390,7 +6390,8 @@
 
   public static class AssistStructure.ViewNode {
     method public float getAlpha();
-    method public int getAutoFillId();
+    method public android.view.autofill.AutoFillId getAutoFillId();
+    method public android.view.autofill.AutoFillType getAutoFillType();
     method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
     method public int getChildCount();
     method public java.lang.String getClassName();
@@ -6806,6 +6807,7 @@
     method protected android.view.View getErrorView();
     method protected void prepareView(android.view.View);
     method public void setAppWidget(int, android.appwidget.AppWidgetProviderInfo);
+    method public void setAsyncExecutor(java.util.concurrent.Executor);
     method public void updateAppWidget(android.widget.RemoteViews);
     method public void updateAppWidgetOptions(android.os.Bundle);
     method public void updateAppWidgetSize(android.os.Bundle, int, int, int, int);
@@ -24086,11 +24088,8 @@
     method public boolean requestBandwidthUpdate(android.net.Network);
     method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
     method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent);
-    method public deprecated boolean requestRouteToHost(int, int);
     method public deprecated void setNetworkPreference(int);
     method public static deprecated boolean setProcessDefaultNetwork(android.net.Network);
-    method public deprecated int startUsingNetworkFeature(int, java.lang.String);
-    method public deprecated int stopUsingNetworkFeature(int, java.lang.String);
     method public void unregisterNetworkCallback(android.net.ConnectivityManager.NetworkCallback);
     method public void unregisterNetworkCallback(android.app.PendingIntent);
     field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
@@ -28667,7 +28666,7 @@
     method public void surfaceChanged(android.view.SurfaceHolder, int, int, int);
     method public void surfaceCreated(android.view.SurfaceHolder);
     method public void surfaceDestroyed(android.view.SurfaceHolder);
-    method public void surfaceRedrawNeeded(android.view.SurfaceHolder);
+    method public deprecated void surfaceRedrawNeeded(android.view.SurfaceHolder);
     field public static final int DEBUG_CHECK_GL_ERROR = 1; // 0x1
     field public static final int DEBUG_LOG_GL_CALLS = 2; // 0x2
     field public static final int RENDERMODE_CONTINUOUSLY = 1; // 0x1
@@ -35160,26 +35159,19 @@
     method public void onDisconnected();
     method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback);
     method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.SaveCallback);
+    field public static final java.lang.String EXTRA_DATASET_EXTRAS = "android.service.autofill.extra.DATASET_EXTRAS";
+    field public static final java.lang.String EXTRA_RESPONSE_EXTRAS = "android.service.autofill.extra.RESPONSE_EXTRAS";
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
   }
 
   public final class FillCallback {
     method public void onFailure(java.lang.CharSequence);
-    method public void onSuccess(android.service.autofill.FillCallback.FillData);
-  }
-
-  public static final class FillCallback.FillData {
-  }
-
-  public static class FillCallback.FillData.Builder {
-    ctor public FillCallback.FillData.Builder();
-    method public android.service.autofill.FillCallback.FillData build();
-    method public android.service.autofill.FillCallback.FillData.Builder setTextField(int, java.lang.String);
+    method public void onSuccess(android.view.autofill.FillResponse);
   }
 
   public final class SaveCallback {
     method public void onFailure(java.lang.CharSequence);
-    method public void onSuccess(int[]);
+    method public void onSuccess(android.view.autofill.AutoFillId[]);
   }
 
 }
@@ -36844,6 +36836,7 @@
     method public void unhold();
     method public void unregisterCallback(android.telecom.Call.Callback);
     field public static final java.lang.String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts";
+    field public static final java.lang.String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS = "android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS";
     field public static final int STATE_ACTIVE = 4; // 0x4
     field public static final int STATE_CONNECTING = 9; // 0x9
     field public static final int STATE_DIALING = 1; // 0x1
@@ -39579,6 +39572,7 @@
     method public android.text.StaticLayout.Builder setHyphenationFrequency(int);
     method public android.text.StaticLayout.Builder setIncludePad(boolean);
     method public android.text.StaticLayout.Builder setIndents(int[], int[]);
+    method public android.text.StaticLayout.Builder setJustify(boolean);
     method public android.text.StaticLayout.Builder setLineSpacing(float, float);
     method public android.text.StaticLayout.Builder setMaxLines(int);
     method public android.text.StaticLayout.Builder setText(java.lang.CharSequence);
@@ -43356,6 +43350,7 @@
 
   public static abstract interface SurfaceHolder.Callback2 implements android.view.SurfaceHolder.Callback {
     method public abstract void surfaceRedrawNeeded(android.view.SurfaceHolder);
+    method public default void surfaceRedrawNeededAsync(android.view.SurfaceHolder, java.lang.Runnable);
   }
 
   public class SurfaceView extends android.view.View {
@@ -43436,6 +43431,7 @@
     method public void addTouchables(java.util.ArrayList<android.view.View>);
     method public android.view.ViewPropertyAnimator animate();
     method public void announceForAccessibility(java.lang.CharSequence);
+    method public void autoFill(android.view.autofill.AutoFillValue);
     method protected boolean awakenScrollBars();
     method protected boolean awakenScrollBars(int);
     method protected boolean awakenScrollBars(int, boolean);
@@ -43487,8 +43483,8 @@
     method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
     method public boolean dispatchNestedScroll(int, int, int, int, int[]);
     method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public deprecated void dispatchProvideStructure(android.view.ViewStructure);
-    method public void dispatchProvideStructure(android.view.ViewStructure, int);
+    method public void dispatchProvideAutoFillStructure(android.view.ViewStructure, int);
+    method public void dispatchProvideStructure(android.view.ViewStructure);
     method protected void dispatchRestoreInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSaveInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSetActivated(boolean);
@@ -43523,6 +43519,8 @@
     method public float getAlpha();
     method public android.view.animation.Animation getAnimation();
     method public android.os.IBinder getApplicationWindowToken();
+    method public android.view.autofill.AutoFillType getAutoFillType();
+    method public android.view.autofill.VirtualViewDelegate getAutoFillVirtualViewDelegate(android.view.autofill.VirtualViewDelegate.Callback);
     method public android.graphics.drawable.Drawable getBackground();
     method public android.content.res.ColorStateList getBackgroundTintList();
     method public android.graphics.PorterDuff.Mode getBackgroundTintMode();
@@ -43760,10 +43758,10 @@
     method protected void onMeasure(int, int);
     method protected void onOverScrolled(int, int, boolean, boolean);
     method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public deprecated void onProvideStructure(android.view.ViewStructure);
-    method public void onProvideStructure(android.view.ViewStructure, int);
-    method public deprecated void onProvideVirtualStructure(android.view.ViewStructure);
-    method public void onProvideVirtualStructure(android.view.ViewStructure, int);
+    method public void onProvideAutoFillStructure(android.view.ViewStructure, int);
+    method public void onProvideAutoFillVirtualStructure(android.view.ViewStructure, int);
+    method public void onProvideStructure(android.view.ViewStructure);
+    method public void onProvideVirtualStructure(android.view.ViewStructure);
     method public android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int);
     method protected void onRestoreInstanceState(android.os.Parcelable);
     method public void onRtlPropertiesChanged(int);
@@ -43970,8 +43968,8 @@
     field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
     field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
     field public static final android.util.Property<android.view.View, java.lang.Float> ALPHA;
-    field public static final int ASSIST_FLAG_NON_SANITIZED_TEXT = 2; // 0x2
-    field public static final int ASSIST_FLAG_SANITIZED_TEXT = 1; // 0x1
+    field public static final int AUTO_FILL_FLAG_TYPE_FILL = 1; // 0x1
+    field public static final int AUTO_FILL_FLAG_TYPE_SAVE = 2; // 0x2
     field public static final int DRAG_FLAG_GLOBAL = 256; // 0x100
     field public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 64; // 0x40
     field public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 128; // 0x80
@@ -44605,6 +44603,7 @@
     method public abstract int addChildCount(int);
     method public abstract void asyncCommit();
     method public abstract android.view.ViewStructure asyncNewChild(int);
+    method public abstract android.view.ViewStructure asyncNewChild(int, int);
     method public abstract int getChildCount();
     method public abstract android.os.Bundle getExtras();
     method public abstract java.lang.CharSequence getHint();
@@ -44613,9 +44612,11 @@
     method public abstract int getTextSelectionStart();
     method public abstract boolean hasExtras();
     method public abstract android.view.ViewStructure newChild(int);
+    method public abstract android.view.ViewStructure newChild(int, int);
     method public abstract void setAccessibilityFocused(boolean);
     method public abstract void setActivated(boolean);
     method public abstract void setAlpha(float);
+    method public abstract void setAutoFillType(android.view.autofill.AutoFillType);
     method public abstract void setCheckable(boolean);
     method public abstract void setChecked(boolean);
     method public abstract void setChildCount(int);
@@ -45838,6 +45839,80 @@
 
 }
 
+package android.view.autofill {
+
+  public final class AutoFillId implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillId> CREATOR;
+  }
+
+  public final class AutoFillType implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.view.autofill.AutoFillType forList();
+    method public static android.view.autofill.AutoFillType forText(int);
+    method public static android.view.autofill.AutoFillType forToggle();
+    method public int getSubType();
+    method public boolean isList();
+    method public boolean isText();
+    method public boolean isToggle();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillType> CREATOR;
+  }
+
+  public final class AutoFillValue implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.view.autofill.AutoFillValue forList(int);
+    method public static android.view.autofill.AutoFillValue forText(java.lang.CharSequence);
+    method public static android.view.autofill.AutoFillValue forToggle(boolean);
+    method public int getListValue();
+    method public java.lang.CharSequence getTextValue();
+    method public boolean getToggleValue();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillValue> CREATOR;
+  }
+
+  public final class Dataset implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.Dataset> CREATOR;
+  }
+
+  public static final class Dataset.Builder {
+    ctor public Dataset.Builder(java.lang.CharSequence);
+    method public android.view.autofill.Dataset build();
+    method public android.view.autofill.Dataset.Builder setExtras(android.os.Bundle);
+    method public android.view.autofill.Dataset.Builder setValue(android.view.autofill.AutoFillId, android.view.autofill.AutoFillValue);
+  }
+
+  public final class FillResponse implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.FillResponse> CREATOR;
+  }
+
+  public static final class FillResponse.Builder {
+    ctor public FillResponse.Builder();
+    method public android.view.autofill.FillResponse.Builder addDataset(android.view.autofill.Dataset);
+    method public android.view.autofill.FillResponse.Builder addSavableFields(android.view.autofill.AutoFillId...);
+    method public android.view.autofill.FillResponse build();
+    method public android.view.autofill.FillResponse.Builder setExtras(android.os.Bundle);
+  }
+
+  public abstract class VirtualViewDelegate {
+    ctor public VirtualViewDelegate();
+    method public abstract void autoFill(int, android.view.autofill.AutoFillValue);
+  }
+
+  public static abstract class VirtualViewDelegate.Callback {
+    ctor public VirtualViewDelegate.Callback();
+    method public void onFocusChanged(int, boolean);
+    method public void onNodeRemoved(int...);
+    method public void onValueChanged(int);
+  }
+
+}
+
 package android.view.inputmethod {
 
   public class BaseInputConnection implements android.view.inputmethod.InputConnection {
@@ -49289,6 +49364,7 @@
     method public boolean getIncludeFontPadding();
     method public android.os.Bundle getInputExtras(boolean);
     method public int getInputType();
+    method public boolean getJustify();
     method public final android.text.method.KeyListener getKeyListener();
     method public final android.text.Layout getLayout();
     method public float getLetterSpacing();
@@ -49397,6 +49473,7 @@
     method public void setIncludeFontPadding(boolean);
     method public void setInputExtras(int) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public void setInputType(int);
+    method public void setJustify(boolean);
     method public void setKeyListener(android.text.method.KeyListener);
     method public void setLetterSpacing(float);
     method public void setLineSpacing(float, float);
diff --git a/api/test-removed.txt b/api/test-removed.txt
index d7a8bce..ab22b6e 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -126,6 +126,12 @@
 
 package android.net {
 
+  public class ConnectivityManager {
+    method public deprecated boolean requestRouteToHost(int, int);
+    method public deprecated int startUsingNetworkFeature(int, java.lang.String);
+    method public deprecated int stopUsingNetworkFeature(int, java.lang.String);
+  }
+
   public abstract class PskKeyManager {
     ctor public PskKeyManager();
     field public static final int MAX_IDENTITY_HINT_LENGTH_BYTES = 128; // 0x80
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 0d9e8a0..87e5416 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -70,9 +70,8 @@
 import android.os.StrictMode;
 import android.os.SystemProperties;
 import android.os.UserHandle;
-import android.service.autofill.FillableInputField;
 import android.service.autofill.AutoFillService;
-import android.service.autofill.IAutoFillCallback;
+import android.service.autofill.IAutoFillAppCallback;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
 import android.text.TextAssistant;
@@ -115,6 +114,11 @@
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.autofill.VirtualViewDelegate;
+import android.view.autofill.Dataset;
+import android.view.autofill.DatasetField;
+import android.view.autofill.AutoFillId;
+import android.view.autofill.FillResponse;
 import android.widget.AdapterView;
 import android.widget.EditText;
 import android.widget.Toast;
@@ -130,6 +134,7 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -697,6 +702,9 @@
     private static final String TAG = "Activity";
     private static final boolean DEBUG_LIFECYCLE = false;
 
+    // TODO(b/33197203): set to false once stable
+    private static final boolean DEBUG_AUTO_FILL = true;
+
     /** Standard activity result: operation canceled. */
     public static final int RESULT_CANCELED    = 0;
     /** Standard activity result: operation succeeded. */
@@ -847,7 +855,10 @@
     private boolean mEatKeyUpEvent;
 
     @GuardedBy("this")
-    private IAutoFillCallback mAutoFillCallback;
+    private WeakReference<IAutoFillAppCallback> mAutoFillCallback;
+
+    @GuardedBy("this")
+    private VirtualViewDelegate.Callback mAutoFillDelegateCallback;
 
     private static native String getDlWarning();
 
@@ -1718,47 +1729,73 @@
     }
 
     /**
-     * Lazily gets the {@code IAutoFillCallback} for this activitity.
+     * Lazily sets the {@link #mAutoFillDelegateCallback}.
+     */
+    private void setAutoFillDelegateCallback() {
+        synchronized (this) {
+            if (mAutoFillDelegateCallback == null) {
+                mAutoFillDelegateCallback = new VirtualViewDelegate.Callback() {
+                    // TODO(b/33197203): implement
+                };
+            }
+        }
+    }
+
+    /**
+     * Lazily gets the {@link IAutoFillAppCallback} for this activitity.
      *
      * <p>This callback is used by the {@link AutoFillService} app to auto-fill the activity fields.
      */
-    IAutoFillCallback getAutoFillCallback() {
+    WeakReference<IAutoFillAppCallback> getAutoFillCallback() {
         synchronized (this) {
             if (mAutoFillCallback == null) {
-                mAutoFillCallback = new IAutoFillCallback.Stub() {
+                final IAutoFillAppCallback cb = new IAutoFillAppCallback.Stub() {
                     @Override
-                    public void autofill(@SuppressWarnings("rawtypes") List fields)
-                            throws RemoteException {
+                    public void autoFill(Dataset dataset) throws RemoteException {
+                        // TODO(b/33197203): must keep the dataset so subsequent calls pass the same
+                        // dataset.extras to service
                         runOnUiThread(() -> {
                             final View root = getWindow().getDecorView().getRootView();
-                            for (Object field : fields) {
-                                if (!(field instanceof FillableInputField)) {
-                                    Slog.w(TAG,  "autofill(): invalid type " + field.getClass());
+                            for (DatasetField field : dataset.getFields()) {
+                                final AutoFillId id = field.getId();
+                                if (id == null) {
+                                    Log.w(TAG, "autoFill(): null id on " + field);
                                     continue;
                                 }
-                                FillableInputField autoFillField = (FillableInputField) field;
-                                final int viewId = autoFillField.getId();
+                                final int viewId = id.getViewId();
                                 final View view = root.findViewByAccessibilityIdTraversal(viewId);
-                                // TODO(b/33197203): should handle other types of view as well, but
-                                // that will require:
-                                // - a new interface like AutoFillable
-                                // - a way for the views to define the type of the autofield value
-                                if ((view instanceof EditText)) {
-                                    ((EditText) view).setText(autoFillField.getValue());
+                                if (view == null) {
+                                    Log.w(TAG, "autoFill(): no View with id " + viewId);
+                                    continue;
+                                }
+
+                                // TODO(b/33197203): handle protected value (like credit card)
+                                if (id.isVirtual()) {
+                                    // Delegate virtual fields to provider.
+                                    setAutoFillDelegateCallback();
+                                    final VirtualViewDelegate mgr = view
+                                            .getAutoFillVirtualViewDelegate(
+                                                    mAutoFillDelegateCallback);
+                                    if (mgr == null) {
+                                        Log.w(TAG, "autoFill(): cannot fill virtual " + id
+                                                + "; no auto-fill provider for view "
+                                                + view.getClass());
+                                        continue;
+                                    }
+                                    if (DEBUG_AUTO_FILL) {
+                                        Log.d(TAG, "autoFill(): delegating " + id
+                                                + " to virtual manager  " + mgr);
+                                    }
+                                    mgr.autoFill(id.getVirtualChildId(), field.getValue());
+                                } else {
+                                    // Handle non-virtual fields itself.
+                                    view.autoFill(field.getValue());
                                 }
                             }
                         });
                     }
-
-                    @Override
-                    public void showError(String message) {
-                        runOnUiThread(() -> {
-                            // TODO(b/33197203): temporary show a toast until it uses the Snack bar.
-                            Toast.makeText(Activity.this, "Auto-fill request failed: " + message,
-                                    Toast.LENGTH_LONG).show();
-                        });
-                    }
                 };
+                mAutoFillCallback = new WeakReference<IAutoFillAppCallback>(cb);
             }
         }
         return mAutoFillCallback;
@@ -6096,7 +6133,7 @@
 
         if (mAutoFillCallback != null) {
             writer.print(prefix); writer.print("mAutoFillCallback: " );
-                    writer.println(mAutoFillCallback);
+                    writer.println(mAutoFillCallback.get());
         }
 
         mHandler.getLooper().dump(new PrintWriterPrinter(writer), prefix);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 6ee0210..48aca8e 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -491,6 +491,12 @@
     /** @hide requestType for assist context: generate full AssistStructure. */
     public static final int ASSIST_CONTEXT_FULL = 1;
 
+    /** @hide requestType for assist context: generate full AssistStructure for auto-fill. */
+    public static final int ASSIST_CONTEXT_AUTO_FILL = 2;
+
+    /** @hide requestType for assist context: generate full AssistStructure for auto-fill save. */
+    public static final int ASSIST_CONTEXT_AUTO_FILL_SAVE = 3;
+
     /** @hide Flag for registerUidObserver: report changes in process state. */
     public static final int UID_OBSERVER_PROCSTATE = 1<<0;
 
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e34fabc..45d325a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -89,7 +89,7 @@
 import android.security.NetworkSecurityPolicy;
 import android.security.net.config.NetworkSecurityConfigProvider;
 import android.service.autofill.AutoFillService;
-import android.service.autofill.IAutoFillCallback;
+import android.service.autofill.IAutoFillAppCallback;
 import android.service.voice.VoiceInteractionSession;
 import android.util.AndroidRuntimeException;
 import android.util.ArrayMap;
@@ -1758,6 +1758,7 @@
                 case LOCAL_VOICE_INTERACTION_STARTED:
                     handleLocalVoiceInteractionStarted((IBinder) ((SomeArgs) msg.obj).arg1,
                             (IVoiceInteractor) ((SomeArgs) msg.obj).arg2);
+                    break;
                 case ATTACH_AGENT:
                     handleAttachAgent((String) msg.obj);
                     break;
@@ -2884,9 +2885,8 @@
         // - it does not call onProvideAssistData()
         // - it needs an IAutoFillCallback
         // - it sets the flags so views can provide autofill-specific data (such as passwords)
-        boolean forAutoFill = (cmd.flags
-                & (View.ASSIST_FLAG_SANITIZED_TEXT
-                        | View.ASSIST_FLAG_NON_SANITIZED_TEXT)) != 0;
+        boolean forAutoFill = cmd.requestType == ActivityManager.ASSIST_CONTEXT_AUTO_FILL
+                || cmd.requestType == ActivityManager.ASSIST_CONTEXT_AUTO_FILL_SAVE;
 
         // TODO(b/33197203): decide if lastSessionId logic applies to auto-fill sessions
         if (mLastSessionId != cmd.sessionId) {
@@ -2910,22 +2910,23 @@
             if (!forAutoFill) {
                 r.activity.getApplication().dispatchOnProvideAssistData(r.activity, data);
                 r.activity.onProvideAssistData(data);
+                referrer = r.activity.onProvideReferrer();
             }
-            referrer = r.activity.onProvideReferrer();
             if (cmd.requestType == ActivityManager.ASSIST_CONTEXT_FULL || forAutoFill) {
                 structure = new AssistStructure(r.activity, cmd.flags);
                 Intent activityIntent = r.activity.getIntent();
-                if (cmd.flags > 0) {
+                if (forAutoFill) {
                     data.putInt(VoiceInteractionSession.KEY_FLAGS, cmd.flags);
                 }
+                boolean addAutoFillCallback = false;
                 // TODO(b/33197203): re-evaluate conditions below for auto-fill. In particular,
                 // FLAG_SECURE might be allowed on AUTO_FILL but not on AUTO_FILL_SAVE)
-                if (activityIntent != null && (r.window == null ||
+                boolean notSecure = r.window == null ||
                         (r.window.getAttributes().flags
-                                & WindowManager.LayoutParams.FLAG_SECURE) == 0)) {
+                                & WindowManager.LayoutParams.FLAG_SECURE) == 0;
+                if (activityIntent != null && notSecure) {
                     if (forAutoFill) {
-                        IAutoFillCallback autoFillCallback = r.activity.getAutoFillCallback();
-                        data.putBinder(AutoFillService.KEY_CALLBACK, autoFillCallback.asBinder());
+                        addAutoFillCallback = true;
                     } else {
                         Intent intent = new Intent(activityIntent);
                         intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
@@ -2936,10 +2937,21 @@
                 } else {
                     if (!forAutoFill) {
                         content.setDefaultIntent(new Intent());
+                    } else {
+                        // activityIntent is unlikely to be null, but if it is, we should still
+                        // set the auto-fill callback.
+                        addAutoFillCallback = notSecure;
                     }
                 }
                 if (!forAutoFill) {
                     r.activity.onProvideAssistContent(content);
+                } else if (addAutoFillCallback) {
+                    IAutoFillAppCallback cb = r.activity.getAutoFillCallback().get();
+                    if (cb != null) {
+                        data.putBinder(AutoFillService.KEY_CALLBACK, cb.asBinder());
+                    } else {
+                        Slog.w(TAG, "handleRequestAssistContextExtras(): callback was GCed");
+                    }
                 }
             }
         }
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 21854d3..2ed9eab 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -586,10 +586,16 @@
     void unregisterTaskStackListener(ITaskStackListener listener);
     void moveStackToDisplay(int stackId, int displayId);
     boolean requestAutoFillData(in IResultReceiver receiver, in Bundle receiverExtras,
-            in IBinder activityToken, int flags);
+            int resultCode, in IBinder activityToken, int flags);
     void dismissKeyguard(in IBinder token, in IKeyguardDismissCallback callback);
     int restartUserInBackground(int userId);
 
+    /** Cancels the window transitions for the given task. */
+    void cancelTaskWindowTransition(int taskId);
+
+    /** Cancels the thumbnail transitions for the given task. */
+    void cancelTaskThumbnailTransition(int taskId);
+
     // WARNING: when these transactions are updated, check if they are any callers on the native
     // side. If so, make sure they are using the correct transaction ids and arguments.
     // If a transaction which will also be used on the native side is being inserted, add it
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index e454ae1..ef997c9 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -95,4 +95,11 @@
      * perform relevant animations before the window disappears.
      */
     void onTaskRemovalStarted(int taskId);
+
+    /**
+     * Called when the task has been put in a locked state because one or more of the
+     * activities inside it belong to a managed profile user, and that user has just
+     * been locked.
+     */
+    void onTaskProfileLocked(int taskId, int userId);
 }
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index 0639552..ad5e69b 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -74,4 +74,8 @@
     public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation)
             throws RemoteException {
     }
+
+    @Override
+    public void onTaskProfileLocked(int taskId, int userId) {
+    }
 }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index a56ff5e..29633aa 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -279,6 +279,8 @@
      * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_LOCAL_TIME} (convert to String), optional</li>
      * <li>{@link #EXTRA_PROVISIONING_TIME_ZONE}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_LOCALE}, optional</li>
@@ -290,6 +292,8 @@
      * <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_PORT} (convert to String), optional</li>
      * <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_BYPASS}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_WIFI_PAC_URL}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_SUPPORT_URL}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_ORGANIZATION_NAME}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}, optional</li></ul>
      *
      * @hide
@@ -688,6 +692,67 @@
         = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
 
     /**
+     * A String extra holding the localized name of the organization under management.
+     *
+     * The name is displayed only during provisioning.
+     *
+     * <p>Use in an intent with action {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_PROVISIONING_ORGANIZATION_NAME =
+            "android.app.extra.PROVISIONING_ORGANIZATION_NAME";
+
+    /**
+     * A String extra holding a url to the website of the device's provider. The website can be
+     * opened in a browser during provisioning.
+     *
+     * <p>Use in an intent with action {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_PROVISIONING_SUPPORT_URL =
+            "android.app.extra.PROVISIONING_SUPPORT_URL";
+
+    /**
+     * A String extra holding the localized name of the device admin package. It should be the same
+     * as the app label of the package.
+     *
+     * <p>Use in an intent with action {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL =
+            "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL";
+
+    /**
+     * A {@link Uri} extra pointing to the app icon of device admin package. This image will be
+     * shown during the provisioning.
+     * <h5>The following URI schemes are accepted:</h5>
+     * <ul>
+     * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+     * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})</li>
+     * </ul>
+     *
+     * <p> It is the responsibility of the caller to provide an image with a reasonable
+     * pixel density for the device.
+     *
+     * <p> If a content: URI is passed, the intent should have the flag
+     * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} and the uri should be added to the
+     * {@link android.content.ClipData} of the intent too.
+     *
+     * <p>Use in an intent with action {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI =
+            "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI";
+
+    /**
      * An int extra holding a minimum required version code for the device admin package. If the
      * device admin is already installed on the device, it will only be re-downloaded from
      * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION} if the version of the
@@ -808,7 +873,7 @@
      * </ul>
      *
      * <p> It is the responsibility of the caller to provide an image with a reasonable
-     * pixed density for the device.
+     * pixel density for the device.
      *
      * <p> If a content: URI is passed, the intent should have the flag
      * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} and the uri should be added to the
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 1988e42..b94264e 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -21,6 +21,8 @@
 import android.view.ViewRootImpl;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
+import android.view.autofill.AutoFillType;
+import android.view.autofill.AutoFillId;
 
 import java.util.ArrayList;
 
@@ -411,25 +413,30 @@
             mTitle = root.getTitle();
             mDisplayId = root.getDisplayId();
             mRoot = new ViewNode();
+
+            // Must explicitly call the proper method based on flags since we don't know which
+            // method (if any) was overridden by the View subclass.
+            boolean forAutoFill = (flags
+                    & (View.AUTO_FILL_FLAG_TYPE_FILL
+                            | View.AUTO_FILL_FLAG_TYPE_SAVE)) != 0;
+
             ViewNodeBuilder builder = new ViewNodeBuilder(assist, mRoot, false);
             if ((root.getWindowFlags()& WindowManager.LayoutParams.FLAG_SECURE) != 0) {
                 // This is a secure window, so it doesn't want a screenshot, and that
                 // means we should also not copy out its view hierarchy.
 
-                // Must explicitly set which method to calls since View subclasses might
-                // have implemented the deprecated method.
-                if (flags == 0) {
-                    view.onProvideStructure(builder);
+                if (forAutoFill) {
+                    view.onProvideAutoFillStructure(builder, flags);
                 } else {
-                    view.onProvideStructure(builder, flags);
+                    view.onProvideStructure(builder);
                 }
                 builder.setAssistBlocked(true);
                 return;
             }
-            if (flags == 0) {
-                view.dispatchProvideStructure(builder);
+            if (forAutoFill) {
+                view.dispatchProvideAutoFillStructure(builder, flags);
             } else {
-                view.dispatchProvideStructure(builder, flags);
+                view.dispatchProvideStructure(builder);
             }
         }
 
@@ -526,7 +533,10 @@
         String mIdPackage;
         String mIdType;
         String mIdEntry;
-        int mAutoFillId = View.NO_ID;
+        // TODO(b/33197203): once we have more flags, it might be better to store the individual
+        // fields (viewId and childId) of the field.
+        AutoFillId mAutoFillId;
+        AutoFillType mAutoFillType;
         int mX;
         int mY;
         int mScrollX;
@@ -551,7 +561,11 @@
         static final int FLAGS_ACTIVATED = 0x00002000;
         static final int FLAGS_CONTEXT_CLICKABLE = 0x00004000;
 
-        static final int FLAGS_HAS_AUTO_FILL_ID = 0x80000000;
+        // TODO(b/33197203): auto-fill data is made of many fields and ideally we should verify
+        // one-by-one to optimize what's sent over, but there isn't enough flag bits for that, we'd
+        // need to create a 'flags2' or 'autoFillFlags' field and add these flags there.
+        // So, to keep thinkg simpler for now, let's just use on flag for all of them...
+        static final int FLAGS_HAS_AUTO_FILL_DATA = 0x80000000;
         static final int FLAGS_HAS_MATRIX = 0x40000000;
         static final int FLAGS_HAS_ALPHA = 0x20000000;
         static final int FLAGS_HAS_ELEVATION = 0x10000000;
@@ -595,8 +609,9 @@
                     }
                 }
             }
-            if ((flags&FLAGS_HAS_AUTO_FILL_ID) != 0) {
-                mAutoFillId = in.readInt();
+            if ((flags&FLAGS_HAS_AUTO_FILL_DATA) != 0) {
+                mAutoFillId = in.readParcelable(null);
+                mAutoFillType = in.readParcelable(null);
             }
             if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
                 mX = in.readInt();
@@ -653,8 +668,8 @@
             if (mId != View.NO_ID) {
                 flags |= FLAGS_HAS_ID;
             }
-            if (mAutoFillId != View.NO_ID) {
-                flags |= FLAGS_HAS_AUTO_FILL_ID;
+            if (mAutoFillId != null) {
+                flags |= FLAGS_HAS_AUTO_FILL_DATA;
             }
             if ((mX&~0x7fff) != 0 || (mY&~0x7fff) != 0
                     || (mWidth&~0x7fff) != 0 | (mHeight&~0x7fff) != 0) {
@@ -700,8 +715,9 @@
                     }
                 }
             }
-            if ((flags&FLAGS_HAS_AUTO_FILL_ID) != 0) {
-                out.writeInt(mAutoFillId);
+            if ((flags&FLAGS_HAS_AUTO_FILL_DATA) != 0) {
+                out.writeParcelable(mAutoFillId, 0);
+                out.writeParcelable(mAutoFillType,  0);
             }
             if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
                 out.writeInt(mX);
@@ -773,16 +789,26 @@
         }
 
         /**
-         * Returns the id that can be used to auto-fill the view.
+         * Gets the id that can be used to auto-fill the view contents.
          *
          * <p>It's only set when the {@link AssistStructure} is used for auto-filling purposes, not
          * for assist.
          */
-        public int getAutoFillId() {
+        public AutoFillId getAutoFillId() {
             return mAutoFillId;
         }
 
         /**
+         * Gets the the type of value that can be used to auto-fill the view contents.
+         *
+         * <p>It's only set when the {@link AssistStructure} is used for auto-filling purposes, not
+         * for assist.
+         */
+        public AutoFillType getAutoFillType() {
+            return mAutoFillType;
+        }
+
+        /**
          * Returns the left edge of this view, in pixels, relative to the left edge of its parent.
          */
         public int getLeft() {
@@ -1318,17 +1344,23 @@
             return mNode.mChildren != null ? mNode.mChildren.length : 0;
         }
 
-        @Override
-        public ViewStructure newChild(int index) {
+        private void setAutoFillId(ViewNode child, boolean forAutoFill, int virtualId) {
+            if (forAutoFill) {
+                child.mAutoFillId = new AutoFillId(mNode.mAutoFillId, virtualId);
+            }
+        }
+
+        private ViewStructure newChild(int index, boolean forAutoFill, int virtualId) {
             ViewNode node = new ViewNode();
+            setAutoFillId(node, forAutoFill, virtualId);
             mNode.mChildren[index] = node;
             return new ViewNodeBuilder(mAssist, node, false);
         }
 
-        @Override
-        public ViewStructure asyncNewChild(int index) {
+        private ViewStructure asyncNewChild(int index, boolean forAutoFill, int virtualId) {
             synchronized (mAssist) {
                 ViewNode node = new ViewNode();
+                setAutoFillId(node, forAutoFill, virtualId);
                 mNode.mChildren[index] = node;
                 ViewNodeBuilder builder = new ViewNodeBuilder(mAssist, node, true);
                 mAssist.mPendingAsyncChildren.add(builder);
@@ -1337,6 +1369,26 @@
         }
 
         @Override
+        public ViewStructure newChild(int index) {
+            return newChild(index, false, 0);
+        }
+
+        @Override
+        public ViewStructure newChild(int index, int virtualId) {
+            return newChild(index, true, virtualId);
+        }
+
+        @Override
+        public ViewStructure asyncNewChild(int index) {
+            return asyncNewChild(index, false, 0);
+        }
+
+        @Override
+        public ViewStructure asyncNewChild(int index, int virtualId) {
+            return asyncNewChild(index, true, virtualId);
+        }
+
+        @Override
         public void asyncCommit() {
             synchronized (mAssist) {
                 if (!mAsync) {
@@ -1356,9 +1408,20 @@
         }
 
         @Override
-        public void setAutoFillId(int autoFillId) {
-            mNode.mAutoFillId = autoFillId;
+        public void setAutoFillId(int viewId) {
+            mNode.mAutoFillId = new AutoFillId(viewId);
         }
+
+        @Override
+        public AutoFillId getAutoFillId() {
+            return mNode.mAutoFillId;
+        }
+
+        @Override
+        public void setAutoFillType(AutoFillType type) {
+           mNode.mAutoFillType = type;
+        }
+
     }
 
     /** @hide */
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 4c8360f..ef3b1c5 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -347,11 +347,11 @@
     }
 
     /**
-     * Sets an executor which can be used for asynchronously inflating and applying the remoteviews.
-     * @see {@link RemoteViews#applyAsync(Context, ViewGroup, RemoteViews.OnViewAppliedListener, Executor)}
+     * Sets an executor which can be used for asynchronously inflating. CPU intensive tasks like
+     * view inflation or loading images will be performed on the executor. The updates will still
+     * be applied on the UI thread.
      *
      * @param executor the executor to use or null.
-     * @hide
      */
     public void setAsyncExecutor(Executor executor) {
         if (mLastExecutionSignal != null) {
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 3189681..31e779f 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -1094,8 +1094,9 @@
      * <p>Only apps with a foreground activity or a foreground service can call it.  Otherwise
      * it'll throw {@link IllegalStateException}.
      *
-     * <p>When an app calls this API when a previous request is still waiting for a response,
-     * the previous request will be canceled.
+     * <p>It's up to the launcher how to handle previous pending requests when the same package
+     * calls this API multiple times in a row.  It may ignore the previous requests,
+     * for example.
      *
      * @param provider The {@link ComponentName} for the {@link
      *    android.content.BroadcastReceiver BroadcastReceiver} provider for your AppWidget.
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index b686938..98a5341 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -243,7 +243,7 @@
         }
 
         as.mPfd = new ParcelFileDescriptor(fds[0]);
-        as.mSocket = new LocalSocket(fds[0]);
+        as.mSocket = LocalSocket.createConnectedLocalSocket(fds[0]);
         as.mSocketIS = as.mSocket.getInputStream();
         as.mSocketOS = as.mSocket.getOutputStream();
         as.mAddress = RemoteAddr;
@@ -367,7 +367,7 @@
                 if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
                 if (mPfd == null) throw new IOException("bt socket connect failed");
                 FileDescriptor fd = mPfd.getFileDescriptor();
-                mSocket = new LocalSocket(fd);
+                mSocket = LocalSocket.createConnectedLocalSocket(fd);
                 mSocketIS = mSocket.getInputStream();
                 mSocketOS = mSocket.getOutputStream();
             }
@@ -416,9 +416,9 @@
                 if(mSocketState != SocketState.INIT) return EBADFD;
                 if(mPfd == null) return -1;
                 FileDescriptor fd = mPfd.getFileDescriptor();
-                if (DBG) Log.d(TAG, "bindListen(), new LocalSocket ");
-                mSocket = new LocalSocket(fd);
-                if (DBG) Log.d(TAG, "bindListen(), new LocalSocket.getInputStream() ");
+                if (DBG) Log.d(TAG, "bindListen(), Create LocalSocket");
+                mSocket = LocalSocket.createConnectedLocalSocket(fd);
+                if (DBG) Log.d(TAG, "bindListen(), new LocalSocket.getInputStream()");
                 mSocketIS = mSocket.getInputStream();
                 mSocketOS = mSocket.getOutputStream();
             }
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 4b5b995..afd7578 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -1200,7 +1200,7 @@
 
         /**
          * Return {@code TRUE} if a request is valid -- i.e. {@link #accept(Bundle)} has not been
-         * called, and it has not been canceled.
+         * called yet.
          */
         public boolean isValid() {
             try {
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index c8fb3d1..3853400 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -846,8 +846,9 @@
      * <p>Only apps with a foreground activity or a foreground service can call it.  Otherwise
      * it'll throw {@link IllegalStateException}.
      *
-     * <p>When an app calls this API when a previous request is still waiting for a response,
-     * the previous request will be canceled.
+     * <p>It's up to the launcher how to handle previous pending requests when the same package
+     * calls this API multiple times in a row.  It may ignore the previous requests,
+     * for example.
      *
      * @param shortcut New shortcut to pin.  If an app wants to pin an existing (either dynamic
      *     or manifest) shortcut, then it only needs to have an ID, and other fields don't have to
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 13ba6cc..aea1258 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -167,6 +167,8 @@
         public static final int POLICY_DIM = 2;
         // Policy: Make the screen bright as usual.
         public static final int POLICY_BRIGHT = 3;
+        // Policy: Keep the screen and display optimized for VR mode.
+        public static final int POLICY_VR = 4;
 
         // The basic overall policy to apply: off, doze, dim or bright.
         public int policy;
@@ -233,6 +235,10 @@
             return policy == POLICY_BRIGHT || policy == POLICY_DIM;
         }
 
+        public boolean isVr() {
+            return policy == POLICY_VR;
+        }
+
         public void copyFrom(DisplayPowerRequest other) {
             policy = other.policy;
             useProximitySensor = other.useProximitySensor;
@@ -301,6 +307,8 @@
                     return "DIM";
                 case POLICY_BRIGHT:
                     return "BRIGHT";
+                case POLICY_VR:
+                    return "VR";
                 default:
                     return Integer.toString(policy);
             }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index d1d5f40..ac0c0dc 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1163,6 +1163,7 @@
      *             {@link #requestNetwork(NetworkRequest, NetworkCallback)} API.
      *             In {@link VERSION_CODES#M}, and above, this method is unsupported and will
      *             throw {@code UnsupportedOperationException} if called.
+     * @removed
      */
     @Deprecated
     public int startUsingNetworkFeature(int networkType, String feature) {
@@ -1219,6 +1220,7 @@
      *             {@link #unregisterNetworkCallback(NetworkCallback)} API.
      *             In {@link VERSION_CODES#M}, and above, this method is unsupported and will
      *             throw {@code UnsupportedOperationException} if called.
+     * @removed
      */
     @Deprecated
     public int stopUsingNetworkFeature(int networkType, String feature) {
@@ -1633,6 +1635,7 @@
      *             {@link #bindProcessToNetwork} and {@link Network#getSocketFactory} API.
      *             In {@link VERSION_CODES#M}, and above, this method is unsupported and will
      *             throw {@code UnsupportedOperationException} if called.
+     * @removed
      */
     @Deprecated
     public boolean requestRouteToHost(int networkType, int hostAddress) {
diff --git a/core/java/android/net/INetworkScoreService.aidl b/core/java/android/net/INetworkScoreService.aidl
index 932f031..9573953 100644
--- a/core/java/android/net/INetworkScoreService.aidl
+++ b/core/java/android/net/INetworkScoreService.aidl
@@ -100,4 +100,21 @@
      * @hide
      */
     boolean requestScores(in NetworkKey[] networks);
+
+    /**
+     * Determine whether the application with the given UID is the enabled scorer.
+     *
+     * @param callingUid the UID to check
+     * @return true if the provided UID is the active scorer, false otherwise.
+     * @hide
+     */
+    boolean isCallerActiveScorer(int callingUid);
+
+    /**
+     * Obtain the package name of the current active network scorer.
+     *
+     * @return the full package name of the current active scorer, or null if there is no active
+     *         scorer.
+     */
+    String getActiveScorerPackage();
 }
diff --git a/core/java/android/net/LocalServerSocket.java b/core/java/android/net/LocalServerSocket.java
index e1eaf00..3fcde330 100644
--- a/core/java/android/net/LocalServerSocket.java
+++ b/core/java/android/net/LocalServerSocket.java
@@ -89,7 +89,7 @@
 
         impl.accept(acceptedImpl);
 
-        return LocalSocket.createLocalSocketForAccept(acceptedImpl, LocalSocket.SOCKET_UNKNOWN);
+        return LocalSocket.createLocalSocketForAccept(acceptedImpl);
     }
 
     /**
diff --git a/core/java/android/net/LocalSocket.java b/core/java/android/net/LocalSocket.java
index d9ad74b..8afa1ed 100644
--- a/core/java/android/net/LocalSocket.java
+++ b/core/java/android/net/LocalSocket.java
@@ -31,6 +31,7 @@
 public class LocalSocket implements Closeable {
 
     private final LocalSocketImpl impl;
+    /** false if impl.create() needs to be called */
     private volatile boolean implCreated;
     private LocalSocketAddress localAddress;
     private boolean isBound;
@@ -61,19 +62,6 @@
      */
     public LocalSocket(int sockType) {
         this(new LocalSocketImpl(), sockType);
-        isBound = false;
-        isConnected = false;
-    }
-
-    /**
-     * Creates a AF_LOCAL/UNIX domain stream socket with FileDescriptor.
-     * @hide
-     */
-    public LocalSocket(FileDescriptor fd) throws IOException {
-        this(new LocalSocketImpl(fd), SOCKET_UNKNOWN);
-        isBound = true;
-        isConnected = true;
-        implCreated = true;
     }
 
     private LocalSocket(LocalSocketImpl impl, int sockType) {
@@ -84,9 +72,27 @@
     }
 
     /**
+     * Creates a LocalSocket instances using the FileDescriptor for an already-connected
+     * AF_LOCAL/UNIX domain stream socket. Note: the FileDescriptor must be closed by the caller:
+     * closing the LocalSocket will not close it.
+     *
+     * @hide - used by BluetoothSocket.
+     */
+    public static LocalSocket createConnectedLocalSocket(FileDescriptor fd) {
+        return createConnectedLocalSocket(new LocalSocketImpl(fd), SOCKET_UNKNOWN);
+    }
+
+    /**
      * for use with LocalServerSocket.accept()
      */
-    static LocalSocket createLocalSocketForAccept(LocalSocketImpl impl, int sockType) {
+    static LocalSocket createLocalSocketForAccept(LocalSocketImpl impl) {
+        return createConnectedLocalSocket(impl, SOCKET_UNKNOWN);
+    }
+
+    /**
+     * Creates a LocalSocket from an existing LocalSocketImpl that is already connected.
+     */
+    private static LocalSocket createConnectedLocalSocket(LocalSocketImpl impl, int sockType) {
         LocalSocket socket = new LocalSocket(impl, sockType);
         socket.isConnected = true;
         socket.isBound = true;
diff --git a/core/java/android/net/LocalSocketImpl.java b/core/java/android/net/LocalSocketImpl.java
index d8f7821..05c8afb 100644
--- a/core/java/android/net/LocalSocketImpl.java
+++ b/core/java/android/net/LocalSocketImpl.java
@@ -218,7 +218,7 @@
      *
      * @param fd non-null; bound file descriptor
      */
-    /*package*/ LocalSocketImpl(FileDescriptor fd) throws IOException
+    /*package*/ LocalSocketImpl(FileDescriptor fd)
     {
         this.fd = fd;
     }
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 717ac70..2870dd6 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -168,11 +168,11 @@
      *         scorer.
      */
     public String getActiveScorerPackage() {
-        NetworkScorerAppData app = new NetworkScorerAppManager(mContext).getActiveScorer();
-        if (app == null) {
-            return null;
+        try {
+            return mService.getActiveScorerPackage();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return app.packageName;
     }
 
     /**
@@ -339,4 +339,19 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Determine whether the application with the given UID is the enabled scorer.
+     *
+     * @param callingUid the UID to check
+     * @return true if the provided UID is the active scorer, false otherwise.
+     * @hide
+     */
+    public boolean isCallerActiveScorer(int callingUid) {
+        try {
+            return mService.isCallerActiveScorer(callingUid);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java
index ec0bb25d..23d5af5 100644
--- a/core/java/android/net/NetworkScorerAppManager.java
+++ b/core/java/android/net/NetworkScorerAppManager.java
@@ -16,7 +16,6 @@
 
 package android.net;
 
-import android.Manifest;
 import android.Manifest.permission;
 import android.annotation.Nullable;
 import android.content.ContentResolver;
@@ -28,7 +27,9 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
+
 import com.android.internal.R;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -226,6 +227,7 @@
     }
 
     /** Determine whether the application with the given UID is the enabled scorer. */
+    @Deprecated // Use NetworkScoreManager.isCallerActiveScorer()
     public boolean isCallerActiveScorer(int callingUid) {
         NetworkScorerAppData defaultApp = getActiveScorer();
         if (defaultApp == null) {
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 9d04929..dff0a28 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -49,23 +49,23 @@
  * <i>These levels are mutually exclusive - you may only specify one of them.</i>
  *
  * <table>
- *     <tr><th>Flag Value</th> 
+ *     <tr><th>Flag Value</th>
  *     <th>CPU</th> <th>Screen</th> <th>Keyboard</th></tr>
  *
  *     <tr><td>{@link #PARTIAL_WAKE_LOCK}</td>
- *         <td>On*</td> <td>Off</td> <td>Off</td> 
+ *         <td>On*</td> <td>Off</td> <td>Off</td>
  *     </tr>
- *     
+ *
  *     <tr><td>{@link #SCREEN_DIM_WAKE_LOCK}</td>
- *         <td>On</td> <td>Dim</td> <td>Off</td> 
+ *         <td>On</td> <td>Dim</td> <td>Off</td>
  *     </tr>
  *
  *     <tr><td>{@link #SCREEN_BRIGHT_WAKE_LOCK}</td>
- *         <td>On</td> <td>Bright</td> <td>Off</td> 
+ *         <td>On</td> <td>Bright</td> <td>Off</td>
  *     </tr>
- *     
+ *
  *     <tr><td>{@link #FULL_WAKE_LOCK}</td>
- *         <td>On</td> <td>Bright</td> <td>Bright</td> 
+ *         <td>On</td> <td>Bright</td> <td>Bright</td>
  *     </tr>
  * </table>
  * </p><p>
@@ -85,13 +85,13 @@
  *         the illumination to remain on once it turns on (e.g. from user activity).  This flag
  *         will force the screen and/or keyboard to turn on immediately, when the WakeLock is
  *         acquired.  A typical use would be for notifications which are important for the user to
- *         see immediately.</td> 
+ *         see immediately.</td>
  *     </tr>
- *     
+ *
  *     <tr><td>{@link #ON_AFTER_RELEASE}</td>
  *         <td>If this flag is set, the user activity timer will be reset when the WakeLock is
- *         released, causing the illumination to remain on a bit longer.  This can be used to 
- *         reduce flicker if you are cycling between wake lock conditions.</td> 
+ *         released, causing the illumination to remain on a bit longer.  This can be used to
+ *         reduce flicker if you are cycling between wake lock conditions.</td>
  *     </tr>
  * </table>
  * <p>
@@ -479,6 +479,35 @@
     }
 
     /**
+     * Gets the minimum supported screen brightness setting for VR Mode.
+     * @hide
+     */
+    public int getMinimumScreenBrightnessForVrSetting() {
+        return mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_screenBrightnessForVrSettingMinimum);
+    }
+
+    /**
+     * Gets the maximum supported screen brightness setting for VR Mode.
+     * The screen may be allowed to become dimmer than this value but
+     * this is the maximum value that can be set by the user.
+     * @hide
+     */
+    public int getMaximumScreenBrightnessForVrSetting() {
+        return mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_screenBrightnessForVrSettingMaximum);
+    }
+
+    /**
+     * Gets the default screen brightness for VR setting.
+     * @hide
+     */
+    public int getDefaultScreenBrightnessForVrSetting() {
+        return mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_screenBrightnessForVrSettingDefault);
+    }
+
+    /**
      * Returns true if the twilight service should be used to adjust screen brightness
      * policy.  This setting is experimental and disabled by default.
      * @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cede9eb..2d4a9e9 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2889,6 +2889,15 @@
                 new InclusiveIntegerRangeValidator(0, 255);
 
         /**
+         * The screen backlight brightness between 0 and 255.
+         * @hide
+         */
+        public static final String SCREEN_BRIGHTNESS_FOR_VR = "screen_brightness_for_vr";
+
+        private static final Validator SCREEN_BRIGHTNESS_FOR_VR_VALIDATOR =
+                new InclusiveIntegerRangeValidator(0, 255);
+
+        /**
          * Control whether to enable automatic brightness mode.
          */
         public static final String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
@@ -3882,6 +3891,7 @@
             VALIDATORS.put(DIM_SCREEN, DIM_SCREEN_VALIDATOR);
             VALIDATORS.put(SCREEN_OFF_TIMEOUT, SCREEN_OFF_TIMEOUT_VALIDATOR);
             VALIDATORS.put(SCREEN_BRIGHTNESS, SCREEN_BRIGHTNESS_VALIDATOR);
+            VALIDATORS.put(SCREEN_BRIGHTNESS_FOR_VR, SCREEN_BRIGHTNESS_FOR_VR_VALIDATOR);
             VALIDATORS.put(SCREEN_BRIGHTNESS_MODE, SCREEN_BRIGHTNESS_MODE_VALIDATOR);
             VALIDATORS.put(MODE_RINGER_STREAMS_AFFECTED, MODE_RINGER_STREAMS_AFFECTED_VALIDATOR);
             VALIDATORS.put(MUTE_STREAMS_AFFECTED, MUTE_STREAMS_AFFECTED_VALIDATOR);
diff --git a/core/java/android/service/autofill/AutoFillService.java b/core/java/android/service/autofill/AutoFillService.java
index a7941c7..c2e980c 100644
--- a/core/java/android/service/autofill/AutoFillService.java
+++ b/core/java/android/service/autofill/AutoFillService.java
@@ -17,8 +17,8 @@
 
 import static android.service.voice.VoiceInteractionSession.KEY_FLAGS;
 import static android.service.voice.VoiceInteractionSession.KEY_STRUCTURE;
-import static android.view.View.ASSIST_FLAG_SANITIZED_TEXT;
-import static android.view.View.ASSIST_FLAG_NON_SANITIZED_TEXT;
+import static android.view.View.AUTO_FILL_FLAG_TYPE_FILL;
+import static android.view.View.AUTO_FILL_FLAG_TYPE_SAVE;
 
 import android.annotation.SdkConstant;
 import android.app.Activity;
@@ -32,12 +32,15 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
+import android.view.autofill.AutoFillId;
+import android.view.autofill.FillResponse;
 
 import com.android.internal.os.HandlerCaller;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.os.SomeArgs;
 
-// TODO(b/33197203): improve javadoc (class and methods)
+// TODO(b/33197203): improve javadoc (of both class and methods); in particular, make sure the
+// life-cycle (and how state could be maintained on server-side) is well documented.
 
 /**
  * Top-level service of the current auto-fill service for a given user.
@@ -58,40 +61,50 @@
     @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
     public static final String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
 
-    // Bundle keys.
-    /** @hide */
-    public static final String KEY_CALLBACK = "callback";
+    // Internal bundle keys.
+    /** @hide */ public static final String KEY_CALLBACK = "callback";
+    /** @hide */ public static final String KEY_SAVABLE_IDS = "savable_ids";
+
+    // Prefix for public bundle keys.
+    private static final String KEY_PREFIX = "android.service.autofill.extra.";
+
+    /**
+     * Key of the {@link Bundle} passed to methods such as
+     * {@link #onSaveRequest(AssistStructure, Bundle, CancellationSignal, SaveCallback)}
+     * containing the extras set by
+     * {@link android.view.autofill.FillResponse.Builder#setExtras(Bundle)}.
+     */
+    public static final String EXTRA_RESPONSE_EXTRAS = KEY_PREFIX + "RESPONSE_EXTRAS";
+
+    /**
+     * Key of the {@link Bundle} passed to methods such as
+     * {@link #onSaveRequest(AssistStructure, Bundle, CancellationSignal, SaveCallback)}
+     * containing the extras set by
+     * {@link android.view.autofill.Dataset.Builder#setExtras(Bundle)}.
+     */
+    public static final String EXTRA_DATASET_EXTRAS = KEY_PREFIX + "DATASET_EXTRAS";
 
     // Handler messages.
     private static final int MSG_CONNECT = 1;
     private static final int MSG_AUTO_FILL_ACTIVITY = 2;
     private static final int MSG_DISCONNECT = 3;
 
-    private final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
-        @Override
-        public void send(int resultCode, Bundle resultData) throws RemoteException {
-            final AssistStructure structure = resultData.getParcelable(KEY_STRUCTURE);
-            final IBinder binder = resultData.getBinder(KEY_CALLBACK);
-            final int flags = resultData.getInt(KEY_FLAGS, 0);
+    private final IAutoFillService mInterface = new IAutoFillService.Stub() {
 
+        @Override
+        public void autoFill(AssistStructure structure, IAutoFillServerCallback callback,
+                Bundle extras, int flags) {
             mHandlerCaller
-                .obtainMessageIOO(MSG_AUTO_FILL_ACTIVITY, flags, structure, binder).sendToTarget();
+                    .obtainMessageIOOO(MSG_AUTO_FILL_ACTIVITY, flags, structure, extras, callback)
+                    .sendToTarget();
         }
 
-    };
-
-    private final IAutoFillService mInterface = new IAutoFillService.Stub() {
         @Override
         public void onConnected() {
             mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_CONNECT));
         }
 
         @Override
-        public IResultReceiver getAssistReceiver() {
-            return mAssistReceiver;
-        }
-
-        @Override
         public void onDisconnected() {
             mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_DISCONNECT));
         }
@@ -107,10 +120,11 @@
                     break;
                 } case MSG_AUTO_FILL_ACTIVITY: {
                     final SomeArgs args = (SomeArgs) msg.obj;
-                    final AssistStructure structure = (AssistStructure) args.arg1;
-                    final IBinder binder = (IBinder) args.arg2;
                     final int flags = msg.arg1;
-                    requestAutoFill(structure, flags, binder);
+                    final AssistStructure structure = (AssistStructure) args.arg1;
+                    final Bundle extras = (Bundle) args.arg2;
+                    final IAutoFillServerCallback callback = (IAutoFillServerCallback) args.arg3;
+                    requestAutoFill(callback, structure, extras, flags);
                     break;
                 } case MSG_DISCONNECT: {
                     onDisconnected();
@@ -146,7 +160,7 @@
     }
 
     /**
-     * Called when the Android System connects to service.
+     * Called when the Android system connects to service.
      *
      * <p>You should generally do initialization here rather than in {@link #onCreate}.
      */
@@ -155,12 +169,19 @@
     }
 
     /**
-     * Called when user requests service to auto-fill an {@link Activity}.
+     * Called by the Android system do decide if an {@link Activity} can be auto-filled by the
+     * service.
      *
-     * @param structure {@link Activity}'s view structure .
-     * @param data bundle with optional parameters (currently none) which is passed along on
-     * subsequent calls (so it can be used by the service to share data).
+     * <p>Service must call one of the {@link FillCallback} methods (like
+     * {@link FillCallback#onSuccess(FillResponse)} or {@link FillCallback#onFailure(CharSequence)})
+     * to notify the result of the request.
+     *
+     * @param structure {@link Activity}'s view structure.
+     * @param data bundle containing additional arguments set by the Android system (currently none)
+     * or data passed by the service on previous calls to fullfill other sections of this activity
+     * (see {@link FillResponse} Javadoc for examples of multiple-sections requests).
      * @param cancellationSignal signal for observing cancel requests.
+     * @param callback object used to notify the result of the request.
      */
     public abstract void onFillRequest(AssistStructure structure,
             Bundle data, CancellationSignal cancellationSignal, FillCallback callback);
@@ -168,29 +189,31 @@
     /**
      * Called when user requests service to save the fields of an {@link Activity}.
      *
+     * <p>Service must call one of the {@link SaveCallback} methods (like
+     * {@link SaveCallback#onSuccess(AutoFillId[])} or {@link SaveCallback#onFailure(CharSequence)})
+     * to notify the result of the request.
+     *
      * @param structure {@link Activity}'s view structure.
-     * @param data same bundle passed to
-     * {@link #onFillRequest(AssistStructure, Bundle, CancellationSignal, FillCallback)};
-     * might also contain with optional parameters (currently none).
+     * @param data bundle containing additional arguments set by the Android system (currently none)
+     * or data passed by the service in the {@link FillResponse} that originated this call.
      * @param cancellationSignal signal for observing cancel requests.
      * @param callback object used to notify the result of the request.
      */
     public abstract void onSaveRequest(AssistStructure structure,
             Bundle data, CancellationSignal cancellationSignal, SaveCallback callback);
 
-    private void requestAutoFill(AssistStructure structure, int flags, IBinder binder) {
-        // TODO(b/33197203): pass the Bundle received from mAssistReceiver instead?
-        final Bundle data = new Bundle();
+    private void requestAutoFill(IAutoFillServerCallback callback, AssistStructure structure,
+            Bundle data, int flags) {
         switch (flags) {
-            case ASSIST_FLAG_SANITIZED_TEXT:
-                final FillCallback fillCallback = new FillCallback(binder);
+            case AUTO_FILL_FLAG_TYPE_FILL:
+                final FillCallback fillCallback = new FillCallback(callback);
                 // TODO(b/33197203): hook up the cancelationSignal
                 onFillRequest(structure, data, new CancellationSignal(), fillCallback);
                 break;
-            case ASSIST_FLAG_NON_SANITIZED_TEXT:
-                final SaveCallback saveCallback = new SaveCallback(binder);
+            case AUTO_FILL_FLAG_TYPE_SAVE:
+                final SaveCallback saveCallback = new SaveCallback(callback);
                 // TODO(b/33197203): hook up the cancelationSignal
-                onSaveRequest(structure, null, new CancellationSignal(), saveCallback);
+                onSaveRequest(structure, data, new CancellationSignal(), saveCallback);
                 break;
             default:
                 Log.w(TAG, "invalid flag on requestAutoFill(): " + flags);
@@ -198,7 +221,7 @@
     }
 
     /**
-     * Called when the Android System disconnects from the service.
+     * Called when the Android system disconnects from the service.
      *
      * <p> At this point this service may no longer be an active {@link AutoFillService}.
      */
diff --git a/core/java/android/service/autofill/FillCallback.java b/core/java/android/service/autofill/FillCallback.java
index 3284b90..5a9a9f6 100644
--- a/core/java/android/service/autofill/FillCallback.java
+++ b/core/java/android/service/autofill/FillCallback.java
@@ -18,19 +18,16 @@
 
 import static android.service.autofill.AutoFillService.DEBUG;
 
+import android.annotation.Nullable;
 import android.app.Activity;
-import android.app.assist.AssistStructure.ViewNode;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
-import android.util.SparseArray;
+import android.view.autofill.FillResponse;
 
 import com.android.internal.util.Preconditions;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
 /**
  * Handles auto-fill requests from the {@link AutoFillService} into the {@link Activity} being
  * auto-filled.
@@ -39,40 +36,50 @@
 
     private static final String TAG = "FillCallback";
 
-    private final IAutoFillCallback mCallback;
+    private final IAutoFillServerCallback mCallback;
+
+    private boolean mReplied = false;
 
     /** @hide */
-    FillCallback(IBinder binder) {
-        mCallback = IAutoFillCallback.Stub.asInterface(binder);
+    FillCallback(IAutoFillServerCallback callback) {
+        mCallback = callback;
     }
 
     /**
-     * Auto-fills the {@link Activity}.
+     * Notifies the Android System that an
+     * {@link AutoFillService#onFillRequest(android.app.assist.AssistStructure, Bundle, android.os.CancellationSignal, FillCallback)}
+     * was successfully fulfilled by the service.
      *
-     * @throws RuntimeException if an error occurred while auto-filling it.
+     * @param response auto-fill information for that activity, or {@code null} when the activity
+     * cannot be auto-filled (for example, if it only contains read-only fields).
+     *
+     * @throws RuntimeException if an error occurred while calling the Android System.
      */
-    public void onSuccess(FillData data) {
-        if (DEBUG) Log.d(TAG, "onSuccess(): data=" + data);
+    public void onSuccess(@Nullable FillResponse response) {
+        if (DEBUG) Log.d(TAG, "onSuccess(): respose=" + response);
 
-        Preconditions.checkArgument(data != null, "data cannot be null");
+        checkNotRepliedYet();
 
         try {
-            mCallback.autofill(data.asList());
+            mCallback.showResponse(response);
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
     }
 
     /**
-     * Notifies the {@link Activity} that the auto-fill request failed.
+     * Notifies the Android System that an
+     * {@link AutoFillService#onFillRequest(android.app.assist.AssistStructure, Bundle, android.os.CancellationSignal, FillCallback)}
+     * could not be fulfilled by the service.
      *
-     * @param message error message to be displayed.
+     * @param message error message to be displayed to the user.
      *
-     * @throws RuntimeException if an error occurred while notifying the activity.
+     * @throws RuntimeException if an error occurred while calling the Android System.
      */
     public void onFailure(CharSequence message) {
         if (DEBUG) Log.d(TAG, "onFailure(): message=" + message);
 
+        checkNotRepliedYet();
         Preconditions.checkArgument(message != null, "message cannot be null");
 
         try {
@@ -82,70 +89,9 @@
         }
     }
 
-    /**
-     * Data used to fill the fields of an {@link Activity}.
-     *
-     * <p>This class is immutable.
-     */
-    public static final class FillData {
-
-        private final List<FillableInputField> mList;
-
-        private FillData(Builder builder) {
-            final int size = builder.mFields.size();
-            final List<FillableInputField> list = new ArrayList<>(size);
-            for (int i = 0; i < size; i++) {
-                list.add(builder.mFields.valueAt(i));
-            }
-            mList = Collections.unmodifiableList(list);
-            // TODO: use FastImmutableArraySet or a similar structure instead?
-        }
-
-        /**
-         * Gets the response as a {@code List} so it can be used in a binder call.
-         */
-        List<FillableInputField> asList() {
-            return mList;
-        }
-
-        @Override
-        public String toString() {
-            return "[AutoFillResponse: " + mList + "]";
-        }
-
-        /**
-         * Builder for {@link FillData} objects.
-         *
-         * <p>Typical usage:
-         *
-         * <pre class="prettyprint">
-         * FillCallback.FillData data = new FillCallback.FillData.Builder()
-         *     .setTextField(id1, "value 1")
-         *     .setTextField(id2, "value 2")
-         *     .build()
-         * </pre>
-         */
-        public static class Builder {
-            private final SparseArray<FillableInputField> mFields = new SparseArray<>();
-
-            /**
-             * Auto-fills a text field.
-             *
-             * @param id view id as returned by {@link ViewNode#getAutoFillId()}.
-             * @param text text to be auto-filled.
-             * @return same builder so it can be chained.
-             */
-            public Builder setTextField(int id, String text) {
-                mFields.put(id, FillableInputField.forText(id, text));
-                return this;
-            }
-
-            /**
-             * Builds a new {@link FillData} instance.
-             */
-            public FillData build() {
-                return new FillData(this);
-            }
-        }
+    // There can be only one!!
+    private void checkNotRepliedYet() {
+        Preconditions.checkState(!mReplied, "already replied");
+        mReplied = true;
     }
 }
diff --git a/core/java/android/service/autofill/FillableInputField.java b/core/java/android/service/autofill/FillableInputField.java
deleted file mode 100644
index 62950b4..0000000
--- a/core/java/android/service/autofill/FillableInputField.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2016 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.service.autofill;
-
-import android.app.assist.AssistStructure.ViewNode;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Represents a view field that can be auto-filled.
- *
- * <p>Currently only text-fields are supported, so the value of the field can be obtained through
- * {@link #getValue()}.
- *
- * @hide
- */
-public final class FillableInputField implements Parcelable {
-
-    private final int mId;
-    private final String mValue;
-
-    private FillableInputField(int id, String value) {
-        mId = id;
-        mValue = value;
-    }
-
-    private FillableInputField(Parcel parcel) {
-        mId = parcel.readInt();
-        mValue = parcel.readString();
-    }
-
-    /**
-     * Gets the view id as returned by {@link ViewNode#getAutoFillId()}.
-     */
-    public int getId() {
-        return mId;
-    }
-
-    /**
-     * Gets the value of this field.
-     */
-    public String getValue() {
-        return mValue;
-
-    }
-
-    @Override
-    public String toString() {
-        return "[AutoFillField: " + mId + "=" + mValue + "]";
-    }
-
-    /**
-     * Creates an {@code AutoFillField} for a text field.
-     *
-     * @param id view id as returned by {@link ViewNode#getAutoFillId()}.
-     * @param text value to be auto-filled.
-     */
-    public static FillableInputField forText(int id, String text) {
-        return new FillableInputField(id, text);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeInt(mId);
-        parcel.writeString(mValue);
-    }
-
-    public static final Parcelable.Creator<FillableInputField> CREATOR =
-            new Parcelable.Creator<FillableInputField>() {
-        @Override
-        public FillableInputField createFromParcel(Parcel source) {
-            return new FillableInputField(source);
-        }
-
-        @Override
-        public FillableInputField[] newArray(int size) {
-            return new FillableInputField[size];
-        }
-    };
-}
diff --git a/core/java/android/service/autofill/IAutoFillCallback.aidl b/core/java/android/service/autofill/IAutoFillAppCallback.aidl
similarity index 85%
rename from core/java/android/service/autofill/IAutoFillCallback.aidl
rename to core/java/android/service/autofill/IAutoFillAppCallback.aidl
index d6d4f39..629b1f0 100644
--- a/core/java/android/service/autofill/IAutoFillCallback.aidl
+++ b/core/java/android/service/autofill/IAutoFillAppCallback.aidl
@@ -18,10 +18,11 @@
 
 import java.util.List;
 
+import android.view.autofill.Dataset;
+
 /**
  * @hide
  */
-oneway interface IAutoFillCallback {
-    void autofill(in List values);
-    void showError(String message);
+oneway interface IAutoFillAppCallback {
+    void autoFill(in Dataset dataset);
 }
diff --git a/core/java/android/service/autofill/IAutoFillManagerService.aidl b/core/java/android/service/autofill/IAutoFillManagerService.aidl
index f1251c0..f8ae57b 100644
--- a/core/java/android/service/autofill/IAutoFillManagerService.aidl
+++ b/core/java/android/service/autofill/IAutoFillManagerService.aidl
@@ -24,6 +24,5 @@
  * {@hide}
  */
 oneway interface IAutoFillManagerService {
-
-    void requestAutoFill(IBinder activityToken, int userId, int flags);
+    void requestAutoFill(IBinder activityToken, int userId, in Bundle extras, int flags);
 }
diff --git a/core/java/android/service/autofill/IAutoFillCallback.aidl b/core/java/android/service/autofill/IAutoFillServerCallback.aidl
similarity index 76%
copy from core/java/android/service/autofill/IAutoFillCallback.aidl
copy to core/java/android/service/autofill/IAutoFillServerCallback.aidl
index d6d4f39..9d58c99 100644
--- a/core/java/android/service/autofill/IAutoFillCallback.aidl
+++ b/core/java/android/service/autofill/IAutoFillServerCallback.aidl
@@ -18,10 +18,14 @@
 
 import java.util.List;
 
+import android.view.autofill.AutoFillId;
+import android.view.autofill.FillResponse;
+
 /**
  * @hide
  */
-oneway interface IAutoFillCallback {
-    void autofill(in List values);
+oneway interface IAutoFillServerCallback {
+    void showResponse(in FillResponse response);
     void showError(String message);
+    void highlightSavedFields(in AutoFillId[] ids);
 }
diff --git a/core/java/android/service/autofill/IAutoFillService.aidl b/core/java/android/service/autofill/IAutoFillService.aidl
index bb122e5..a1f22bf 100644
--- a/core/java/android/service/autofill/IAutoFillService.aidl
+++ b/core/java/android/service/autofill/IAutoFillService.aidl
@@ -18,14 +18,15 @@
 
 import android.app.assist.AssistStructure;
 import android.os.Bundle;
-import android.service.autofill.IAutoFillCallback;
+import android.service.autofill.IAutoFillServerCallback;
 import com.android.internal.os.IResultReceiver;
 
 /**
  * @hide
  */
-interface IAutoFillService {
-    oneway void onConnected();
-    oneway void onDisconnected();
-    IResultReceiver getAssistReceiver();
+oneway interface IAutoFillService {
+    void autoFill(in AssistStructure structure, in IAutoFillServerCallback callback,
+                  in Bundle extras, int flags);
+    void onConnected();
+    void onDisconnected();
 }
diff --git a/core/java/android/service/autofill/SaveCallback.java b/core/java/android/service/autofill/SaveCallback.java
index 4dc7392..627d74c 100644
--- a/core/java/android/service/autofill/SaveCallback.java
+++ b/core/java/android/service/autofill/SaveCallback.java
@@ -20,9 +20,11 @@
 
 import android.app.Activity;
 import android.app.assist.AssistStructure.ViewNode;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
+import android.view.autofill.AutoFillId;
 
 import com.android.internal.util.Preconditions;
 
@@ -34,41 +36,53 @@
 
     private static final String TAG = "SaveCallback";
 
-    private final IAutoFillCallback mCallback;
+    private final IAutoFillServerCallback mCallback;
+
+    private boolean mReplied = false;
 
     /** @hide */
-    SaveCallback(IBinder binder) {
-        mCallback = IAutoFillCallback.Stub.asInterface(binder);
+    SaveCallback(IAutoFillServerCallback callback) {
+        mCallback = callback;
     }
 
     /**
-     * Notifies the {@link Activity} that the save request succeeded.
+     * Notifies the Android System that an
+     * {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle, android.os.CancellationSignal, SaveCallback)}
+     * was successfully fulfilled by the service.
      *
      * @param ids ids ({@link ViewNode#getAutoFillId()}) of the fields that were saved.
      *
-     * @throws RuntimeException if an error occurred while saving the data.
+     * @throws RuntimeException if an error occurred while calling the Android System.
      */
-    public void onSuccess(int[] ids) {
+    public void onSuccess(AutoFillId[] ids) {
+        if (DEBUG) Log.d(TAG, "onSuccess(): ids=" + ((ids == null) ? "null" : ids.length));
+
         Preconditions.checkArgument(ids != null, "ids cannot be null");
+        checkNotRepliedYet();
 
         Preconditions.checkArgument(ids.length > 0, "ids cannot be empty");
 
-        if (DEBUG) Log.d(TAG, "onSuccess(): ids=" + ids.length);
-
-        // TODO(b/33197203): display which ids were saved
+        try {
+            mCallback.highlightSavedFields(ids);
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
+        }
     }
 
     /**
-     * Notifies the {@link Activity} that the save request failed.
+     * Notifies the Android System that an
+     * {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle, android.os.CancellationSignal, SaveCallback)}
+     * could not be fulfilled by the service.
      *
-     * @param message error message to be displayed.
+     * @param message error message to be displayed to the user.
      *
-     * @throws RuntimeException if an error occurred while notifying the activity.
+     * @throws RuntimeException if an error occurred while calling the Android System.
      */
     public void onFailure(CharSequence message) {
         if (DEBUG) Log.d(TAG, "onFailure(): message=" + message);
 
         Preconditions.checkArgument(message != null, "message cannot be null");
+        checkNotRepliedYet();
 
         try {
             mCallback.showError(message.toString());
@@ -76,4 +90,10 @@
             e.rethrowAsRuntimeException();
         }
     }
+
+    // There can be only one!!
+    private void checkNotRepliedYet() {
+        Preconditions.checkState(!mReplied, "already replied");
+        mReplied = true;
+    }
 }
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 9ac8996..1e9deeb 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -85,7 +85,7 @@
         this(base, display, paint, width, align, TextDirectionHeuristics.FIRSTSTRONG_LTR,
                 spacingmult, spacingadd, includepad,
                 StaticLayout.BREAK_STRATEGY_SIMPLE, StaticLayout.HYPHENATION_FREQUENCY_NONE,
-                ellipsize, ellipsizedWidth);
+                false /* justify */, ellipsize, ellipsizedWidth);
     }
 
     /**
@@ -102,7 +102,8 @@
                          int width, Alignment align, TextDirectionHeuristic textDir,
                          float spacingmult, float spacingadd,
                          boolean includepad, int breakStrategy, int hyphenationFrequency,
-                         TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
+                         boolean justify, TextUtils.TruncateAt ellipsize,
+                         int ellipsizedWidth) {
         super((ellipsize == null)
                 ? display
                 : (display instanceof Spanned)
@@ -127,6 +128,7 @@
 
         mIncludePad = includepad;
         mBreakStrategy = breakStrategy;
+        mJustify = justify;
         mHyphenationFrequency = hyphenationFrequency;
 
         /*
@@ -300,7 +302,8 @@
                 .setEllipsizedWidth(mEllipsizedWidth)
                 .setEllipsize(mEllipsizeAt)
                 .setBreakStrategy(mBreakStrategy)
-                .setHyphenationFrequency(mHyphenationFrequency);
+                .setHyphenationFrequency(mHyphenationFrequency)
+                .setJustify(mJustify);
         reflowed.generate(b, false, true);
         int n = reflowed.getLineCount();
         // If the new layout has a blank line at the end, but it is not
@@ -808,6 +811,7 @@
     private TextUtils.TruncateAt mEllipsizeAt;
     private int mBreakStrategy;
     private int mHyphenationFrequency;
+    private boolean mJustify;
 
     private PackedIntVector mInts;
     private PackedObjectVector<Directions> mObjects;
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 3cb81b0..2fc12d3 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -218,6 +218,11 @@
         mTextDir = textDir;
     }
 
+    /** @hide */
+    protected void setJustify(boolean justify) {
+        mJustify = justify;
+    }
+
     /**
      * Replace constructor properties of this Layout with new ones.  Be careful.
      */
@@ -266,6 +271,99 @@
         drawText(canvas, firstLine, lastLine);
     }
 
+    private boolean isJustificationRequired(int lineNum) {
+        if (!mJustify) return false;
+        final int lineEnd = getLineEnd(lineNum);
+        return lineEnd < mText.length() && mText.charAt(lineEnd - 1) != '\n';
+    }
+
+    private float getJustifyWidth(int lineNum) {
+        Alignment paraAlign = mAlignment;
+        TabStops tabStops = null;
+        boolean tabStopsIsInitialized = false;
+
+        int left = 0;
+        int right = mWidth;
+
+        final int dir = getParagraphDirection(lineNum);
+
+        ParagraphStyle[] spans = NO_PARA_SPANS;
+        if (mSpannedText) {
+            Spanned sp = (Spanned) mText;
+            final int start = getLineStart(lineNum);
+
+            final boolean isFirstParaLine = (start == 0 || mText.charAt(start - 1) == '\n');
+
+            if (isFirstParaLine) {
+                final int spanEnd = sp.nextSpanTransition(start, mText.length(),
+                        ParagraphStyle.class);
+                spans = getParagraphSpans(sp, start, spanEnd, ParagraphStyle.class);
+
+                for (int n = spans.length - 1; n >= 0; n--) {
+                    if (spans[n] instanceof AlignmentSpan) {
+                        paraAlign = ((AlignmentSpan) spans[n]).getAlignment();
+                        break;
+                    }
+                }
+            }
+
+            final int length = spans.length;
+            boolean useFirstLineMargin = isFirstParaLine;
+            for (int n = 0; n < length; n++) {
+                if (spans[n] instanceof LeadingMarginSpan2) {
+                    int count = ((LeadingMarginSpan2) spans[n]).getLeadingMarginLineCount();
+                    int startLine = getLineForOffset(sp.getSpanStart(spans[n]));
+                    if (lineNum < startLine + count) {
+                        useFirstLineMargin = true;
+                        break;
+                    }
+                }
+            }
+            for (int n = 0; n < length; n++) {
+                if (spans[n] instanceof LeadingMarginSpan) {
+                    LeadingMarginSpan margin = (LeadingMarginSpan) spans[n];
+                    if (dir == DIR_RIGHT_TO_LEFT) {
+                        right -= margin.getLeadingMargin(useFirstLineMargin);
+                    } else {
+                        left += margin.getLeadingMargin(useFirstLineMargin);
+                    }
+                }
+            }
+        }
+
+        if (getLineContainsTab(lineNum)) {
+            tabStops = new TabStops(TAB_INCREMENT, spans);
+        }
+
+        final Alignment align;
+        if (paraAlign == Alignment.ALIGN_LEFT) {
+            align = (dir == DIR_LEFT_TO_RIGHT) ?  Alignment.ALIGN_NORMAL : Alignment.ALIGN_OPPOSITE;
+        } else if (paraAlign == Alignment.ALIGN_RIGHT) {
+            align = (dir == DIR_LEFT_TO_RIGHT) ?  Alignment.ALIGN_OPPOSITE : Alignment.ALIGN_NORMAL;
+        } else {
+            align = paraAlign;
+        }
+
+        final int indentWidth;
+        if (align == Alignment.ALIGN_NORMAL) {
+            if (dir == DIR_LEFT_TO_RIGHT) {
+                indentWidth = getIndentAdjust(lineNum, Alignment.ALIGN_LEFT);
+            } else {
+                indentWidth = -getIndentAdjust(lineNum, Alignment.ALIGN_RIGHT);
+            }
+        } else if (align == Alignment.ALIGN_OPPOSITE) {
+            if (dir == DIR_LEFT_TO_RIGHT) {
+                indentWidth = -getIndentAdjust(lineNum, Alignment.ALIGN_RIGHT);
+            } else {
+                indentWidth = getIndentAdjust(lineNum, Alignment.ALIGN_LEFT);
+            }
+        } else { // Alignment.ALIGN_CENTER
+            indentWidth = getIndentAdjust(lineNum, Alignment.ALIGN_CENTER);
+        }
+
+        return right - left - indentWidth;
+    }
+
     /**
      * @hide
      */
@@ -274,7 +372,7 @@
         int previousLineEnd = getLineStart(firstLine);
         ParagraphStyle[] spans = NO_PARA_SPANS;
         int spanEnd = 0;
-        TextPaint paint = mPaint;
+        final TextPaint paint = mPaint;
         CharSequence buf = mText;
 
         Alignment paraAlign = mAlignment;
@@ -288,6 +386,7 @@
         for (int lineNum = firstLine; lineNum <= lastLine; lineNum++) {
             int start = previousLineEnd;
             previousLineEnd = getLineStart(lineNum + 1);
+            final boolean justify = isJustificationRequired(lineNum);
             int end = getLineVisibleEnd(lineNum, start, previousLineEnd);
 
             int ltop = previousLineBottom;
@@ -386,34 +485,42 @@
             }
 
             int x;
+            final int indentWidth;
             if (align == Alignment.ALIGN_NORMAL) {
                 if (dir == DIR_LEFT_TO_RIGHT) {
-                    x = left + getIndentAdjust(lineNum, Alignment.ALIGN_LEFT);
+                    indentWidth = getIndentAdjust(lineNum, Alignment.ALIGN_LEFT);
+                    x = left + indentWidth;
                 } else {
-                    x = right + getIndentAdjust(lineNum, Alignment.ALIGN_RIGHT);
+                    indentWidth = -getIndentAdjust(lineNum, Alignment.ALIGN_RIGHT);
+                    x = right - indentWidth;
                 }
             } else {
                 int max = (int)getLineExtent(lineNum, tabStops, false);
                 if (align == Alignment.ALIGN_OPPOSITE) {
                     if (dir == DIR_LEFT_TO_RIGHT) {
-                        x = right - max + getIndentAdjust(lineNum, Alignment.ALIGN_RIGHT);
+                        indentWidth = -getIndentAdjust(lineNum, Alignment.ALIGN_RIGHT);
+                        x = right - max - indentWidth;
                     } else {
-                        x = left - max + getIndentAdjust(lineNum, Alignment.ALIGN_LEFT);
+                        indentWidth = getIndentAdjust(lineNum, Alignment.ALIGN_LEFT);
+                        x = left - max + indentWidth;
                     }
                 } else { // Alignment.ALIGN_CENTER
+                    indentWidth = getIndentAdjust(lineNum, Alignment.ALIGN_CENTER);
                     max = max & ~1;
-                    x = ((right + left - max) >> 1) +
-                            getIndentAdjust(lineNum, Alignment.ALIGN_CENTER);
+                    x = ((right + left - max) >> 1) + indentWidth;
                 }
             }
 
             paint.setHyphenEdit(getHyphen(lineNum));
             Directions directions = getLineDirections(lineNum);
-            if (directions == DIRS_ALL_LEFT_TO_RIGHT && !mSpannedText && !hasTab) {
+            if (directions == DIRS_ALL_LEFT_TO_RIGHT && !mSpannedText && !hasTab && !justify) {
                 // XXX: assumes there's nothing additional to be done
                 canvas.drawText(buf, start, end, x, lbaseline, paint);
             } else {
                 tl.set(paint, buf, start, end, dir, directions, hasTab, tabStops);
+                if (justify) {
+                    tl.justify(right - left - indentWidth);
+                }
                 tl.draw(canvas, x, ltop, lbaseline, lbottom);
             }
             paint.setHyphenEdit(0);
@@ -1094,6 +1201,9 @@
         TextLine tl = TextLine.obtain();
         mPaint.setHyphenEdit(getHyphen(line));
         tl.set(mPaint, mText, start, end, dir, directions, hasTabs, tabStops);
+        if (isJustificationRequired(line)) {
+            tl.justify(getJustifyWidth(line));
+        }
         float width = tl.metrics(null);
         mPaint.setHyphenEdit(0);
         TextLine.recycle(tl);
@@ -1118,6 +1228,9 @@
         TextLine tl = TextLine.obtain();
         mPaint.setHyphenEdit(getHyphen(line));
         tl.set(mPaint, mText, start, end, dir, directions, hasTabs, tabStops);
+        if (isJustificationRequired(line)) {
+            tl.justify(getJustifyWidth(line));
+        }
         float width = tl.metrics(null);
         mPaint.setHyphenEdit(0);
         TextLine.recycle(tl);
@@ -1303,10 +1416,7 @@
                 return end - 1;
             }
 
-            // Note: keep this in sync with Minikin LineBreaker::isLineEndSpace()
-            if (!(ch == ' ' || ch == '\t' || ch == 0x1680 ||
-                    (0x2000 <= ch && ch <= 0x200A && ch != 0x2007) ||
-                    ch == 0x205F || ch == 0x3000)) {
+            if (!TextLine.isLineEndSpace(ch)) {
                 break;
             }
 
@@ -2086,6 +2196,7 @@
     private boolean mSpannedText;
     private TextDirectionHeuristic mTextDir;
     private SpanSet<LineBackgroundSpan> mLineBackgroundSpans;
+    private boolean mJustify;
 
     public static final int DIR_LEFT_TO_RIGHT = 1;
     public static final int DIR_RIGHT_TO_LEFT = -1;
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 081be3a..cb5b073 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -94,6 +94,7 @@
             b.mMaxLines = Integer.MAX_VALUE;
             b.mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
             b.mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE;
+            b.mJustify = false;
 
             b.mMeasuredText = MeasuredText.obtain();
             return b;
@@ -320,6 +321,17 @@
         }
 
         /**
+         * Enables or disables paragraph justification. The default value is disabled (false).
+         *
+         * @param justify true for enabling and false for disabling paragraph justification.
+         * @return this builder, useful for chaining.
+         */
+        public Builder setJustify(boolean justify) {
+            mJustify = justify;
+            return this;
+        }
+
+        /**
          * Measurement and break iteration is done in native code. The protocol for using
          * the native code is as follows.
          *
@@ -404,6 +416,7 @@
         int mHyphenationFrequency;
         int[] mLeftIndents;
         int[] mRightIndents;
+        boolean mJustify;
 
         Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
 
@@ -557,6 +570,7 @@
 
         mLeftIndents = b.mLeftIndents;
         mRightIndents = b.mRightIndents;
+        setJustify(b.mJustify);
 
         generate(b, b.mIncludePad, b.mIncludePad);
     }
@@ -676,7 +690,8 @@
 
             nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart,
                     firstWidth, firstWidthLineCount, restWidth,
-                    variableTabStops, TAB_INCREMENT, b.mBreakStrategy, b.mHyphenationFrequency);
+                    variableTabStops, TAB_INCREMENT, b.mBreakStrategy, b.mHyphenationFrequency,
+                    b.mJustify);
             if (mLeftIndents != null || mRightIndents != null) {
                 // TODO(raph) performance: it would be better to do this once per layout rather
                 // than once per paragraph, but that would require a change to the native
@@ -1284,7 +1299,8 @@
     // Set up paragraph text and settings; done as one big method to minimize jni crossings
     private static native void nSetupParagraph(long nativePtr, char[] text, int length,
             float firstWidth, int firstWidthLineCount, float restWidth,
-            int[] variableTabStops, int defaultTabStop, int breakStrategy, int hyphenationFrequency);
+            int[] variableTabStops, int defaultTabStop, int breakStrategy, int hyphenationFrequency,
+            boolean isJustified);
 
     private static native float nAddStyleRun(long nativePtr, long nativePaint,
             long nativeTypeface, int start, int end, boolean isRtl);
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index c411860..fcff9a2 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -54,6 +54,10 @@
     private char[] mChars;
     private boolean mCharsValid;
     private Spanned mSpanned;
+
+    // Additional width of whitespace for justification. This value is per whitespace, thus
+    // the line width will increase by mAddedWidth x (number of stretchable whitespaces).
+    private float mAddedWidth;
     private final TextPaint mWorkPaint = new TextPaint();
     private final SpanSet<MetricAffectingSpan> mMetricAffectingSpanSpanSet =
             new SpanSet<MetricAffectingSpan>(MetricAffectingSpan.class);
@@ -177,6 +181,25 @@
             }
         }
         mTabs = tabStops;
+        mAddedWidth = 0;
+    }
+
+    /**
+     * Justify the line to the given width.
+     */
+    void justify(float justifyWidth) {
+        int end = mLen;
+        while (end > 0 && isLineEndSpace(mText.charAt(mStart + end - 1))) {
+            end--;
+        }
+        final int spaces = countStretchableSpaces(0, end);
+        if (spaces == 0) {
+            // There are no stretchable spaces, so we can't help the justification by adding any
+            // width.
+            return;
+        }
+        final float width = Math.abs(measure(end, false, null));
+        mAddedWidth = (justifyWidth - width) / spaces;
     }
 
     /**
@@ -595,6 +618,7 @@
 
         TextPaint wp = mWorkPaint;
         wp.set(mPaint);
+        wp.setWordSpacing(mAddedWidth);
 
         int spanStart = runStart;
         int spanLimit;
@@ -695,6 +719,7 @@
             Canvas c, float x, int top, int y, int bottom,
             FontMetricsInt fmi, boolean needWidth, int offset) {
 
+        wp.setWordSpacing(mAddedWidth);
         // Get metrics first (even for empty strings or "0" width runs)
         if (fmi != null) {
             expandMetricsFromPaint(fmi, wp);
@@ -981,5 +1006,34 @@
         return TabStops.nextDefaultStop(h, TAB_INCREMENT);
     }
 
+    private boolean isStretchableWhitespace(int ch) {
+        // TODO: Support other stretchable whitespace. (Bug: 34013491)
+        return ch == 0x0020 || ch == 0x00A0;
+    }
+
+    private int nextStretchableSpace(int start, int end) {
+        for (int i = start; i < end; i++) {
+            final char c = mCharsValid ? mChars[i] : mText.charAt(i + mStart);
+            if (isStretchableWhitespace(c)) return i;
+        }
+        return end;
+    }
+
+    /* Return the number of spaces in the text line, for the purpose of justification */
+    private int countStretchableSpaces(int start, int end) {
+        int count = 0;
+        for (int i = start; i < end; i = nextStretchableSpace(i + 1, end)) {
+            count++;
+        }
+        return count;
+    }
+
+    // Note: keep this in sync with Minikin LineBreaker::isLineEndSpace()
+    public static boolean isLineEndSpace(char ch) {
+        return ch == ' ' || ch == '\t' || ch == 0x1680
+                || (0x2000 <= ch && ch <= 0x200A && ch != 0x2007)
+                || ch == 0x205F || ch == 0x3000;
+    }
+
     private static final int TAB_INCREMENT = 20;
 }
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 58bc9a7..bb952ab 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -29,6 +29,8 @@
 import android.os.SystemProperties;
 import android.provider.Settings;
 import android.text.style.AbsoluteSizeSpan;
+import android.text.style.AccessibilityClickableSpan;
+import android.text.style.AccessibilityURLSpan;
 import android.text.style.AlignmentSpan;
 import android.text.style.BackgroundColorSpan;
 import android.text.style.BulletSpan;
@@ -621,7 +623,11 @@
     /** @hide */
     public static final int TTS_SPAN = 24;
     /** @hide */
-    public static final int LAST_SPAN = TTS_SPAN;
+    public static final int ACCESSIBILITY_CLICKABLE_SPAN = 25;
+    /** @hide */
+    public static final int ACCESSIBILITY_URL_SPAN = 26;
+    /** @hide */
+    public static final int LAST_SPAN = ACCESSIBILITY_URL_SPAN;
 
     /**
      * Flatten a CharSequence and whatever styles can be copied across processes
@@ -803,6 +809,14 @@
                     readSpan(p, sp, new TtsSpan(p));
                     break;
 
+                case ACCESSIBILITY_CLICKABLE_SPAN:
+                    readSpan(p, sp, new AccessibilityClickableSpan(p));
+                    break;
+
+                case ACCESSIBILITY_URL_SPAN:
+                    readSpan(p, sp, new AccessibilityURLSpan(p));
+                    break;
+
                 default:
                     throw new RuntimeException("bogus span encoding " + kind);
                 }
diff --git a/core/java/android/text/style/AccessibilityClickableSpan.java b/core/java/android/text/style/AccessibilityClickableSpan.java
new file mode 100644
index 0000000..9c305ff
--- /dev/null
+++ b/core/java/android/text/style/AccessibilityClickableSpan.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2016 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.text.style;
+
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.ParcelableSpan;
+import android.text.Spanned;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import com.android.internal.R;
+
+import java.lang.ref.WeakReference;
+
+
+/**
+ * {@link ClickableSpan} cannot be parceled, but accessibility services need to be able to cause
+ * their callback handlers to be called. This class serves as a parcelable placeholder for the
+ * real spans.
+ *
+ * This span is also passed back to an app's process when an accessibility service tries to click
+ * it. It contains enough information to track down the original clickable span so it can be
+ * called.
+ *
+ * @hide
+ */
+public class AccessibilityClickableSpan extends ClickableSpan
+        implements ParcelableSpan {
+    // The id of the span this one replaces
+    private final int mOriginalClickableSpanId;
+
+    // Only retain a weak reference to the node to avoid referencing cycles that could create memory
+    // leaks.
+    private WeakReference<AccessibilityNodeInfo> mAccessibilityNodeInfoRef;
+
+
+    /**
+     * @param originalClickableSpanId The id of the span this one replaces
+     */
+    public AccessibilityClickableSpan(int originalClickableSpanId) {
+        mOriginalClickableSpanId = originalClickableSpanId;
+    }
+
+    public AccessibilityClickableSpan(Parcel p) {
+        mOriginalClickableSpanId = p.readInt();
+    }
+
+    @Override
+    public int getSpanTypeId() {
+        return getSpanTypeIdInternal();
+    }
+
+    @Override
+    public int getSpanTypeIdInternal() {
+        return TextUtils.ACCESSIBILITY_CLICKABLE_SPAN;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        writeToParcelInternal(dest, flags);
+    }
+
+    @Override
+    public void writeToParcelInternal(Parcel dest, int flags) {
+        dest.writeInt(mOriginalClickableSpanId);
+    }
+
+    /**
+     * Find the ClickableSpan that matches the one used to create this object.
+     *
+     * @param text The text that contains the original ClickableSpan.
+     * @return The ClickableSpan that matches this object, or {@code null} if no such object
+     * can be found.
+     */
+    public ClickableSpan findClickableSpan(CharSequence text) {
+        if (!(text instanceof Spanned)) {
+            return null;
+        }
+        Spanned sp = (Spanned) text;
+        ClickableSpan[] os = sp.getSpans(0, text.length(), ClickableSpan.class);
+        for (int i = 0; i < os.length; i++) {
+            if (os[i].getId() == mOriginalClickableSpanId) {
+                return os[i];
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Set the accessibilityNodeInfo that this placeholder belongs to. This node is not
+     * included in the parceling logic, and must be set to allow the onClick handler to function.
+     *
+     * @param accessibilityNodeInfo The info this span is part of
+     */
+    public void setAccessibilityNodeInfo(AccessibilityNodeInfo accessibilityNodeInfo) {
+        mAccessibilityNodeInfoRef = new WeakReference<>(accessibilityNodeInfo);
+    }
+
+    /**
+     * Perform the click from an accessibility service. Will not work unless
+     * setAccessibilityNodeInfo is called with a properly initialized node.
+     *
+     * @param unused This argument is required by the superclass but is unused. The real view will
+     * be determined by the AccessibilityNodeInfo.
+     */
+    @Override
+    public void onClick(View unused) {
+        if (mAccessibilityNodeInfoRef == null) {
+            return;
+        }
+        AccessibilityNodeInfo info = mAccessibilityNodeInfoRef.get();
+        if (info == null) {
+            return;
+        }
+        Bundle arguments = new Bundle();
+        arguments.putParcelable(ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN, this);
+
+        info.performAction(R.id.accessibilityActionClickOnClickableSpan, arguments);
+    }
+
+    public static final Parcelable.Creator<AccessibilityClickableSpan> CREATOR =
+            new Parcelable.Creator<AccessibilityClickableSpan>() {
+                @Override
+                public AccessibilityClickableSpan createFromParcel(Parcel parcel) {
+                    return new AccessibilityClickableSpan(parcel);
+                }
+
+                @Override
+                public AccessibilityClickableSpan[] newArray(int size) {
+                    return new AccessibilityClickableSpan[size];
+                }
+            };
+}
diff --git a/core/java/android/text/style/AccessibilityURLSpan.java b/core/java/android/text/style/AccessibilityURLSpan.java
new file mode 100644
index 0000000..0147009
--- /dev/null
+++ b/core/java/android/text/style/AccessibilityURLSpan.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2016 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.text.style;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+/**
+ * URLSpan's onClick method does not work from an accessibility service. This version of it does.
+ * It is used to replace URLSpans in {@link AccessibilityNodeInfo#setText(CharSequence)}
+ * @hide
+ */
+public class AccessibilityURLSpan extends URLSpan implements Parcelable {
+    final AccessibilityClickableSpan mAccessibilityClickableSpan;
+
+    /**
+     * @param spanToReplace The original span
+     */
+    public AccessibilityURLSpan(URLSpan spanToReplace) {
+        super(spanToReplace.getURL());
+        mAccessibilityClickableSpan =
+                new AccessibilityClickableSpan(spanToReplace.getId());
+    }
+
+    public AccessibilityURLSpan(Parcel p) {
+        super(p);
+        mAccessibilityClickableSpan = new AccessibilityClickableSpan(p);
+    }
+
+    @Override
+    public int getSpanTypeId() {
+        return getSpanTypeIdInternal();
+    }
+
+    @Override
+    public int getSpanTypeIdInternal() {
+        return TextUtils.ACCESSIBILITY_URL_SPAN;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        writeToParcelInternal(dest, flags);
+    }
+
+    @Override
+    public void writeToParcelInternal(Parcel dest, int flags) {
+        super.writeToParcelInternal(dest, flags);
+        mAccessibilityClickableSpan.writeToParcel(dest, flags);
+    }
+
+    @Override
+    public void onClick(View unused) {
+        mAccessibilityClickableSpan.onClick(unused);
+    }
+
+    /**
+     * Delegated to AccessibilityClickableSpan
+     * @param accessibilityNodeInfo
+     */
+    public void setAccessibilityNodeInfo(AccessibilityNodeInfo accessibilityNodeInfo) {
+        mAccessibilityClickableSpan.setAccessibilityNodeInfo(accessibilityNodeInfo);
+    }
+}
diff --git a/core/java/android/text/style/ClickableSpan.java b/core/java/android/text/style/ClickableSpan.java
index 989ef54..a183427 100644
--- a/core/java/android/text/style/ClickableSpan.java
+++ b/core/java/android/text/style/ClickableSpan.java
@@ -26,12 +26,15 @@
  * be called.
  */
 public abstract class ClickableSpan extends CharacterStyle implements UpdateAppearance {
+    private static int sIdCounter = 0;
+
+    private int mId = sIdCounter++;
 
     /**
      * Performs the click action associated with this span.
      */
     public abstract void onClick(View widget);
-   
+
     /**
      * Makes the text underlined and in the link color.
      */
@@ -40,4 +43,14 @@
         ds.setColor(ds.linkColor);
         ds.setUnderlineText(true);
     }
+
+    /**
+     * Get the unique ID for this span.
+     *
+     * @return The unique ID.
+     * @hide
+     */
+    public int getId() {
+        return mId;
+    }
 }
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index 99f6c2a9..79d16fb 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -59,7 +59,7 @@
         private Exception mLastWtf;
 
         // Layout of event log entry received from Android logger.
-        //  see system/core/include/log/logger.h
+        //  see system/core/include/log/log.h
         private static final int LENGTH_OFFSET = 0;
         private static final int HEADER_SIZE_OFFSET = 2;
         private static final int PROCESS_OFFSET = 4;
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index c7b1d03..13ee48e 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN;
+
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.Region;
@@ -24,8 +26,12 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Parcelable;
 import android.os.Process;
 import android.os.RemoteException;
+import android.text.TextUtils;
+import android.text.style.AccessibilityClickableSpan;
+import android.text.style.ClickableSpan;
 import android.util.LongSparseArray;
 import android.view.View.AttachInfo;
 import android.view.accessibility.AccessibilityInteractionClient;
@@ -33,6 +39,7 @@
 import android.view.accessibility.AccessibilityNodeProvider;
 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
 
+import com.android.internal.R;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.Predicate;
 
@@ -655,17 +662,23 @@
                 target = mViewRootImpl.mView;
             }
             if (target != null && isShown(target)) {
-                AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
-                if (provider != null) {
-                    if (virtualDescendantId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
-                        succeeded = provider.performAction(virtualDescendantId, action,
-                                arguments);
-                    } else {
-                        succeeded = provider.performAction(AccessibilityNodeProvider.HOST_VIEW_ID,
-                                action, arguments);
+                if (action == R.id.accessibilityActionClickOnClickableSpan) {
+                    // Handle this hidden action separately
+                    succeeded = handleClickableSpanActionUiThread(
+                            target, virtualDescendantId, arguments);
+                } else {
+                    AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
+                    if (provider != null) {
+                        if (virtualDescendantId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
+                            succeeded = provider.performAction(virtualDescendantId, action,
+                                    arguments);
+                        } else {
+                            succeeded = provider.performAction(
+                                    AccessibilityNodeProvider.HOST_VIEW_ID, action, arguments);
+                        }
+                    } else if (virtualDescendantId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
+                        succeeded = target.performAccessibilityAction(action, arguments);
                     }
-                } else if (virtualDescendantId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
-                    succeeded = target.performAccessibilityAction(action, arguments);
                 }
             }
         } finally {
@@ -816,6 +829,37 @@
         return (appScale != 1.0f || (spec != null && !spec.isNop()));
     }
 
+    private boolean handleClickableSpanActionUiThread(
+            View view, int virtualDescendantId, Bundle arguments) {
+        Parcelable span = arguments.getParcelable(ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN);
+        if (!(span instanceof AccessibilityClickableSpan)) {
+            return false;
+        }
+
+        // Find the original ClickableSpan if it's still on the screen
+        AccessibilityNodeInfo infoWithSpan = null;
+        AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
+        if (provider != null) {
+            int idForNode = (virtualDescendantId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID)
+                    ? AccessibilityNodeProvider.HOST_VIEW_ID : virtualDescendantId;
+            infoWithSpan = provider.createAccessibilityNodeInfo(idForNode);
+        } else if (virtualDescendantId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
+            infoWithSpan = view.createAccessibilityNodeInfo();
+        }
+        if (infoWithSpan == null) {
+            return false;
+        }
+
+        // Click on the corresponding span
+        ClickableSpan clickableSpan = ((AccessibilityClickableSpan) span).findClickableSpan(
+                infoWithSpan.getOriginalText());
+        if (clickableSpan != null) {
+            clickableSpan.onClick(view);
+            return true;
+        }
+        return false;
+    }
+
     /**
      * This class encapsulates a prefetching strategy for the accessibility APIs for
      * querying window content. It is responsible to prefetch a batch of
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 3beb00f..b37ea8e 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -282,6 +282,15 @@
      */
     public static final int STATE_DOZE_SUSPEND = 4;
 
+    /**
+     * Display state: The display is on and optimized for VR mode.
+     *
+     * @see #getState
+     * @see android.os.PowerManager#isInteractive
+     * @hide
+     */
+    public static final int STATE_VR = 5;
+
     /* The color mode constants defined below must be kept in sync with the ones in
      * system/graphics.h */
 
@@ -866,7 +875,8 @@
      * Gets the state of the display, such as whether it is on or off.
      *
      * @return The state of the display: one of {@link #STATE_OFF}, {@link #STATE_ON},
-     * {@link #STATE_DOZE}, {@link #STATE_DOZE_SUSPEND}, or {@link #STATE_UNKNOWN}.
+     * {@link #STATE_DOZE}, {@link #STATE_DOZE_SUSPEND}, or
+     * {@link #STATE_UNKNOWN}.
      */
     public int getState() {
         synchronized (this) {
@@ -982,6 +992,8 @@
                 return "DOZE";
             case STATE_DOZE_SUSPEND:
                 return "DOZE_SUSPEND";
+            case STATE_VR:
+                return "VR";
             default:
                 return Integer.toString(state);
         }
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 8611d69..c0ebd2c 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -190,16 +190,6 @@
     void enableSurfaceTrace(in ParcelFileDescriptor fd);
     void disableSurfaceTrace();
 
-    /**
-     * Cancels the window transitions for the given task.
-     */
-    void cancelTaskWindowTransition(int taskId);
-
-    /**
-     * Cancels the thumbnail transitions for the given task.
-     */
-    void cancelTaskThumbnailTransition(int taskId);
-
     // These can only be called with the SET_ORIENTATION permission.
     /**
      * Update the current screen rotation based on the current state of
diff --git a/core/java/android/view/SurfaceHolder.java b/core/java/android/view/SurfaceHolder.java
index a3e8312..2fd2e96 100644
--- a/core/java/android/view/SurfaceHolder.java
+++ b/core/java/android/view/SurfaceHolder.java
@@ -116,9 +116,34 @@
          * size before it has been correctly drawn that way).  This will
          * typically be preceeded by a call to {@link #surfaceChanged}.
          *
+         * As of O, {@link #surfaceRedrawNeededAsync} may be implemented
+         * to provide a non-blocking implementation. If {@link #surfaceRedrawNeededAsync}
+         * is not implemented, then this will be called instead.
+         *
          * @param holder The SurfaceHolder whose surface has changed.
          */
-        public void surfaceRedrawNeeded(SurfaceHolder holder);
+        void surfaceRedrawNeeded(SurfaceHolder holder);
+
+        /**
+         * An alternative to surfaceRedrawNeeded where it is not required to block
+         * until the redraw is complete. You should initiate the redraw, and return,
+         * later invoking drawingFinished when your redraw is complete.
+         *
+         * This can be useful to avoid blocking your main application thread on rendering.
+         *
+         * As of O, if this is implemented {@link #surfaceRedrawNeeded} will not be called.
+         * However it is still recommended to implement {@link #surfaceRedrawNeeded} for
+         * compatibility with older versions of the platform.
+         *
+         * @param holder The SurfaceHolder which needs redrawing.
+         * @param drawingFinished A runnable to signal completion. This may be invoked
+         * from any thread.
+         *
+         */
+        default void surfaceRedrawNeededAsync(SurfaceHolder holder, Runnable drawingFinished) {
+            surfaceRedrawNeeded(holder);
+            drawingFinished.run();
+        }
     }
 
     /**
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index d46910c..018be86 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -33,6 +33,7 @@
 import android.util.Log;
 
 import com.android.internal.view.BaseIWindow;
+import com.android.internal.view.SurfaceCallbackHelper;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -639,21 +640,13 @@
                             if (callbacks == null) {
                                 callbacks = getSurfaceCallbacks();
                             }
-                            for (SurfaceHolder.Callback c : callbacks) {
-                                if (c instanceof SurfaceHolder.Callback2) {
-                                    ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
-                                            mSurfaceHolder);
-                                }
-                            }
+                            SurfaceCallbackHelper sch =
+                                    new SurfaceCallbackHelper(mSession, mWindow);
+                            sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
                         }
                     }
                 } finally {
                     mIsCreating = false;
-                    if (redrawNeeded) {
-                        if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
-                                + "finishedDrawing");
-                        mSession.finishDrawing(mWindow);
-                    }
                     mSession.performDeferredDestroy(mWindow);
                 }
             } catch (RemoteException ex) {
@@ -876,7 +869,6 @@
     }
 
     private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
-
         private static final String LOG_TAG = "SurfaceHolder";
 
         @Override
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0b1dfa2..aedd0df 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -39,6 +39,7 @@
 import android.annotation.Size;
 import android.annotation.TestApi;
 import android.annotation.UiThread;
+import android.app.Application.OnProvideAssistDataListener;
 import android.content.ClipData;
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -103,6 +104,9 @@
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Transformation;
+import android.view.autofill.AutoFillType;
+import android.view.autofill.AutoFillValue;
+import android.view.autofill.VirtualViewDelegate;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
@@ -4025,18 +4029,34 @@
 
 
     /**
-     * <p>When setting a {@link android.app.assist.AssistStructure}, its nodes should not contain
-     * PII (Personally Identifiable Information).
+     * Set when a request was made to decide if views in an {@link android.app.Activity} can be
+     * auto-filled by an {@link android.service.autofill.AutoFillService}.
+     *
+     * <p>Since this request is made without a explicit user consent, the resulting
+     * {@link android.app.assist.AssistStructure} should not contain any PII
+     * (Personally Identifiable Information).
+     *
+     * <p>Examples:
+     * <ul>
+     * <li>{@link android.widget.TextView} texts should only be included when they were set by
+     * static resources.
+     * <li>{@link android.webkit.WebView} virtual children should be restricted to a subset of
+     * input fields and tags (like {@code id}).
+     * </ul>
      */
-    // TODO(b/33197203) (b/33269702): improve documentation: mention all cases, show examples, etc.
-    public static final int ASSIST_FLAG_SANITIZED_TEXT = 0x1;
+    // TODO(b/33197203) (b/34078930): improve documentation: mention all cases, show examples, etc.
+    // In particular, be more specific about webview restrictions
+    public static final int AUTO_FILL_FLAG_TYPE_FILL = 0x1;
 
     /**
-     * <p>When setting a {@link android.app.assist.AssistStructure}, its nodes should contain all
-     * type of data, even sensitive PII (Personally Identifiable Information) like passwords or
-     * credit card numbers.
+     * Set when the user explicitly asked a {@link android.service.autofill.AutoFillService} to save
+     * the value of the {@link View}s in an {@link android.app.Activity}.
+     *
+     * <p>The resulting {@link android.app.assist.AssistStructure} can contain any kind of PII
+     * (Personally Identifiable Information). For example, the text of password fields should be
+     * included since that's what's typically saved.
      */
-    public static final int ASSIST_FLAG_NON_SANITIZED_TEXT = 0x2;
+    public static final int AUTO_FILL_FLAG_TYPE_SAVE = 0x2;
 
     /**
      * Set to true when drawing cache is enabled and cannot be created.
@@ -6873,35 +6893,32 @@
      * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}.
      * @param structure Fill in with structured view data.  The default implementation
      * fills in all data that can be inferred from the view itself.
-     *
-     * @deprecated As of API O sub-classes should override
-     * {@link #onProvideStructure(ViewStructure, int)} instead.
      */
-    // TODO(b/33197203): set proper API above
-    @Deprecated
     public void onProvideStructure(ViewStructure structure) {
-        onProvideStructure(structure, 0);
+        onProvideStructureForAssistOrAutoFill(structure, 0);
     }
 
     /**
-     * Called when assist structure is being retrieved from a view as part of
-     * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} or as part
-     * of an auto-fill request.
-     *
-     * <p>The default implementation fills in all data that can be inferred from the view itself.
+     * Called when assist structure is being retrieved from a view as part of an auto-fill request.
      *
      * <p>The structure must be filled according to the request type, which is set in the
      * {@code flags} parameter - see the documentation on each flag for more details.
      *
-     * @param structure Fill in with structured view data. The default implementation
+     * @param structure Fill in with structured view data.  The default implementation
      * fills in all data that can be inferred from the view itself.
-     * @param flags optional flags (see {@link #ASSIST_FLAG_SANITIZED_TEXT} and
-     * {@link #ASSIST_FLAG_NON_SANITIZED_TEXT} for more info).
+     * @param flags optional flags (see {@link #AUTO_FILL_FLAG_TYPE_FILL} and
+     * {@link #AUTO_FILL_FLAG_TYPE_SAVE} for more info).
      */
-    public void onProvideStructure(ViewStructure structure, int flags) {
+    public void onProvideAutoFillStructure(ViewStructure structure, int flags) {
+        onProvideStructureForAssistOrAutoFill(structure, flags);
+    }
+
+    private void onProvideStructureForAssistOrAutoFill(ViewStructure structure, int flags) {
+        // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well,
+        // this method should take a boolean with the type of request.
         boolean forAutoFill = (flags
-                & (View.ASSIST_FLAG_SANITIZED_TEXT
-                        | View.ASSIST_FLAG_NON_SANITIZED_TEXT)) != 0;
+                & (View.AUTO_FILL_FLAG_TYPE_FILL
+                        | View.AUTO_FILL_FLAG_TYPE_SAVE)) != 0;
         final int id = mID;
         if (id > 0 && (id&0xff000000) != 0 && (id&0x00ff0000) != 0
                 && (id&0x0000ffff) != 0) {
@@ -6923,6 +6940,8 @@
             // The auto-fill id needs to be unique, but its value doesn't matter, so it's better to
             // reuse the accessibility id to save space.
             structure.setAutoFillId(getAccessibilityViewId());
+
+            structure.setAutoFillType(getAutoFillType());
         }
 
         structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop);
@@ -6973,40 +6992,33 @@
      * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the
      * view's virtual accessibility nodes, if any.  You can override this for a more
      * optimal implementation providing this data.
-     *
-     * @deprecated As of API O, sub-classes should override
-     * {@link #onProvideVirtualStructure(ViewStructure, int)} instead.
      */
-    // TODO(b/33197203): set proper API above
-    @Deprecated
     public void onProvideVirtualStructure(ViewStructure structure) {
-        onProvideVirtualStructure(structure, 0);
+        onProvideVirtualStructureForAssistOrAutoFill(structure, 0);
     }
 
     /**
-     * Called when assist structure is being retrieved from a view as part of
-     * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} or as part
-     * of an auto-fill request to generate additional virtual structure under this view.
+     * Called when assist structure is being retrieved from a view as part of an auto-fill request
+     * to generate additional virtual structure under this view.
      *
      * <p>The defaullt implementation uses {@link #getAccessibilityNodeProvider()} to try to
-     * generate this from the view's virtual accessibility nodes, if any.  You can override this
+     * generate this from the view's virtual accessibility nodes, if any. You can override this
      * for a more optimal implementation providing this data.
      *
      * <p>The structure must be filled according to the request type, which is set in the
      * {@code flags} parameter - see the documentation on each flag for more details.
      *
      * @param structure Fill in with structured view data.
-     * @param flags optional flags (see {@link #ASSIST_FLAG_SANITIZED_TEXT} and
-     * {@link #ASSIST_FLAG_NON_SANITIZED_TEXT} for more info).
+     * @param flags optional flags (see {@link #AUTO_FILL_FLAG_TYPE_FILL} and
+     * {@link #AUTO_FILL_FLAG_TYPE_SAVE} for more info).
      */
-    public void onProvideVirtualStructure(ViewStructure structure, int flags) {
-        boolean sanitize = (flags & View.ASSIST_FLAG_SANITIZED_TEXT) != 0;
+    public void onProvideAutoFillVirtualStructure(ViewStructure structure, int flags) {
+        onProvideVirtualStructureForAssistOrAutoFill(structure, flags);
+    }
 
-        if (sanitize) {
-            // TODO(b/33197203): change populateVirtualStructure so it sanitizes data in this case.
-            return;
-        }
-
+    private void onProvideVirtualStructureForAssistOrAutoFill(ViewStructure structure, int flags) {
+        // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well,
+        // this method should take a boolean with the type of request.
         AccessibilityNodeProvider provider = getAccessibilityNodeProvider();
         if (provider != null) {
             AccessibilityNodeInfo info = createAccessibilityNodeInfo();
@@ -7017,8 +7029,66 @@
         }
     }
 
+    /**
+     * Gets the {@link VirtualViewDelegate} responsible for auto-filling the virtual children of
+     * this view.
+     *
+     * <p>By default returns {@code null} but should be overridden when view provides a virtual
+     * hierachy on {@link OnProvideAssistDataListener} that takes flags used by the AutoFill
+     * Framework (such as {@link #AUTO_FILL_FLAG_TYPE_FILL} and
+     * {@link #AUTO_FILL_FLAG_TYPE_SAVE}).
+     */
+    @Nullable
+    public VirtualViewDelegate getAutoFillVirtualViewDelegate(
+            @SuppressWarnings("unused") VirtualViewDelegate.Callback callback) {
+        return null;
+    }
+
+    /**
+     * Automatically fills the content of this view with the {@code value}.
+     *
+     * <p>By default does nothing, but views should override it (and {@link #getAutoFillType()} to
+     * support the AutoFill Framework.
+     *
+     * <p>Typically, it is implemented by:
+     *
+     * <ol>
+     * <li>Call the proper getter method on {@link AutoFillValue} to fetch the actual value.
+     * <li>Pass the actual value to the equivalent setter in the view.
+     * <ol>
+     *
+     * <p>For example, a text-field view would call:
+     *
+     * <pre class="prettyprint">
+     * CharSequence text = value.getTextValue();
+     * if (text != null) {
+     *     setText(text);
+     * }
+     * </pre>
+     */
+    public void autoFill(@SuppressWarnings("unused") AutoFillValue value) {
+    }
+
+    /**
+     * Describes the auto-fill type that should be used on callas to
+     * {@link #autoFill(AutoFillValue)} and
+     * {@link VirtualViewDelegate#autoFill(int, AutoFillValue)}.
+     *
+     * <p>By default returns {@code null}, but views should override it (and
+     * {@link #autoFill(AutoFillValue)} to support the AutoFill Framework.
+     */
+    @Nullable
+    public AutoFillType getAutoFillType() {
+        return null;
+    }
+
     private void populateVirtualStructure(ViewStructure structure,
             AccessibilityNodeProvider provider, AccessibilityNodeInfo info, int flags) {
+        // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well,
+        // this method should take a boolean with the type of request.
+
+        final boolean sanitized = (flags & View.AUTO_FILL_FLAG_TYPE_FILL) != 0;
+
         structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()),
                 null, null, null);
         Rect rect = structure.getTempRect();
@@ -7056,7 +7126,10 @@
         CharSequence cname = info.getClassName();
         structure.setClassName(cname != null ? cname.toString() : null);
         structure.setContentDescription(info.getContentDescription());
-        if (info.getText() != null || info.getError() != null) {
+        if (!sanitized && (info.getText() != null || info.getError() != null)) {
+            // TODO(b/33197203) (b/33269702): when sanitized, try to use the Accessibility API to
+            // just set sanitized values (like text coming from resource files), rather than not
+            // setting it at all.
             structure.setText(info.getText(), info.getTextSelectionStart(),
                     info.getTextSelectionEnd());
         }
@@ -7077,14 +7150,9 @@
      * Dispatch creation of {@link ViewStructure} down the hierarchy.  The default
      * implementation calls {@link #onProvideStructure} and
      * {@link #onProvideVirtualStructure}.
-     *
-     * @deprecated As of API O,  sub-classes should override
-     * {@link #dispatchProvideStructure(ViewStructure, int)} instead.
      */
-    // TODO(b/33197203): set proper API above
-    @Deprecated
     public void dispatchProvideStructure(ViewStructure structure) {
-        dispatchProvideStructure(structure, 0);
+        dispatchProvideStructureForAssistOrAutoFill(structure, 0);
     }
 
     /**
@@ -7093,22 +7161,33 @@
      * <p>The structure must be filled according to the request type, which is set in the
      * {@code flags} parameter - see the documentation on each flag for more details.
      *
-     * <p>The default implementation calls {@link #onProvideStructure(ViewStructure, int)} and
-     * {@link #onProvideVirtualStructure(ViewStructure, int)}.
+     * <p>The default implementation calls {@link #onProvideAutoFillStructure(ViewStructure, int)}
+     * and {@link #onProvideAutoFillVirtualStructure(ViewStructure, int)}.
      *
      * @param structure Fill in with structured view data.
-     * @param flags optional flags (see {@link #ASSIST_FLAG_SANITIZED_TEXT} and
-     * {@link #ASSIST_FLAG_NON_SANITIZED_TEXT} for more info).
+     * @param flags optional flags (see {@link #AUTO_FILL_FLAG_TYPE_FILL} and
+     * {@link #AUTO_FILL_FLAG_TYPE_SAVE} for more info).
      */
-    public void dispatchProvideStructure(ViewStructure structure, int flags) {
+    public void dispatchProvideAutoFillStructure(ViewStructure structure, int flags) {
+        dispatchProvideStructureForAssistOrAutoFill(structure, flags);
+    }
+
+    private void dispatchProvideStructureForAssistOrAutoFill(ViewStructure structure, int flags) {
+        // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well,
+        // this method should take a boolean with the type of request.
         boolean forAutoFill = (flags
-                & (View.ASSIST_FLAG_SANITIZED_TEXT
-                        | View.ASSIST_FLAG_NON_SANITIZED_TEXT)) != 0;
+                & (View.AUTO_FILL_FLAG_TYPE_FILL
+                        | View.AUTO_FILL_FLAG_TYPE_SAVE)) != 0;
 
         boolean blocked = forAutoFill ? isAutoFillBlocked() : isAssistBlocked();
         if (!blocked) {
-            onProvideStructure(structure, flags);
-            onProvideVirtualStructure(structure, flags);
+            if (forAutoFill) {
+                onProvideAutoFillStructure(structure, flags);
+                onProvideAutoFillVirtualStructure(structure, flags);
+            } else {
+                onProvideStructure(structure);
+                onProvideVirtualStructure(structure);
+            }
         } else {
             structure.setClassName(getAccessibilityClassName().toString());
             structure.setAssistBlocked(true);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 56501ec..1f1af4b 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3156,18 +3156,34 @@
     }
 
     /**
+     * Dispatch creation of {@link ViewStructure} down the hierarchy.  This implementation
+     * adds in all child views of the view group, in addition to calling the default View
+     * implementation.
+     */
+    @Override
+    public void dispatchProvideStructure(ViewStructure structure) {
+        super.dispatchProvideStructure(structure);
+        dispatchProvideStructureForAssistOrAutoFill(structure, 0);
+    }
+
+    /**
      * {@inheritDoc}
      *
      * <p>This implementation adds in all child views of the view group, in addition to calling the
      * default {@link View} implementation.
      */
     @Override
-    public void dispatchProvideStructure(ViewStructure structure, int flags) {
-        super.dispatchProvideStructure(structure, flags);
+    public void dispatchProvideAutoFillStructure(ViewStructure structure, int flags) {
+        super.dispatchProvideAutoFillStructure(structure, flags);
+        dispatchProvideStructureForAssistOrAutoFill(structure, flags);
+    }
 
+    private void dispatchProvideStructureForAssistOrAutoFill(ViewStructure structure, int flags) {
+        // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well,
+        // this method should take a boolean with the type of request.
         boolean forAutoFill = (flags
-                & (View.ASSIST_FLAG_SANITIZED_TEXT
-                        | View.ASSIST_FLAG_NON_SANITIZED_TEXT)) != 0;
+                & (View.AUTO_FILL_FLAG_TYPE_FILL
+                        | View.AUTO_FILL_FLAG_TYPE_SAVE)) != 0;
 
         boolean blocked = forAutoFill ? isAutoFillBlocked() : isAssistBlocked();
 
@@ -3233,12 +3249,11 @@
                                 preorderedList, children, childIndex);
                         final ViewStructure cstructure = structure.newChild(i);
 
-                        // Must explicitly check which recursive method to call because child might
-                        // not be overriding the new, flags-based version
-                        if (flags == 0) {
-                            child.dispatchProvideStructure(cstructure);
+                        // Must explicitly check which recursive method to call.
+                        if (forAutoFill) {
+                            child.dispatchProvideAutoFillStructure(cstructure, flags);
                         } else {
-                            child.dispatchProvideStructure(cstructure, flags);
+                            child.dispatchProvideStructure(cstructure);
                         }
                     }
                     if (preorderedList != null) preorderedList.clear();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index d6db634..b42f769 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -96,6 +96,7 @@
 import com.android.internal.policy.PhoneFallbackEventHandler;
 import com.android.internal.view.BaseSurfaceHolder;
 import com.android.internal.view.RootViewSurfaceTaker;
+import com.android.internal.view.SurfaceCallbackHelper;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -528,11 +529,17 @@
      */
     public void notifyChildRebuilt() {
         if (mView instanceof RootViewSurfaceTaker) {
+            if (mSurfaceHolderCallback != null) {
+                mSurfaceHolder.removeCallback(mSurfaceHolderCallback);
+            }
+
             mSurfaceHolderCallback =
                 ((RootViewSurfaceTaker)mView).willYouTakeTheSurface();
+
             if (mSurfaceHolderCallback != null) {
                 mSurfaceHolder = new TakenSurfaceHolder();
                 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
+                mSurfaceHolder.addCallback(mSurfaceHolderCallback);
             } else {
                 mSurfaceHolder = null;
             }
@@ -581,6 +588,7 @@
                     if (mSurfaceHolderCallback != null) {
                         mSurfaceHolder = new TakenSurfaceHolder();
                         mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
+                        mSurfaceHolder.addCallback(mSurfaceHolderCallback);
                     }
                 }
 
@@ -1957,7 +1965,6 @@
                         mSurfaceHolder.ungetCallbacks();
 
                         mIsCreating = true;
-                        mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder);
                         SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
                         if (callbacks != null) {
                             for (SurfaceHolder.Callback c : callbacks) {
@@ -1967,8 +1974,6 @@
                         surfaceChanged = true;
                     }
                     if (surfaceChanged || surfaceGenerationId != mSurface.getGenerationId()) {
-                        mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
-                                lp.format, mWidth, mHeight);
                         SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
                         if (callbacks != null) {
                             for (SurfaceHolder.Callback c : callbacks) {
@@ -1981,7 +1986,6 @@
                 } else if (hadSurface) {
                     mSurfaceHolder.ungetCallbacks();
                     SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
-                    mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
                     if (callbacks != null) {
                         for (SurfaceHolder.Callback c : callbacks) {
                             c.surfaceDestroyed(mSurfaceHolder);
@@ -2646,21 +2650,18 @@
             if (LOCAL_LOGV) {
                 Log.v(mTag, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
             }
+
             if (mSurfaceHolder != null && mSurface.isValid()) {
-                mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
+                SurfaceCallbackHelper sch = new SurfaceCallbackHelper(mWindowSession, mWindow);
                 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
-                if (callbacks != null) {
-                    for (SurfaceHolder.Callback c : callbacks) {
-                        if (c instanceof SurfaceHolder.Callback2) {
-                            ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(mSurfaceHolder);
-                        }
-                    }
+
+                sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
+            } else {
+                try {
+                    mWindowSession.finishDrawing(mWindow);
+                } catch (RemoteException e) {
                 }
             }
-            try {
-                mWindowSession.finishDrawing(mWindow);
-            } catch (RemoteException e) {
-            }
         }
     }
 
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index e9ff9d0..839e11c 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -19,6 +19,10 @@
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.os.Bundle;
+import android.view.autofill.AutoFillId;
+import android.view.autofill.AutoFillType;
+import android.view.autofill.AutoFillValue;
+import android.view.autofill.VirtualViewDelegate;
 
 /**
  * Container for storing additional per-view data generated by {@link View#onProvideStructure
@@ -258,6 +262,12 @@
     public abstract ViewStructure newChild(int index);
 
     /**
+     * Like {@link #newChild(int)}, but providing a {@code virtualId} to the child so it can be
+     * auto-filled by {@link VirtualViewDelegate#autoFill(int, AutoFillValue)}.
+     */
+    public abstract ViewStructure newChild(int index, int virtualId);
+
+    /**
      * Like {@link #newChild}, but allows the caller to asynchronously populate the returned
      * child.  It can transfer the returned {@link ViewStructure} to another thread for it
      * to build its content (and children etc).  Once done, some thread must call
@@ -268,6 +278,17 @@
     public abstract ViewStructure asyncNewChild(int index);
 
     /**
+     * Like {@link #asyncNewChild(int)}, but providing a {@code virtualId} to the child so it can be
+     * auto-filled by {@link VirtualViewDelegate#autoFill(int, AutoFillValue)}.
+     */
+    public abstract ViewStructure asyncNewChild(int index, int virtualId);
+
+    /**
+     * Sets the {@link AutoFillType} that can be used to auto-fill this node.
+     */
+    public abstract void setAutoFillType(AutoFillType info);
+
+    /**
      * Call when done populating a {@link ViewStructure} returned by
      * {@link #asyncNewChild}.
      */
@@ -277,5 +298,8 @@
     public abstract Rect getTempRect();
 
     /** @hide */
-    public abstract void setAutoFillId(int autoFillId);
+    public abstract void setAutoFillId(int viewId);
+
+    /** @hide */
+    public abstract AutoFillId getAutoFillId();
 }
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index caa09cc..dd85256 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -437,6 +437,15 @@
     }
 
     /**
+     * Holds the contents of a starting window. {@link #addSplashScreen} needs to wrap the
+     * contents of the starting window into an class implementing this interface, which then will be
+     * held by WM and passed into {@link #removeSplashScreen} when the starting window is no
+     * longer needed.
+     */
+    interface StartingSurface {
+    }
+
+    /**
      * Interface for calling back in to the window manager that is private
      * between it and the policy.
      */
@@ -738,17 +747,17 @@
      *        context to for resources.
      *
      * @return Optionally you can return the View that was used to create the
-     *         window, for easy removal in removeStartingWindow.
+     *         window, for easy removal in removeSplashScreen.
      *
-     * @see #removeStartingWindow
+     * @see #removeSplashScreen
      */
-    public View addStartingWindow(IBinder appToken, String packageName,
-            int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel,
-            int labelRes, int icon, int logo, int windowFlags, Configuration overrideConfig);
+    public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme,
+            CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon,
+            int logo, int windowFlags, Configuration overrideConfig);
 
     /**
      * Called when the first window of an application has been displayed, while
-     * {@link #addStartingWindow} has created a temporary initial window for
+     * {@link #addSplashScreen} has created a temporary initial window for
      * that application.  You should at this point remove the window from the
      * window manager.  This is called without the window manager locked so
      * that you can call back into it.
@@ -759,11 +768,11 @@
      * even if you previously returned one.
      *
      * @param appToken Token of the application that has started.
-     * @param window Window View that was returned by createStartingWindow.
+     * @param surface Surface that was returned by {@link #addSplashScreen}.
      *
-     * @see #addStartingWindow
+     * @see #addSplashScreen
      */
-    public void removeStartingWindow(IBinder appToken, View window);
+    public void removeSplashScreen(IBinder appToken, StartingSurface surface);
 
     /**
      * Prepare for a window being added to the window manager.  You can throw an
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 9127861..91468da 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -25,7 +25,13 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.InputType;
+import android.text.Spannable;
+import android.text.Spanned;
 import android.text.TextUtils;
+import android.text.style.AccessibilityClickableSpan;
+import android.text.style.AccessibilityURLSpan;
+import android.text.style.ClickableSpan;
+import android.text.style.URLSpan;
 import android.util.ArraySet;
 import android.util.LongArray;
 import android.util.Pools.SynchronizedPool;
@@ -464,6 +470,14 @@
     public static final String ACTION_ARGUMENT_PROGRESS_VALUE =
             "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
 
+    /**
+     * Argument to pass the {@link AccessibilityClickableSpan}.
+     * For use with R.id.accessibilityActionClickOnClickableSpan
+     * @hide
+     */
+    public static final String ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN =
+            "android.view.accessibility.action.ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN";
+
     // Focus types
 
     /**
@@ -628,6 +642,8 @@
 
     private CharSequence mPackageName;
     private CharSequence mClassName;
+    // Hidden, unparceled value used to hold the original value passed to setText
+    private CharSequence mOriginalText;
     private CharSequence mText;
     private CharSequence mError;
     private CharSequence mContentDescription;
@@ -2213,14 +2229,49 @@
 
     /**
      * Gets the text of this node.
+     * <p>
+     *   <strong>Note:</strong> If the text contains {@link ClickableSpan}s or {@link URLSpan}s,
+     *   these spans will have been replaced with ones whose {@link ClickableSpan#onClick(View)}
+     *   can be called from an {@link AccessibilityService}. When called from a service, the
+     *   {@link View} argument is ignored and the corresponding span will be found on the view that
+     *   this {@code AccessibilityNodeInfo} represents and called with that view as its argument.
+     *   <p>
+     *   This treatment of {@link ClickableSpan}s means that the text returned from this method may
+     *   different slightly one passed to {@link #setText(CharSequence)}, although they will be
+     *   equivalent according to {@link TextUtils#equals(CharSequence, CharSequence)}. The
+     *   {@link ClickableSpan#onClick(View)} of any spans, however, will generally not work outside
+     *   of an accessibility service.
+     * </p>
      *
      * @return The text.
      */
     public CharSequence getText() {
+        // Attach this node to any spans that need it
+        if (mText instanceof Spanned) {
+            Spanned spanned = (Spanned) mText;
+            AccessibilityClickableSpan[] clickableSpans =
+                    spanned.getSpans(0, mText.length(), AccessibilityClickableSpan.class);
+            for (int i = 0; i < clickableSpans.length; i++) {
+                clickableSpans[i].setAccessibilityNodeInfo(this);
+            }
+            AccessibilityURLSpan[] urlSpans =
+                    spanned.getSpans(0, mText.length(), AccessibilityURLSpan.class);
+            for (int i = 0; i < urlSpans.length; i++) {
+                urlSpans[i].setAccessibilityNodeInfo(this);
+            }
+        }
         return mText;
     }
 
     /**
+     * Get the text passed to setText before any changes to the spans.
+     * @hide
+     */
+    public CharSequence getOriginalText() {
+        return mOriginalText;
+    }
+
+    /**
      * Sets the text of this node.
      * <p>
      *   <strong>Note:</strong> Cannot be called from an
@@ -2234,6 +2285,34 @@
      */
     public void setText(CharSequence text) {
         enforceNotSealed();
+        mOriginalText = text;
+        // Replace any ClickableSpans in mText with placeholders
+        if (text instanceof Spanned) {
+            ClickableSpan[] spans =
+                    ((Spanned) text).getSpans(0, text.length(), ClickableSpan.class);
+            if (spans.length > 0) {
+                Spannable spannable = Spannable.Factory.getInstance().newSpannable(text);
+                for (int i = 0; i < spans.length; i++) {
+                    ClickableSpan span = spans[i];
+                    if ((span instanceof AccessibilityClickableSpan)
+                            || (span instanceof AccessibilityURLSpan)) {
+                        // We've already done enough
+                        break;
+                    }
+                    int spanToReplaceStart = spannable.getSpanStart(span);
+                    int spanToReplaceEnd = spannable.getSpanEnd(span);
+                    int spanToReplaceFlags = spannable.getSpanFlags(span);
+                    spannable.removeSpan(span);
+                    ClickableSpan replacementSpan = (span instanceof URLSpan)
+                            ? new AccessibilityURLSpan((URLSpan) span)
+                            : new AccessibilityClickableSpan(span.getId());
+                    spannable.setSpan(replacementSpan, spanToReplaceStart, spanToReplaceEnd,
+                            spanToReplaceFlags);
+                }
+                mText = spannable;
+                return;
+            }
+        }
         mText = (text == null) ? null : text.subSequence(0, text.length());
     }
 
diff --git a/core/java/android/view/animation/AnimationSet.java b/core/java/android/view/animation/AnimationSet.java
index 09d4dfc..767024e 100644
--- a/core/java/android/view/animation/AnimationSet.java
+++ b/core/java/android/view/animation/AnimationSet.java
@@ -237,7 +237,7 @@
                 mDuration = a.getStartOffset() + a.getDuration();
                 mLastEnd = mStartOffset + mDuration;
             } else {
-                mLastEnd = Math.max(mLastEnd, a.getStartOffset() + a.getDuration());
+                mLastEnd = Math.max(mLastEnd, mStartOffset + a.getStartOffset() + a.getDuration());
                 mDuration = mLastEnd - mStartOffset;
             }
         }
diff --git a/core/java/android/service/autofill/IAutoFillCallback.aidl b/core/java/android/view/autofill/AutoFillId.aidl
similarity index 63%
copy from core/java/android/service/autofill/IAutoFillCallback.aidl
copy to core/java/android/view/autofill/AutoFillId.aidl
index d6d4f39..56f0338 100644
--- a/core/java/android/service/autofill/IAutoFillCallback.aidl
+++ b/core/java/android/view/autofill/AutoFillId.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
+/**
+ * Copyright (c) 2017, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,14 +14,6 @@
  * limitations under the License.
  */
 
-package android.service.autofill;
+package android.view.autofill;
 
-import java.util.List;
-
-/**
- * @hide
- */
-oneway interface IAutoFillCallback {
-    void autofill(in List values);
-    void showError(String message);
-}
+parcelable AutoFillId;
\ No newline at end of file
diff --git a/core/java/android/view/autofill/AutoFillId.java b/core/java/android/view/autofill/AutoFillId.java
new file mode 100644
index 0000000..b7b694d
--- /dev/null
+++ b/core/java/android/view/autofill/AutoFillId.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view.autofill;
+
+import static android.view.autofill.Helper.DEBUG;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A unique identifier for an auto-fill node inside an {@link android.app.Activity}.
+ */
+public final class AutoFillId implements Parcelable {
+
+    private int mViewId;
+    private boolean mVirtual;
+    private int mVirtualId;
+
+    /** @hide */
+    public AutoFillId(int id) {
+        mVirtual = false;
+        mViewId = id;
+    }
+
+    /** @hide */
+    public AutoFillId(AutoFillId parent, int virtualChildId) {
+        mVirtual = true;
+        mViewId = parent.mViewId;
+        mVirtualId = virtualChildId;
+    }
+
+    /** @hide */
+    public int getViewId() {
+        return mViewId;
+    }
+
+    /** @hide */
+    public int getVirtualChildId() {
+        return mVirtualId;
+    }
+
+    /** @hide */
+    public boolean isVirtual() {
+        return mVirtual;
+    }
+
+    /////////////////////////////////
+    //  Object "contract" methods. //
+    /////////////////////////////////
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + mViewId;
+        result = prime * result + mVirtualId;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        final AutoFillId other = (AutoFillId) obj;
+        if (mViewId != other.mViewId) return false;
+        if (mVirtualId != other.mVirtualId) return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        if (!DEBUG) return super.toString();
+
+        final StringBuilder builder = new StringBuilder("FieldId [viewId=").append(mViewId);
+        if (mVirtual) {
+            builder.append(", virtualId=").append(mVirtualId);
+        }
+        return builder.append(']').toString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeInt(mViewId);
+        parcel.writeInt(mVirtual ? 1 : 0);
+        parcel.writeInt(mVirtualId);
+    }
+
+    private AutoFillId(Parcel parcel) {
+        mViewId = parcel.readInt();
+        mVirtual = parcel.readInt() == 1;
+        mVirtualId = parcel.readInt();
+    }
+
+    public static final Parcelable.Creator<AutoFillId> CREATOR =
+            new Parcelable.Creator<AutoFillId>() {
+        @Override
+        public AutoFillId createFromParcel(Parcel source) {
+            return new AutoFillId(source);
+        }
+
+        @Override
+        public AutoFillId[] newArray(int size) {
+            return new AutoFillId[size];
+        }
+    };
+}
diff --git a/core/java/android/service/autofill/IAutoFillCallback.aidl b/core/java/android/view/autofill/AutoFillType.aidl
similarity index 63%
copy from core/java/android/service/autofill/IAutoFillCallback.aidl
copy to core/java/android/view/autofill/AutoFillType.aidl
index d6d4f39..a63d7c5 100644
--- a/core/java/android/service/autofill/IAutoFillCallback.aidl
+++ b/core/java/android/view/autofill/AutoFillType.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
+/**
+ * Copyright (c) 2016, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,14 +14,6 @@
  * limitations under the License.
  */
 
-package android.service.autofill;
+package android.view.autofill;
 
-import java.util.List;
-
-/**
- * @hide
- */
-oneway interface IAutoFillCallback {
-    void autofill(in List values);
-    void showError(String message);
-}
+parcelable AutoFillType;
\ No newline at end of file
diff --git a/core/java/android/view/autofill/AutoFillType.java b/core/java/android/view/autofill/AutoFillType.java
new file mode 100644
index 0000000..017f7f8
--- /dev/null
+++ b/core/java/android/view/autofill/AutoFillType.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.autofill;
+
+import static android.view.autofill.Helper.DEBUG;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * Defines the type of a object that can be used to auto-fill a {@link View} so the
+ * {@link android.service.autofill.AutoFillService} can use the proper {@link AutoFillValue} to
+ * fill it.
+ *
+ * <p>Some {@link AutoFillType}s can have an optional {@code sub-type}: the
+ * main {@code type} defines the view's UI control category (like a text field), while the optional
+ * {@code sub-type} define its semantics (like a postal address).
+ */
+public final class AutoFillType implements Parcelable {
+
+    // Cached instance for types that don't have subtype; it uses the "lazy initialization holder
+    // class idiom" (Effective Java, Item 71) to avoid memory utilization when auto-fill is not
+    // enabled.
+    private static class DefaultTypesHolder {
+        static final AutoFillType TOGGLE = new AutoFillType(TYPE_TOGGLE, 0);
+        static final AutoFillType LIST = new AutoFillType(TYPE_LIST, 0);
+    }
+
+    private static final int TYPE_TEXT = 1;
+    private static final int TYPE_TOGGLE = 2;
+    // TODO(b/33197203): make sure it works with Spinners and/or add a new type for them
+    // (since they're often used for credit card selection)
+    private static final int TYPE_LIST = 3;
+
+    // TODO(b/33197203): add others, like date picker? That would be trick, because they're set as:
+    // updateDate(int year, int month, int dayOfMonth)
+    // So, we would have to either use a long representing the Date.time(), or a custom long
+    // representing:
+    // year * 10000 + month * 100 + day
+    // Then a custom getDatePickerValue(Bundle) that returns an immutable object with these 3 fields
+
+    private final int mType;
+    private final int mSubType;
+
+    private AutoFillType(int type, int subType) {
+        mType = type;
+        mSubType = subType;
+    }
+
+    /**
+     * Checks if this is a type for a text field, which is filled by a {@link CharSequence}.
+     *
+     * <p>{@link AutoFillValue} instances for auto-filling a {@link View} can be obtained through
+     * {@link AutoFillValue#forText(CharSequence)}, and the value of a bundle passed to auto-fill a
+     * {@link View} can be fetched through {@link AutoFillValue#getTextValue()}.
+     *
+     * <p>Sub-type for this type is the value defined by {@link TextView#getInputType()}.
+     */
+    public boolean isText() {
+        return mType == TYPE_TEXT;
+    }
+
+    /**
+     * Checks if this is a a type for a togglable field, which is filled by a {@code boolean}.
+     *
+     * <p>{@link AutoFillValue} instances for auto-filling a {@link View} can be obtained through
+     * {@link AutoFillValue#forToggle(boolean)}, and the value of a bundle passed to auto-fill a
+     * {@link View} can be fetched through {@link AutoFillValue#getToggleValue()}.
+     *
+     * <p>This type has no sub-types.
+     */
+    public boolean isToggle() {
+        return mType == TYPE_TOGGLE;
+    }
+
+    /**
+     * Checks if this is a type for a selection list field, which is filled by a {@code integer}
+     * representing the element index inside the list (starting at {@code 0}.
+     *
+     * <p>{@link AutoFillValue} instances for auto-filling a {@link View} can be obtained through
+     * {@link AutoFillValue#forList(int)}, and the value of a bundle passed to auto-fill a
+     * {@link View} can be fetched through {@link AutoFillValue#getListValue()}.
+     *
+     * <p>This type has no sub-types.
+     */
+    public boolean isList() {
+        return mType == TYPE_LIST;
+    }
+
+
+    /**
+     * Gets the optional sub-type, representing the {@link View}'s semantic.
+     *
+     * @return {@code 0} if type does not support sub-types.
+     */
+    public int getSubType() {
+        return mSubType;
+    }
+
+    /////////////////////////////////////
+    //  Object "contract" methods. //
+    /////////////////////////////////////
+
+    @Override
+    public String toString() {
+        if (!DEBUG) return super.toString();
+
+        return "AutoFillType [type=" + mType + ", subType=" + mSubType + "]";
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + mSubType;
+        result = prime * result + mType;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        final AutoFillType other = (AutoFillType) obj;
+        if (mSubType != other.mSubType) return false;
+        if (mType != other.mType) return false;
+        return true;
+    }
+
+    /////////////////////////////////////
+    //  Parcelable "contract" methods. //
+    /////////////////////////////////////
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeInt(mType);
+        parcel.writeInt(mSubType);
+    }
+
+    private AutoFillType(Parcel parcel) {
+        mType = parcel.readInt();
+        mSubType = parcel.readInt();
+    }
+
+    public static final Parcelable.Creator<AutoFillType> CREATOR =
+            new Parcelable.Creator<AutoFillType>() {
+        @Override
+        public AutoFillType createFromParcel(Parcel source) {
+            return new AutoFillType(source);
+        }
+
+        @Override
+        public AutoFillType[] newArray(int size) {
+            return new AutoFillType[size];
+        }
+    };
+
+    ////////////////////
+    // Factory methods //
+    ////////////////////
+
+    /**
+     * Creates a text field type, which is filled by a {@link CharSequence}.
+     *
+     * <p>See {@link #isText()} for more info.
+     */
+    public static AutoFillType forText(int inputType) {
+        return new AutoFillType(TYPE_TEXT, inputType);
+    }
+
+    /**
+     * Creates a type that can be toggled which is filled by a {@code boolean}.
+     *
+     * <p>See {@link #isToggle()} for more info.
+     */
+    public static AutoFillType forToggle() {
+        return DefaultTypesHolder.TOGGLE;
+    }
+
+    /**
+     * Creates a selection list, which is filled by a {@code integer} representing the element index
+     * inside the list (starting at {@code 0}.
+     *
+     * <p>See {@link #isList()} for more info.
+     */
+    public static AutoFillType forList() {
+        return DefaultTypesHolder.LIST;
+    }
+}
diff --git a/core/java/android/service/autofill/IAutoFillCallback.aidl b/core/java/android/view/autofill/AutoFillValue.aidl
similarity index 63%
copy from core/java/android/service/autofill/IAutoFillCallback.aidl
copy to core/java/android/view/autofill/AutoFillValue.aidl
index d6d4f39..3b284b9 100644
--- a/core/java/android/service/autofill/IAutoFillCallback.aidl
+++ b/core/java/android/view/autofill/AutoFillValue.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
+/**
+ * Copyright (c) 2016, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,14 +14,6 @@
  * limitations under the License.
  */
 
-package android.service.autofill;
+package android.view.autofill;
 
-import java.util.List;
-
-/**
- * @hide
- */
-oneway interface IAutoFillCallback {
-    void autofill(in List values);
-    void showError(String message);
-}
+parcelable AutoFillValue;
\ No newline at end of file
diff --git a/core/java/android/view/autofill/AutoFillValue.java b/core/java/android/view/autofill/AutoFillValue.java
new file mode 100644
index 0000000..c39f26b
--- /dev/null
+++ b/core/java/android/view/autofill/AutoFillValue.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.autofill;
+
+import static android.view.autofill.Helper.DEBUG;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.View;
+
+/**
+ * Abstracts how a {@link View} can be auto-filled by an
+ * {@link android.service.autofill.AutoFillService}.
+ *
+ * <p>Each {@link AutoFillValue} has a {@code type} and optionally a {@code sub-type}: the
+ * {@code type} defines the view's UI control category (like a text field), while the optional
+ * {@code sub-type} define its semantics (like a postal address).
+ */
+public final class AutoFillValue implements Parcelable {
+
+    private final CharSequence mText;
+    private final int mListIndex;
+    private final boolean mToggle;
+
+    private AutoFillValue(CharSequence text, int listIndex, boolean toggle) {
+        mText = text;
+        mListIndex = listIndex;
+        mToggle = toggle;
+    }
+
+    /**
+     * Gets the value to auto-fill a text field.
+     *
+     * <p>See {@link AutoFillType#isText()} for more info.
+     */
+    public CharSequence getTextValue() {
+        return mText;
+    }
+
+    /**
+     * Gets the value to auto-fill a toggable field.
+     *
+     * <p>See {@link AutoFillType#isToggle()} for more info.
+     */
+    public boolean getToggleValue() {
+        return mToggle;
+    }
+
+    /**
+     * Gets the value to auto-fill a selection list field.
+     *
+     * <p>See {@link AutoFillType#isList()} for more info.
+     */
+    public int getListValue() {
+        return mListIndex;
+    }
+
+    /////////////////////////////////////
+    //  Object "contract" methods. //
+    /////////////////////////////////////
+
+    @Override
+    public String toString() {
+        if (!DEBUG) return super.toString();
+
+        return "AutoFillValue[text=" + mText + ", listIndex=" + mListIndex + ", toggle=" + mToggle
+                + "]";
+    }
+
+    /////////////////////////////////////
+    //  Parcelable "contract" methods. //
+    /////////////////////////////////////
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeCharSequence(mText);
+        parcel.writeInt(mListIndex);
+        parcel.writeInt(mToggle ? 1 : 0);
+    }
+
+    private AutoFillValue(Parcel parcel) {
+        mText = parcel.readCharSequence();
+        mListIndex = parcel.readInt();
+        mToggle = parcel.readInt() == 1;
+    }
+
+    public static final Parcelable.Creator<AutoFillValue> CREATOR =
+            new Parcelable.Creator<AutoFillValue>() {
+        @Override
+        public AutoFillValue createFromParcel(Parcel source) {
+            return new AutoFillValue(source);
+        }
+
+        @Override
+        public AutoFillValue[] newArray(int size) {
+            return new AutoFillValue[size];
+        }
+    };
+
+    ////////////////////
+    // Factory methods //
+    ////////////////////
+
+    // TODO(b/33197203): add unit tests for each supported type (new / get should return same value)
+    /**
+     * Creates a new {@link AutoFillValue} to auto-fill a text field.
+     *
+     * <p>See {@link AutoFillType#isText()} for more info.
+     */
+    public static AutoFillValue forText(CharSequence value) {
+        return new AutoFillValue(value, 0, false);
+    }
+
+    /**
+     * Creates a new {@link AutoFillValue} to auto-fill a toggable field.
+     *
+     * <p>See {@link AutoFillType#isToggle()} for more info.
+     */
+    public static AutoFillValue forToggle(boolean value) {
+        return new AutoFillValue(null, 0, value);
+    }
+
+    /**
+     * Creates a new {@link AutoFillValue} to auto-fill a selection list field.
+     *
+     * <p>See {@link AutoFillType#isList()} for more info.
+     */
+    public static AutoFillValue forList(int value) {
+        return new AutoFillValue(null, value, false);
+    }
+}
diff --git a/core/java/android/service/autofill/IAutoFillCallback.aidl b/core/java/android/view/autofill/Dataset.aidl
similarity index 63%
copy from core/java/android/service/autofill/IAutoFillCallback.aidl
copy to core/java/android/view/autofill/Dataset.aidl
index d6d4f39..2a8e67c 100644
--- a/core/java/android/service/autofill/IAutoFillCallback.aidl
+++ b/core/java/android/view/autofill/Dataset.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
+/**
+ * Copyright (c) 2016, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,14 +14,6 @@
  * limitations under the License.
  */
 
-package android.service.autofill;
+package android.view.autofill;
 
-import java.util.List;
-
-/**
- * @hide
- */
-oneway interface IAutoFillCallback {
-    void autofill(in List values);
-    void showError(String message);
-}
+parcelable Dataset;
\ No newline at end of file
diff --git a/core/java/android/view/autofill/Dataset.java b/core/java/android/view/autofill/Dataset.java
new file mode 100644
index 0000000..a73eb774
--- /dev/null
+++ b/core/java/android/view/autofill/Dataset.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.autofill;
+
+import static android.view.autofill.Helper.DEBUG;
+import static android.view.autofill.Helper.append;
+
+import android.app.Activity;
+import android.app.assist.AssistStructure.ViewNode;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.service.autofill.AutoFillService;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A set of data that can be used to auto-fill an {@link Activity}.
+ *
+ * <p>It contains:
+ *
+ * <ol>
+ *   <li>A name used to identify the dataset in the UI.
+ *   <li>A list of id/value pairs for the fields that can be auto-filled.
+ *   <li>An optional {@link Bundle} with extras (used only by the service creating it).
+ * </ol>
+ *
+ * See {@link FillResponse} for examples.
+ */
+public final class Dataset implements Parcelable {
+
+    private final CharSequence mName;
+    private final ArrayList<DatasetField> mFields;
+    private final Bundle mExtras;
+
+    private Dataset(Dataset.Builder builder) {
+        mName = builder.mName;
+        // TODO(b/33197203): make an immutable copy of mFields?
+        mFields = builder.mFields;
+        mExtras = builder.mExtras;
+    }
+
+    /** @hide */
+    public CharSequence getName() {
+        return mName;
+    }
+
+    /** @hide */
+    public List<DatasetField> getFields() {
+        return mFields;
+    }
+
+    /** @hide */
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public String toString() {
+        if (!DEBUG) return super.toString();
+
+        final StringBuilder builder = new StringBuilder("Dataset [name=").append(mName)
+                .append(", fields=").append(mFields).append(", extras=");
+        append(builder, mExtras);
+        return builder.append(']').toString();
+    }
+
+    /**
+     * A builder for {@link Dataset} objects.
+     */
+    public static final class Builder {
+        private CharSequence mName;
+        private final ArrayList<DatasetField> mFields = new ArrayList<>();
+        private Bundle mExtras;
+
+        /**
+         * Creates a new builder.
+         *
+         * @param name Name used to identify the dataset in the UI. Typically it's the same value as
+         * the first field in the dataset (like username or email address) or an user-provided name
+         * (like "My Work Address").
+         */
+        public Builder(CharSequence name) {
+            mName = Preconditions.checkStringNotEmpty(name, "name cannot be empty or null");
+        }
+
+        /**
+         * Sets the value of a field.
+         *
+         * @param id id returned by {@link ViewNode#getAutoFillId()}.
+         * @param value value to be auto filled.
+         */
+        public Dataset.Builder setValue(AutoFillId id, AutoFillValue value) {
+            putField(new DatasetField(id, value));
+            return this;
+        }
+
+        /**
+         * Creates a new {@link Dataset} instance.
+         */
+        public Dataset build() {
+            return new Dataset(this);
+        }
+
+        /**
+         * Sets a {@link Bundle} that will be passed to subsequent calls to {@link AutoFillService}
+         * methods such as
+         * {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle,
+         * android.os.CancellationSignal, android.service.autofill.SaveCallback)}, using
+         * {@link AutoFillService#EXTRA_DATASET_EXTRAS} as the key.
+         *
+         * <p>It can be used to keep service state in between calls.
+         */
+        public Builder setExtras(Bundle extras) {
+            mExtras = Objects.requireNonNull(extras, "extras cannot be null");
+            return this;
+        }
+
+        /**
+         * Emulates {@code Map.put()} by adding a new field to the list if its id is not the yet,
+         * or replacing the existing one.
+         */
+        private void putField(DatasetField field) {
+            // TODO(b/33197203): check if already exists and replaces it if so
+            mFields.add(field);
+        }
+    }
+
+    /////////////////////////////////////
+    //  Parcelable "contract" methods. //
+    /////////////////////////////////////
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeCharSequence(mName);
+        parcel.writeList(mFields);
+        parcel.writeBundle(mExtras);
+    }
+
+    @SuppressWarnings("unchecked")
+    private Dataset(Parcel parcel) {
+        mName = parcel.readCharSequence();
+        mFields = parcel.readArrayList(null);
+        mExtras = parcel.readBundle();
+    }
+
+    public static final Parcelable.Creator<Dataset> CREATOR = new Parcelable.Creator<Dataset>() {
+        @Override
+        public Dataset createFromParcel(Parcel source) {
+            return new Dataset(source);
+        }
+
+        @Override
+        public Dataset[] newArray(int size) {
+            return new Dataset[size];
+        }
+    };
+}
diff --git a/core/java/android/view/autofill/DatasetField.java b/core/java/android/view/autofill/DatasetField.java
new file mode 100644
index 0000000..c6b92ac
--- /dev/null
+++ b/core/java/android/view/autofill/DatasetField.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.autofill;
+
+import static android.view.autofill.Helper.DEBUG;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public final class DatasetField implements Parcelable {
+
+    private final AutoFillId mId;
+    private final AutoFillValue mValue;
+
+    DatasetField(AutoFillId id, AutoFillValue value) {
+        mId = id;
+        mValue = value;
+    }
+
+    public AutoFillId getId() {
+        return mId;
+    }
+
+    public AutoFillValue getValue() {
+        return mValue;
+    }
+
+    /////////////////////////////////
+    //  Object "contract" methods. //
+    /////////////////////////////////
+
+    @Override
+    public String toString() {
+        if (!DEBUG) return super.toString();
+
+        return "DatasetField [id=" + mId + ", value=" + mValue + "]";
+    }
+
+    /////////////////////////////////////
+    //  Parcelable "contract" methods. //
+    /////////////////////////////////////
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeParcelable(mId, 0);
+        parcel.writeParcelable(mValue, 0);
+    }
+
+    private DatasetField(Parcel parcel) {
+        mId = parcel.readParcelable(null);
+        mValue = parcel.readParcelable(null);
+    }
+
+    public static final Parcelable.Creator<DatasetField> CREATOR =
+            new Parcelable.Creator<DatasetField>() {
+        @Override
+        public DatasetField createFromParcel(Parcel source) {
+            return new DatasetField(source);
+        }
+
+        @Override
+        public DatasetField[] newArray(int size) {
+            return new DatasetField[size];
+        }
+    };
+}
diff --git a/core/java/android/service/autofill/IAutoFillCallback.aidl b/core/java/android/view/autofill/FieldId.aidl
similarity index 63%
copy from core/java/android/service/autofill/IAutoFillCallback.aidl
copy to core/java/android/view/autofill/FieldId.aidl
index d6d4f39..35af645 100644
--- a/core/java/android/service/autofill/IAutoFillCallback.aidl
+++ b/core/java/android/view/autofill/FieldId.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
+/**
+ * Copyright (c) 2016, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,14 +14,6 @@
  * limitations under the License.
  */
 
-package android.service.autofill;
+package android.view.autofill;
 
-import java.util.List;
-
-/**
- * @hide
- */
-oneway interface IAutoFillCallback {
-    void autofill(in List values);
-    void showError(String message);
-}
+parcelable FieldId;
\ No newline at end of file
diff --git a/core/java/android/service/autofill/IAutoFillCallback.aidl b/core/java/android/view/autofill/FillResponse.aidl
similarity index 63%
copy from core/java/android/service/autofill/IAutoFillCallback.aidl
copy to core/java/android/view/autofill/FillResponse.aidl
index d6d4f39..b018f15 100644
--- a/core/java/android/service/autofill/IAutoFillCallback.aidl
+++ b/core/java/android/view/autofill/FillResponse.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
+/**
+ * Copyright (c) 2016, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,14 +14,6 @@
  * limitations under the License.
  */
 
-package android.service.autofill;
+package android.view.autofill;
 
-import java.util.List;
-
-/**
- * @hide
- */
-oneway interface IAutoFillCallback {
-    void autofill(in List values);
-    void showError(String message);
-}
+parcelable FillResponse;
\ No newline at end of file
diff --git a/core/java/android/view/autofill/FillResponse.java b/core/java/android/view/autofill/FillResponse.java
new file mode 100644
index 0000000..3a14767
--- /dev/null
+++ b/core/java/android/view/autofill/FillResponse.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view.autofill;
+
+import static android.view.autofill.Helper.DEBUG;
+import static android.view.autofill.Helper.append;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.service.autofill.AutoFillService;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Response for a
+ * {@link AutoFillService#onFillRequest(android.app.assist.AssistStructure, Bundle,
+ * android.os.CancellationSignal, android.service.autofill.FillCallback)}
+ * request.
+ *
+ * <p>The response typically contains one or more {@link Dataset}s, each representing a set of
+ * fields that can be auto-filled together. For example, for a login page with username/password
+ * where the user only have one account in the service, the response could be:
+ *
+ * <pre class="prettyprint">
+ *  new FillResponse.Builder()
+ *      .add(new Dataset.Builder("homer")
+ *          .setTextFieldValue(id1, "homer")
+ *          .setTextFieldValue(id2, "D'OH!")
+ *          .build())
+ *      .build();
+ * </pre>
+ *
+ * <p>If the user had 2 accounts, each with its own user-provided names, the response could be:
+ *
+ * <pre class="prettyprint">
+ *  new FillResponse.Builder()
+ *      .add(new Dataset.Builder("Homer's Account")
+ *          .setTextFieldValue(id1, "homer")
+ *          .setTextFieldValue(id2, "D'OH!")
+ *          .build())
+ *      .add(new Dataset.Builder("Bart's Account")
+ *          .setTextFieldValue(id1, "elbarto")
+ *          .setTextFieldValue(id2, "cowabonga")
+ *          .build())
+ *      .build();
+ * </pre>
+ *
+ * <p>If the user does not have any data associated with this {@link Activity} but the service
+ * wants to offer the user the option to save the data that was entered, then the service could
+ * populate the response with {@code savableIds} instead of {@link Dataset}s:
+ *
+ * <pre class="prettyprint">
+ *  new FillResponse.Builder()
+ *      .addSavableFields(id1, id2)
+ *      .build();
+ * </pre>
+ *
+ * <p>Similarly, there might be cases where the user data on the service is enough to populate some
+ * fields but not all, and the service would still be interested on saving the other fields. In this
+ * scenario, the service could populate the response with both {@link Dataset}s and
+ * {@code savableIds}:
+ *
+ * <pre class="prettyprint">
+ *   new FillResponse.Builder()
+ *       .add(new Dataset.Builder("Homer")
+ *          .setTextFieldValue(id1, "Homer")                  // first name
+ *          .setTextFieldValue(id2, "Simpson")                // last name
+ *          .setTextFieldValue(id3, "742 Evergreen Terrace")  // street
+ *          .setTextFieldValue(id4, "Springfield")            // city
+ *          .build())
+ *       .addSavableFields(id5, id6) // state and zipcode
+ *       .build();
+ *
+ * </pre>
+ *
+ * <p>Notice that the ids that are part of a dataset (ids 1 to 4, in this example) are automatically
+ * added to the {@code savableIds} list.
+ *
+ * <p>If the service has multiple {@link Dataset}s with multiple options for some fields on each
+ * dataset (for example, multiple accounts with both a home and work address), then it should
+ * "partition" the {@link Activity} in sections and populate the response with just a subset of the
+ * data that would fulfill the first section; then once the user fills the first section and taps
+ * a field from the next section, the Android system would issue another request for that section,
+ * and so on. For example, the first response could be:
+ *
+ * <pre class="prettyprint">
+ *  new FillResponse.Builder()
+ *      .add(new Dataset.Builder("Homer")
+ *          .setTextFieldValue(id1, "Homer")
+ *          .setTextFieldValue(id2, "Simpson")
+ *          .build())
+ *      .add(new Dataset.Builder("Bart")
+ *          .setTextFieldValue(id1, "Bart")
+ *          .setTextFieldValue(id2, "Simpson")
+ *          .build())
+ *      .build();
+ * </pre>
+ *
+ * <p>Then after the user picks the {@code Homer} dataset and taps the {@code Street} field to
+ * trigger another auto-fill request, the second response could be:
+ *
+ * <pre class="prettyprint">
+ *  new FillResponse.Builder()
+ *      .add(new Dataset.Builder("Home")
+ *          .setTextFieldValue(id3, "742 Evergreen Terrace")
+ *          .setTextFieldValue(id4, "Springfield")
+ *          .build())
+ *      .add(new Dataset.Builder("Work")
+ *          .setTextFieldValue(id3, "Springfield Nuclear Power Plant")
+ *          .setTextFieldValue(id4, "Springfield")
+ *          .build())
+ *      .build();
+ * </pre>
+ *
+ * <p>Finally, the service can use the {@link FillResponse.Builder#setExtras(Bundle)} and/or
+ * {@link Dataset.Builder#setExtras(Bundle)} methods to pass
+ * a {@link Bundle} with service-specific data use to identify this response on future calls (like
+ * {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle,
+ * android.os.CancellationSignal, android.service.autofill.SaveCallback)}) - such bundle will be
+ * available as the {@link AutoFillService#EXTRA_RESPONSE_EXTRAS} extra in
+ * that method's {@code extras} argument.
+ */
+public final class FillResponse implements Parcelable {
+
+    private final List<Dataset> mDatasets;
+    private final AutoFillId[] mSavableIds;
+    private final Bundle mExtras;
+
+    private FillResponse(Builder builder) {
+        // TODO(b/33197203): make it immutable?
+        mDatasets = builder.mDatasets;
+        final int size = builder.mSavableIds.size();
+        mSavableIds = new AutoFillId[size];
+        int i = 0;
+        for (AutoFillId id : builder.mSavableIds) {
+            mSavableIds[i++] = id;
+        }
+        mExtras = builder.mExtras;
+    }
+
+    /** @hide */
+    public List<Dataset> getDatasets() {
+        return mDatasets;
+    }
+
+    /** @hide */
+    public AutoFillId[] getSavableIds() {
+        return mSavableIds;
+    }
+
+    /** @hide */
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    /**
+     * Builder for {@link FillResponse} objects.
+     */
+    public static final class Builder {
+        private final List<Dataset> mDatasets = new ArrayList<>();
+        private final Set<AutoFillId> mSavableIds = new HashSet<>();
+        private  Bundle mExtras;
+
+        /**
+         * Adds a new {@link Dataset} to this response.
+         *
+         * @throws IllegalArgumentException if a dataset with same {@code name} already exists.
+         */
+        public Builder addDataset(Dataset dataset) {
+            Preconditions.checkNotNull(dataset, "dataset cannot be null");
+            // TODO(b/33197203): check if name already exists
+            // TODO(b/33197203): check if authId already exists (and update javadoc)
+            mDatasets.add(dataset);
+            for (DatasetField field : dataset.getFields()) {
+                mSavableIds.add(field.getId());
+            }
+            return this;
+        }
+
+        /**
+         * Adds ids of additional fields that the service would be interested to save (through
+         * {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle,
+         * android.os.CancellationSignal, android.service.autofill.SaveCallback)}) but were not
+         * indirectly set through {@link #addDataset(Dataset)}.
+         *
+         * <p>See {@link FillResponse} for examples.
+         */
+        public Builder addSavableFields(AutoFillId...ids) {
+            for (AutoFillId id : ids) {
+                mSavableIds.add(id);
+            }
+            return this;
+        }
+
+        /**
+         * Sets a {@link Bundle} that will be passed to subsequent calls to {@link AutoFillService}
+         * methods such as
+         * {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle,
+         * android.os.CancellationSignal, android.service.autofill.SaveCallback)}, using
+         * {@link AutoFillService#EXTRA_RESPONSE_EXTRAS} as the key.
+         *
+         * <p>It can be used when to keep service state in between calls.
+         */
+        public Builder setExtras(Bundle extras) {
+            mExtras = Objects.requireNonNull(extras, "extras cannot be null");
+            return this;
+        }
+
+        /**
+         * Builds a new {@link FillResponse} instance.
+         */
+        public FillResponse build() {
+            return new FillResponse(this);
+        }
+    }
+
+    /////////////////////////////////////
+    //  Object "contract" methods. //
+    /////////////////////////////////////
+    @Override
+    public String toString() {
+        if (!DEBUG) return super.toString();
+
+        final StringBuilder builder = new StringBuilder("FillResponse: [datasets=")
+                .append(mDatasets).append(", savableIds=").append(Arrays.toString(mSavableIds))
+                .append(", extras=");
+        append(builder, mExtras);
+        return builder.append(']').toString();
+    }
+
+    /////////////////////////////////////
+    //  Parcelable "contract" methods. //
+    /////////////////////////////////////
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeList(mDatasets);
+        parcel.writeParcelableArray(mSavableIds, 0);
+        parcel.writeBundle(mExtras);
+    }
+
+    private FillResponse(Parcel parcel) {
+        mDatasets = new ArrayList<>();
+        parcel.readList(mDatasets, null);
+        mSavableIds = parcel.readParcelableArray(null, AutoFillId.class);
+        mExtras = parcel.readBundle();
+    }
+
+    public static final Parcelable.Creator<FillResponse> CREATOR =
+            new Parcelable.Creator<FillResponse>() {
+        @Override
+        public FillResponse createFromParcel(Parcel source) {
+            return new FillResponse(source);
+        }
+
+        @Override
+        public FillResponse[] newArray(int size) {
+            return new FillResponse[size];
+        }
+    };
+}
diff --git a/core/java/android/view/autofill/Helper.java b/core/java/android/view/autofill/Helper.java
new file mode 100644
index 0000000..772710e
--- /dev/null
+++ b/core/java/android/view/autofill/Helper.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.autofill;
+
+import android.os.Bundle;
+
+import java.util.Set;
+
+/** @hide */
+public final class Helper {
+
+    // TODO(b/33197203): set to false when stable
+    static final boolean DEBUG = true;
+    static final String REDACTED = "[REDACTED]";
+
+    static void append(StringBuilder builder, Bundle bundle) {
+        if (bundle == null) {
+            builder.append("N/A");
+        } else if (!DEBUG) {
+            builder.append(REDACTED);
+        } else {
+            final Set<String> keySet = bundle.keySet();
+            builder.append("[bundle with ").append(keySet.size()).append(" extras:");
+            for (String key : keySet) {
+                builder.append(' ').append(key).append('=').append(bundle.get(key)).append(',');
+            }
+            builder.append(']');
+        }
+    }
+
+    private Helper() {
+        throw new UnsupportedOperationException("contains static members only");
+    }
+}
diff --git a/core/java/android/view/autofill/VirtualViewDelegate.java b/core/java/android/view/autofill/VirtualViewDelegate.java
new file mode 100644
index 0000000..a19b4e5
--- /dev/null
+++ b/core/java/android/view/autofill/VirtualViewDelegate.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view.autofill;
+
+import android.util.Log;
+import android.view.View;
+import android.view.ViewStructure;
+
+/**
+ * This class is the contract a client should implement to enable support of a
+ * virtual view hierarchy rooted at a given view for auto-fill purposes.
+ *
+ * <p>The view hierarchy is typically created through the
+ * {@link View#onProvideAutoFillVirtualStructure(android.view.ViewStructure, int)} call and client
+ * add virtual children by calling {@link ViewStructure#newChild(int, int)} or
+ * {@link ViewStructure#asyncNewChild(int, int)}, where the client provides the {@code virtualId}
+ * of the children - the same {@code virtualId} is used in the methods of this class.
+ *
+ * <p>Objects of this class are typically created by overriding
+ * {@link View#getAutoFillVirtualViewDelegate(Callback)} and saving the passed callback, which must
+ * be notified upon changes on the hierarchy.
+ *
+ * <p>The main use case of these API is to enable custom views that draws its content - such as
+ * {@link android.webkit.WebView} providers - to support the AutoFill Framework:
+ *
+ * <ol>
+ *   <li>Client populates the virtual hierarchy on
+ * {@link View#onProvideAutoFillVirtualStructure(android.view.ViewStructure, int)}
+ *   <li>Android System generates the proper {@link AutoFillId} - encapsulating the view and the
+ * virtual node ids - and pass it to the {@link android.service.autofill.AutoFillService}.
+ *   <li>The service uses the {@link AutoFillId} to populate the auto-fill {@link Dataset}s and pass
+ *   it back to the Android System.
+ *   <li>Android System uses the {@link AutoFillId} to find the proper custom view and calls
+ *   {@link #autoFill(int, AutoFillValue)} on that view passing the virtual id.
+ *   <li>This provider than finds the node in the hierarchy and auto-fills it.
+ * </ol>
+ *
+ */
+public abstract class VirtualViewDelegate {
+
+    // TODO(b/33197203): set to false once stable
+    private static final boolean DEBUG = true;
+
+    private static final String TAG = "VirtualViewDelegate";
+
+    /**
+     * Auto-fills a virtual view with the {@code value}.
+     *
+     * @param virtualId id identifying the virtual node inside the custom view.
+     * @param value value to be auto-filled.
+     */
+    public abstract void autoFill(int virtualId, AutoFillValue value);
+
+    /**
+     * Callback used to notify the AutoFill Framework of changes made on the view hierarchy while
+     * an {@link android.app.Activity} is being auto filled.
+     */
+    public abstract static class Callback {
+
+        /**
+         * Sent when the focus inside the hierarchy changed.
+         *
+         * <p>Typically callled twice - for the nodes that lost and gained focus.
+         *
+         * <p>This method should only be called when the change was not caused by the AutoFill
+         * Framework itselft (i.e, through {@link VirtualViewDelegate#autoFill(int, AutoFillValue)},
+         * but by external causes (for example, when the user changed the value through the view's
+         * UI).
+         *
+         * @param virtualId id of the node whose focus changed.
+         * @param hasFocus {@code true} when focus was gained, {@code false} when it was lost.
+         */
+        public void onFocusChanged(int virtualId, boolean hasFocus) {
+            if (DEBUG) Log.d(TAG, "onFocusChanged() for " + virtualId + ": " + hasFocus);
+        }
+
+        /**
+         * Sent when the value of a node was changed.
+         *
+         * <p>This method should only be called when the change was not caused by the AutoFill
+         * Framework itselft (i.e, through {@link VirtualViewDelegate#autoFill(int, AutoFillValue)},
+         * but by external causes (for example, when the user changed the value through the view's
+         * UI).
+         *
+         * @param virtualId id of the node whose value changed.
+         */
+        public void onValueChanged(int virtualId) {
+            if (DEBUG) Log.d(TAG, "onValueChanged() for" + virtualId);
+        }
+
+        /**
+         * Sent when nodes were removed (or had their ids changed) after the hierarchy has been
+         * committed to
+         * {@link View#onProvideAutoFillVirtualStructure(android.view.ViewStructure, int)}.
+         *
+         * <p>For example, when the view is rendering an {@code HTML} page, it should call this
+         * method when:
+         * <ul>
+         * <li>User navigated to another page and some (or all) nodes are gone.
+         * <li>The page's {@code DOM} was changed by {@code JavaScript} and some nodes moved (and
+         * are now identified by different ids).
+         * </ul>
+         *
+         * @param virtualIds id of the nodes that were removed.
+         */
+        public void onNodeRemoved(int... virtualIds) {
+            if (DEBUG) Log.d(TAG, "onNodeRemoved(): " + virtualIds);
+        }
+    }
+}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 8ecc42d..f98c099 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2515,8 +2515,8 @@
     }
 
     @Override
-    public void onProvideVirtualStructure(ViewStructure structure, int flags) {
-        mProvider.getViewDelegate().onProvideVirtualStructure(structure, flags);
+    public void onProvideAutoFillVirtualStructure(ViewStructure structure, int flags) {
+        mProvider.getViewDelegate().onProvideAutoFillVirtualStructure(structure, flags);
     }
 
     /** @hide */
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index eb0c44c..d7a49e4 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -59,8 +59,8 @@
 
     // visible for WebViewZygoteInit to look up the class by reflection and call preloadInZygote.
     /** @hide */
-    public static final String CHROMIUM_WEBVIEW_FACTORY =
-            "com.android.webview.chromium.WebViewChromiumFactoryProvider";
+    private static final String CHROMIUM_WEBVIEW_FACTORY =
+            "com.android.webview.chromium.WebViewChromiumFactoryProviderForO";
 
     private static final String CHROMIUM_WEBVIEW_FACTORY_METHOD = "create";
 
@@ -143,6 +143,23 @@
     }
 
     /**
+     * @hide
+     */
+    public static Class<WebViewFactoryProvider> getWebViewProviderClass(  ClassLoader clazzLoader)
+            throws ClassNotFoundException{
+        try {
+            return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY,
+                    true, clazzLoader);
+        } catch (ClassNotFoundException e) {
+            // TODO: This loads the provider which is not built for O, should be removed
+            // before the release.
+            return (Class<WebViewFactoryProvider>) Class.forName(
+                    "com.android.webview.chromium.WebViewChromiumFactoryProvider",
+                    true, clazzLoader);
+        }
+    }
+
+    /**
      * Load the native library for the given package name iff that package
      * name is the same as the one providing the webview.
      */
@@ -366,9 +383,9 @@
 
                 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "Class.forName()");
                 try {
-                    return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY,
-                            true, clazzLoader);
-                } finally {
+                    return getWebViewProviderClass(clazzLoader);
+                }
+                finally {
                     Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
                 }
             } catch (ClassNotFoundException e) {
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 7b95180..dd1b0d2 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -312,7 +312,7 @@
         public void onProvideVirtualStructure(android.view.ViewStructure structure);
 
         @SuppressWarnings("unused")
-        public default void onProvideVirtualStructure(android.view.ViewStructure structure,
+        public default void onProvideAutoFillVirtualStructure(android.view.ViewStructure structure,
                 int flags) {
         }
 
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 3213a34..718070d 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -34,6 +34,8 @@
 import android.view.ViewHierarchyEncoder;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.autofill.AutoFillType;
+import android.view.autofill.AutoFillValue;
 
 import com.android.internal.R;
 
@@ -52,6 +54,7 @@
  * </p>
  */
 public abstract class CompoundButton extends Button implements Checkable {
+
     private boolean mChecked;
     private boolean mBroadcasting;
 
@@ -111,6 +114,7 @@
         applyButtonTint();
     }
 
+    @Override
     public void toggle() {
         setChecked(!mChecked);
     }
@@ -130,6 +134,7 @@
     }
 
     @ViewDebug.ExportedProperty
+    @Override
     public boolean isChecked() {
         return mChecked;
     }
@@ -139,6 +144,7 @@
      *
      * @param checked true to check the button, false to uncheck it
      */
+    @Override
     public void setChecked(boolean checked) {
         if (mChecked != checked) {
             mChecked = checked;
@@ -514,12 +520,15 @@
                     + " checked=" + checked + "}";
         }
 
-        public static final Parcelable.Creator<SavedState> CREATOR
-                = new Parcelable.Creator<SavedState>() {
+        @SuppressWarnings("hiding")
+        public static final Parcelable.Creator<SavedState> CREATOR =
+                new Parcelable.Creator<SavedState>() {
+            @Override
             public SavedState createFromParcel(Parcel in) {
                 return new SavedState(in);
             }
 
+            @Override
             public SavedState[] newArray(int size) {
                 return new SavedState[size];
             }
@@ -551,4 +560,16 @@
         super.encodeProperties(stream);
         stream.addProperty("checked", isChecked());
     }
+
+    // TODO(b/33197203): add unit/CTS tests for auto-fill methods
+
+    @Override
+    public void autoFill(AutoFillValue value) {
+        setChecked(value.getToggleValue());
+    }
+
+    @Override
+    public AutoFillType getAutoFillType() {
+        return AutoFillType.forToggle();
+    }
 }
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index 043eb34..af5c842 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -24,8 +24,10 @@
 import android.text.method.ArrowKeyMovementMethod;
 import android.text.method.MovementMethod;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.accessibility.AccessibilityNodeInfo;
-
+import android.view.autofill.AutoFillType;
+import android.view.autofill.AutoFillValue;
 
 /*
  * This is supposed to be a *very* thin veneer over TextView.
@@ -154,4 +156,26 @@
             info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_TEXT);
         }
     }
+
+    // TODO(b/33197203): add unit/CTS tests for auto-fill methods
+
+    @Override
+    public void autoFill(AutoFillValue value) {
+        final CharSequence text = value.getTextValue();
+
+        if (text == null) {
+            Log.w(VIEW_LOG_TAG, "EditText.autoFill(): no text on AutoFillValue");
+            return;
+        }
+        // TODO(b/33197203): once auto-fill is triggered by the IME, we'll need a new setText()
+        // or setAutoFillText() method on TextView to avoid re-triggering it.
+        setText(text);
+    }
+
+    @Override
+    public AutoFillType getAutoFillType() {
+        // TODO(b/33197203): ideally it should return a constant, but value returned by
+        // getInputType() can change.
+        return AutoFillType.forText(getInputType());
+    }
 }
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index 54b5763..45fd9e6 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -16,12 +16,16 @@
 
 package android.widget;
 
+
 import android.annotation.IdRes;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.autofill.AutoFillType;
+import android.view.autofill.AutoFillValue;
 
 import com.android.internal.R;
 
@@ -51,6 +55,7 @@
  *
  */
 public class RadioGroup extends LinearLayout {
+
     // holds the checked id; the selection is empty by default
     private int mCheckedId = -1;
     // tracks children radio buttons checked state
@@ -335,6 +340,7 @@
     }
 
     private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener {
+        @Override
         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
             // prevents from infinite recursion
             if (mProtectFromCheckedChange) {
@@ -364,6 +370,7 @@
         /**
          * {@inheritDoc}
          */
+        @Override
         public void onChildViewAdded(View parent, View child) {
             if (parent == RadioGroup.this && child instanceof RadioButton) {
                 int id = child.getId();
@@ -384,6 +391,7 @@
         /**
          * {@inheritDoc}
          */
+        @Override
         public void onChildViewRemoved(View parent, View child) {
             if (parent == RadioGroup.this && child instanceof RadioButton) {
                 ((RadioButton) child).setOnCheckedChangeWidgetListener(null);
@@ -394,4 +402,22 @@
             }
         }
     }
+
+    // TODO(b/33197203): add unit/CTS tests for auto-fill methods
+
+    @Override
+    public void autoFill(AutoFillValue value) {
+        final int index = value.getListValue();
+        final View child = getChildAt(index);
+        if (child == null) {
+            Log.w(VIEW_LOG_TAG, "RadioGroup.autoFill(): no child with index " + index);
+            return;
+        }
+        check(child.getId());
+    }
+
+    @Override
+    public AutoFillType getAutoFillType() {
+        return AutoFillType.forList();
+    }
 }
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index e629df9..a9257e6 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -1404,10 +1404,19 @@
     }
 
     @Override
-    public void onProvideStructure(ViewStructure structure, int flags) {
-        super.onProvideStructure(structure, flags);
+    public void onProvideStructure(ViewStructure structure) {
+        super.onProvideStructure(structure);
+        onProvideAutoFillStructureForAssistOrAutoFill(structure);
+    }
 
-        // NOTE: current there is no difference for Assist (flags=0) or AutoFill (flags>0);
+    @Override
+    public void onProvideAutoFillStructure(ViewStructure structure, int flags) {
+        super.onProvideAutoFillStructure(structure, flags);
+        onProvideAutoFillStructureForAssistOrAutoFill(structure);
+    }
+
+    // NOTE: currently there is no difference for Assist or AutoFill, so it doesn't take flags
+    private void onProvideAutoFillStructureForAssistOrAutoFill(ViewStructure structure) {
         CharSequence switchText = isChecked() ? mTextOn : mTextOff;
         if (!TextUtils.isEmpty(switchText)) {
             CharSequence oldText = structure.getText();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1961bf6..1ddf53d 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -596,6 +596,7 @@
 
     private int mBreakStrategy;
     private int mHyphenationFrequency;
+    private boolean mJustify;
 
     private int mMaximum = Integer.MAX_VALUE;
     private int mMaxMode = LINES;
@@ -769,6 +770,7 @@
         String fontFeatureSettings = null;
         mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
         mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE;
+        mJustify = false;
 
         final Resources.Theme theme = context.getTheme();
 
@@ -3298,6 +3300,29 @@
     }
 
     /**
+     * Enables or disables full justification. The default value is false.
+     *
+     * @see #getJustify()
+     */
+    public void setJustify(boolean justify) {
+        mJustify = justify;
+        if (mLayout != null) {
+            nullLayouts();
+            requestLayout();
+            invalidate();
+        }
+    }
+
+    /**
+     * @return true if currently paragraph justification is enabled.
+     *
+     * @see #setJustify(boolean)
+     */
+    public boolean getJustify() {
+        return mJustify;
+    }
+
+    /**
      * Sets font feature settings. The format is the same as the CSS
      * font-feature-settings attribute:
      * <a href="https://www.w3.org/TR/css-fonts-3/#font-feature-settings-prop">
@@ -7170,6 +7195,7 @@
                         .setIncludePad(mIncludePad)
                         .setBreakStrategy(mBreakStrategy)
                         .setHyphenationFrequency(mHyphenationFrequency)
+                        .setJustify(mJustify)
                         .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
                 if (shouldEllipsize) {
                     builder.setEllipsize(mEllipsize)
@@ -7211,7 +7237,7 @@
         if (mText instanceof Spannable) {
             result = new DynamicLayout(mText, mTransformed, mTextPaint, wantWidth,
                     alignment, mTextDir, mSpacingMult, mSpacingAdd, mIncludePad,
-                    mBreakStrategy, mHyphenationFrequency,
+                    mBreakStrategy, mHyphenationFrequency, mJustify,
                     getKeyListener() == null ? effectiveEllipsize : null, ellipsisWidth);
         } else {
             if (boring == UNKNOWN_BORING) {
@@ -7261,6 +7287,7 @@
                     .setIncludePad(mIncludePad)
                     .setBreakStrategy(mBreakStrategy)
                     .setHyphenationFrequency(mHyphenationFrequency)
+                    .setJustify(mJustify)
                     .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
             if (shouldEllipsize) {
                 builder.setEllipsize(effectiveEllipsize)
@@ -9391,11 +9418,23 @@
     }
 
     @Override
-    public void onProvideStructure(ViewStructure structure, int flags) {
-        super.onProvideStructure(structure, flags);
+    public void onProvideStructure(ViewStructure structure) {
+        super.onProvideStructure(structure);
+        onProvideAutoStructureForAssistOrAutoFill(structure, 0);
+    }
 
+    @Override
+    public void onProvideAutoFillStructure(ViewStructure structure, int flags) {
+        super.onProvideAutoFillStructure(structure, flags);
+        onProvideAutoStructureForAssistOrAutoFill(structure, flags);
+    }
+
+    private void onProvideAutoStructureForAssistOrAutoFill(ViewStructure structure, int flags) {
+        // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well,
+        // this method should take a boolean with the type of request.
         final boolean forAutoFillSave =
-                (flags & ASSIST_FLAG_NON_SANITIZED_TEXT) != 0;
+                (flags & AUTO_FILL_FLAG_TYPE_SAVE) != 0;
+
         final boolean isPassword = hasPasswordTransformationMethod()
                 || isPasswordInputType(getInputType());
         if (!isPassword || forAutoFillSave) {
diff --git a/core/java/com/android/internal/logging/LogBuilder.java b/core/java/com/android/internal/logging/LogBuilder.java
index 634d061..8e2e114 100644
--- a/core/java/com/android/internal/logging/LogBuilder.java
+++ b/core/java/com/android/internal/logging/LogBuilder.java
@@ -17,8 +17,9 @@
 
     private SparseArray<Object> entries = new SparseArray();
 
-    public LogBuilder() {}
-
+    public LogBuilder(int mainCategory) {
+        setCategory(mainCategory);
+    }
 
     public LogBuilder setView(View view) {
         entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_VIEW, view.getId());
diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java
index 12d699d..d82a211 100644
--- a/core/java/com/android/internal/os/WebViewZygoteInit.java
+++ b/core/java/com/android/internal/os/WebViewZygoteInit.java
@@ -24,6 +24,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.webkit.WebViewFactory;
+import android.webkit.WebViewFactoryProvider;
 
 import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
@@ -74,8 +75,8 @@
             // call preloadInZygote() on it to give it the opportunity to preload the native library
             // and perform any other initialisation work that should be shared among the children.
             try {
-                Class providerClass = Class.forName(WebViewFactory.CHROMIUM_WEBVIEW_FACTORY, true,
-                                                    loader);
+                Class<WebViewFactoryProvider> providerClass =
+                        WebViewFactory.getWebViewProviderClass(loader);
                 Object result = providerClass.getMethod("preloadInZygote").invoke(null);
                 if (!((Boolean)result).booleanValue()) {
                     Log.e(TAG, "preloadInZygote returned false");
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 293de3d..e1e0a21 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -85,6 +85,9 @@
      * file descriptor numbers that are to be closed by the child
      * (and replaced by /dev/null) after forking.  An integer value
      * of -1 in any entry in the array means "ignore this one".
+     * @param fdsToIgnore null-ok an array of ints, either null or holding
+     * one or more POSIX file descriptor numbers that are to be ignored
+     * in the file descriptor table check.
      * @param instructionSet null-ok the instruction set to use.
      * @param appDataDir null-ok the data directory of the app.
      *
@@ -93,11 +96,11 @@
      */
     public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
           int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
-          String instructionSet, String appDataDir) {
+          int[] fdsToIgnore, String instructionSet, String appDataDir) {
         VM_HOOKS.preFork();
         int pid = nativeForkAndSpecialize(
                   uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
-                  instructionSet, appDataDir);
+                  fdsToIgnore, instructionSet, appDataDir);
         // Enable tracing as soon as possible for the child process.
         if (pid == 0) {
             Trace.setTracingEnabled(true);
@@ -111,7 +114,7 @@
 
     native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int debugFlags,
           int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
-          String instructionSet, String appDataDir);
+          int[] fdsToIgnore, String instructionSet, String appDataDir);
 
     /**
      * Special method to start the system server process. In addition to the
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 345350c..83e3cff 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -196,11 +196,14 @@
                 rlimits = parsedArgs.rlimits.toArray(intArray2d);
             }
 
+            int[] fdsToIgnore = null;
+
             if (parsedArgs.invokeWith != null) {
                 FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
                 childPipeFd = pipeFds[1];
                 serverPipeFd = pipeFds[0];
                 Os.fcntlInt(childPipeFd, F_SETFD, 0);
+                fdsToIgnore = new int[] { childPipeFd.getInt$(), serverPipeFd.getInt$() };
             }
 
             /**
@@ -233,7 +236,7 @@
 
             pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                     parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
-                    parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
+                    parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
                     parsedArgs.appDataDir);
         } catch (ErrnoException ex) {
             logAndPrintError(newStderr, "Exception creating pipe", ex);
diff --git a/core/java/com/android/internal/view/BaseSurfaceHolder.java b/core/java/com/android/internal/view/BaseSurfaceHolder.java
index b41ef29..32ce0fe 100644
--- a/core/java/com/android/internal/view/BaseSurfaceHolder.java
+++ b/core/java/com/android/internal/view/BaseSurfaceHolder.java
@@ -86,7 +86,7 @@
             mCallbacks.remove(callback);
         }
     }
-    
+
     public SurfaceHolder.Callback[] getCallbacks() {
         if (mHaveGottenCallbacks) {
             return mGottenCallbacks;
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 4f7b106..0185e30 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -562,8 +562,6 @@
             }
             case DO_COMMIT_CONTENT: {
                 final int flags = msg.arg1;
-                final boolean grantUriPermission =
-                        (flags & InputConnection.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0;
                 SomeArgs args = (SomeArgs) msg.obj;
                 try {
                     InputConnection ic = getInputConnection();
@@ -579,22 +577,8 @@
                         args.callback.setCommitContentResult(false, args.seq);
                         return;
                     }
-                    if (grantUriPermission) {
-                        try {
-                            inputContentInfo.requestPermission();
-                        } catch (Exception e) {
-                            Log.e(TAG, "InputConnectionInfo.requestPermission() failed", e);
-                            args.callback.setCommitContentResult(false, args.seq);
-                            return;
-                        }
-                    }
                     final boolean result =
                             ic.commitContent(inputContentInfo, flags, (Bundle) args.arg2);
-                    // If this request is not handled, then there is no reason to keep the URI
-                    // permission.
-                    if (grantUriPermission && !result) {
-                        inputContentInfo.releasePermission();
-                    }
                     args.callback.setCommitContentResult(result, args.seq);
                 } catch (RemoteException e) {
                     Log.w(TAG, "Got RemoteException calling commitContent", e);
diff --git a/core/java/com/android/internal/view/SurfaceCallbackHelper.java b/core/java/com/android/internal/view/SurfaceCallbackHelper.java
new file mode 100644
index 0000000..5b6a82c
--- /dev/null
+++ b/core/java/com/android/internal/view/SurfaceCallbackHelper.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 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.view;
+
+import android.os.RemoteException;
+import android.view.IWindow;
+import android.view.IWindowSession;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+
+public class SurfaceCallbackHelper {
+    IWindowSession mSession;
+    IWindow.Stub mWindow;
+
+    int mFinishDrawingCollected = 0;
+    int mFinishDrawingExpected = 0;
+
+    private Runnable mFinishDrawingRunnable = new Runnable() {
+            @Override
+            public void run() {
+                synchronized (SurfaceCallbackHelper.this) {
+                    mFinishDrawingCollected++;
+                    if (mFinishDrawingCollected < mFinishDrawingExpected) {
+                        return;
+                    }
+                    try {
+                        mSession.finishDrawing(mWindow);
+                    } catch (RemoteException e) {
+                    }
+                }
+            }
+    };
+
+    public SurfaceCallbackHelper(IWindowSession session,
+            IWindow.Stub window) {
+        mSession = session;
+        mWindow = window;
+    }
+
+    public void dispatchSurfaceRedrawNeededAsync(SurfaceHolder holder, SurfaceHolder.Callback callbacks[]) {
+        if (callbacks == null || callbacks.length == 0) {
+            try {
+                mSession.finishDrawing(mWindow);
+            } catch (RemoteException e) {
+            }
+            return;
+        }
+
+        synchronized (this) {
+            mFinishDrawingExpected = callbacks.length;
+            mFinishDrawingCollected = 0;
+        }
+
+        for (SurfaceHolder.Callback c : callbacks) {
+            if (c instanceof SurfaceHolder.Callback2) {
+                ((SurfaceHolder.Callback2) c).surfaceRedrawNeededAsync(
+                        holder, mFinishDrawingRunnable);
+            } else {
+                mFinishDrawingRunnable.run();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp b/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
index aa6348e..dcb7874 100644
--- a/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
+++ b/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
@@ -33,7 +33,9 @@
 #include "HarfBuzzNGFaceSkia.h"
 
 #include <stdlib.h>
-#include <cutils/log.h>
+
+#include <log/log.h>
+
 #include <SkPaint.h>
 #include <SkPath.h>
 #include <SkPoint.h>
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index aa4570f..14d7e81 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -16,32 +16,32 @@
 
 #define LOG_TAG "android.os.Debug"
 
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
+#include <malloc.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
-#include <time.h>
 #include <sys/time.h>
-#include <errno.h>
-#include <assert.h>
-#include <ctype.h>
-#include <malloc.h>
+#include <time.h>
+#include <unistd.h>
 
 #include <iomanip>
 #include <string>
 
-#include "jni.h"
+#include <android-base/stringprintf.h>
+#include <cutils/debugger.h>
+#include <log/log.h>
+#include <utils/misc.h>
+#include <utils/String8.h>
 
-#include "android-base/stringprintf.h"
-#include "cutils/debugger.h"
-#include "cutils/log.h"
 #include "JNIHelp.h"
-#include "memtrack/memtrack.h"
-#include "memunreachable/memunreachable.h"
-#include "utils/misc.h"
-#include "utils/String8.h"
+#include "jni.h"
+#include <memtrack/memtrack.h>
+#include <memunreachable/memunreachable.h>
 
 namespace android
 {
diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp
index ea893f0..de91f70 100644
--- a/core/jni/android_os_Trace.cpp
+++ b/core/jni/android_os_Trace.cpp
@@ -19,15 +19,14 @@
 
 #include <inttypes.h>
 
+#include <cutils/trace.h>
+#include <utils/String8.h>
+#include <log/log.h>
+
 #include <JNIHelp.h>
 #include <ScopedUtfChars.h>
 #include <ScopedStringChars.h>
 
-#include <utils/String8.h>
-
-#include <cutils/trace.h>
-#include <cutils/log.h>
-
 namespace android {
 
 static void sanitizeString(String8& utf8Chars) {
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index 02fa872..c05ef26 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -54,7 +54,8 @@
 // hyphenFrequency)
 static void nSetupParagraph(JNIEnv* env, jclass, jlong nativePtr, jcharArray text, jint length,
         jfloat firstWidth, jint firstWidthLineLimit, jfloat restWidth,
-        jintArray variableTabStops, jint defaultTabStop, jint strategy, jint hyphenFrequency) {
+        jintArray variableTabStops, jint defaultTabStop, jint strategy, jint hyphenFrequency,
+        jboolean isJustified) {
     minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr);
     b->resize(length);
     env->GetCharArrayRegion(text, 0, length, b->buffer());
@@ -68,6 +69,7 @@
     }
     b->setStrategy(static_cast<minikin::BreakStrategy>(strategy));
     b->setHyphenationFrequency(static_cast<minikin::HyphenationFrequency>(hyphenFrequency));
+    b->setJustified(isJustified);
 }
 
 static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks,
@@ -190,7 +192,7 @@
     {"nFinishBuilder", "(J)V", (void*) nFinishBuilder},
     {"nLoadHyphenator", "(Ljava/nio/ByteBuffer;I)J", (void*) nLoadHyphenator},
     {"nSetLocale", "(JLjava/lang/String;J)V", (void*) nSetLocale},
-    {"nSetupParagraph", "(J[CIFIF[IIII)V", (void*) nSetupParagraph},
+    {"nSetupParagraph", "(J[CIFIF[IIIIZ)V", (void*) nSetupParagraph},
     {"nSetIndents", "(J[I)V", (void*) nSetIndents},
     {"nAddStyleRun", "(JJJIIZ)F", (void*) nAddStyleRun},
     {"nAddMeasuredRun", "(JII[F)V", (void*) nAddMeasuredRun},
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 5559d48..abcd1e7 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -29,19 +29,19 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <utils/Atomic.h>
 #include <binder/IInterface.h>
+#include <binder/IServiceManager.h>
 #include <binder/IPCThreadState.h>
-#include <utils/Log.h>
-#include <utils/SystemClock.h>
-#include <utils/List.h>
-#include <utils/KeyedVector.h>
-#include <log/logger.h>
 #include <binder/Parcel.h>
 #include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
-#include <utils/threads.h>
+#include <log/log.h>
+#include <utils/Atomic.h>
+#include <utils/KeyedVector.h>
+#include <utils/List.h>
+#include <utils/Log.h>
 #include <utils/String8.h>
+#include <utils/SystemClock.h>
+#include <utils/threads.h>
 
 #include <ScopedUtfChars.h>
 #include <ScopedLocalRef.h>
diff --git a/core/jni/android_util_Log.cpp b/core/jni/android_util_Log.cpp
index 7719e31..20dfe78 100644
--- a/core/jni/android_util_Log.cpp
+++ b/core/jni/android_util_Log.cpp
@@ -21,7 +21,7 @@
 #include <android-base/macros.h>
 #include <assert.h>
 #include <cutils/properties.h>
-#include <log/logger.h>               // For LOGGER_ENTRY_MAX_PAYLOAD.
+#include <log/log.h>               // For LOGGER_ENTRY_MAX_PAYLOAD.
 #include <utils/Log.h>
 #include <utils/String8.h>
 
diff --git a/core/jni/android_util_jar_StrictJarFile.cpp b/core/jni/android_util_jar_StrictJarFile.cpp
index 2e31c8b..4f1f926 100644
--- a/core/jni/android_util_jar_StrictJarFile.cpp
+++ b/core/jni/android_util_jar_StrictJarFile.cpp
@@ -20,13 +20,14 @@
 #include <memory>
 #include <string>
 
+#include <log/log.h>
+
 #include "JNIHelp.h"
 #include "JniConstants.h"
 #include "ScopedLocalRef.h"
 #include "ScopedUtfChars.h"
 #include "jni.h"
 #include "ziparchive/zip_archive.h"
-#include "cutils/log.h"
 
 namespace android {
 
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index cc7b958..070a2d9 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -43,6 +43,7 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include "android-base/logging.h"
 #include <cutils/fs.h>
 #include <cutils/multiuser.h>
 #include <cutils/sched_policy.h>
@@ -440,6 +441,22 @@
 // The list of open zygote file descriptors.
 static FileDescriptorTable* gOpenFdTable = NULL;
 
+static void FillFileDescriptorVector(JNIEnv* env,
+                                     jintArray java_fds,
+                                     std::vector<int>* fds) {
+  CHECK(fds != nullptr);
+  if (java_fds != nullptr) {
+    ScopedIntArrayRO ar(env, java_fds);
+    if (ar.get() == nullptr) {
+      RuntimeAbort(env, __LINE__, "Bad fd array");
+    }
+    fds->reserve(ar.size());
+    for (size_t i = 0; i < ar.size(); ++i) {
+      fds->push_back(ar[i]);
+    }
+  }
+}
+
 // Utility routine to fork zygote and specialize the child process.
 static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
                                      jint debug_flags, jobjectArray javaRlimits,
@@ -447,6 +464,7 @@
                                      jint mount_external,
                                      jstring java_se_info, jstring java_se_name,
                                      bool is_system_server, jintArray fdsToClose,
+                                     jintArray fdsToIgnore,
                                      jstring instructionSet, jstring dataDir) {
   SetSigChldHandler();
 
@@ -471,12 +489,14 @@
   // If this is the first fork for this zygote, create the open FD table.
   // If it isn't, we just need to check whether the list of open files has
   // changed (and it shouldn't in the normal case).
+  std::vector<int> fds_to_ignore;
+  FillFileDescriptorVector(env, fdsToIgnore, &fds_to_ignore);
   if (gOpenFdTable == NULL) {
-    gOpenFdTable = FileDescriptorTable::Create();
+    gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore);
     if (gOpenFdTable == NULL) {
       RuntimeAbort(env, __LINE__, "Unable to construct file descriptor table.");
     }
-  } else if (!gOpenFdTable->Restat()) {
+  } else if (!gOpenFdTable->Restat(fds_to_ignore)) {
     RuntimeAbort(env, __LINE__, "Unable to restat file descriptor table.");
   }
 
@@ -646,7 +666,9 @@
         JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
         jint debug_flags, jobjectArray rlimits,
         jint mount_external, jstring se_info, jstring se_name,
-        jintArray fdsToClose, jstring instructionSet, jstring appDataDir) {
+        jintArray fdsToClose,
+        jintArray fdsToIgnore,
+        jstring instructionSet, jstring appDataDir) {
     jlong capabilities = 0;
 
     // Grant CAP_WAKE_ALARM to the Bluetooth process.
@@ -681,7 +703,7 @@
 
     return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
             rlimits, capabilities, capabilities, mount_external, se_info,
-            se_name, false, fdsToClose, instructionSet, appDataDir);
+            se_name, false, fdsToClose, fdsToIgnore, instructionSet, appDataDir);
 }
 
 static jint com_android_internal_os_Zygote_nativeForkSystemServer(
@@ -692,7 +714,7 @@
                                       debug_flags, rlimits,
                                       permittedCapabilities, effectiveCapabilities,
                                       MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,
-                                      NULL, NULL);
+                                      NULL, NULL, NULL);
   if (pid > 0) {
       // The zygote process checks whether the child process has died or not.
       ALOGI("System server process %d has been created", pid);
@@ -759,7 +781,7 @@
 
 static const JNINativeMethod gMethods[] = {
     { "nativeForkAndSpecialize",
-      "(II[II[[IILjava/lang/String;Ljava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I",
+      "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[ILjava/lang/String;Ljava/lang/String;)I",
       (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
     { "nativeForkSystemServer", "(II[II[[IJJ)I",
       (void *) com_android_internal_os_Zygote_nativeForkSystemServer },
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 969d336f3..59a536b 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -381,7 +381,7 @@
 }
 
 // static
-FileDescriptorTable* FileDescriptorTable::Create() {
+FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ignore) {
   DIR* d = opendir(kFdPath);
   if (d == NULL) {
     ALOGE("Unable to open directory %s: %s", kFdPath, strerror(errno));
@@ -396,6 +396,10 @@
     if (fd == -1) {
       continue;
     }
+    if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
+      ALOGI("Ignoring open file descriptor %d", fd);
+      continue;
+    }
 
     FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd);
     if (info == NULL) {
@@ -414,7 +418,7 @@
   return new FileDescriptorTable(open_fd_map);
 }
 
-bool FileDescriptorTable::Restat() {
+bool FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore) {
   std::set<int> open_fds;
 
   // First get the list of open descriptors.
@@ -431,6 +435,10 @@
     if (fd == -1) {
       continue;
     }
+    if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
+      ALOGI("Ignoring open file descriptor %d", fd);
+      continue;
+    }
 
     open_fds.insert(fd);
   }
diff --git a/core/jni/fd_utils.h b/core/jni/fd_utils.h
index 9e3afd9..03298c3 100644
--- a/core/jni/fd_utils.h
+++ b/core/jni/fd_utils.h
@@ -122,9 +122,9 @@
   // Creates a new FileDescriptorTable. This function scans
   // /proc/self/fd for the list of open file descriptors and collects
   // information about them. Returns NULL if an error occurs.
-  static FileDescriptorTable* Create();
+  static FileDescriptorTable* Create(const std::vector<int>& fds_to_ignore);
 
-  bool Restat();
+  bool Restat(const std::vector<int>& fds_to_ignore);
 
   // Reopens all file descriptors that are contained in the table. Returns true
   // if all descriptors were successfully re-opened or detached, and false if an
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9cbb8c3..89581bb 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1049,6 +1049,16 @@
          Must be in the range specified by minimum and maximum. -->
     <integer name="config_screenBrightnessSettingDefault">102</integer>
 
+    <!-- Default screen brightness for VR setting. -->
+    <integer name="config_screenBrightnessForVrSettingDefault">86</integer>
+
+    <!-- Minimum screen brightness setting allowed for VR. Device panels start increasing pulse
+         width as brightness decreases below this theshold. -->
+    <integer name="config_screenBrightnessForVrSettingMinimum">79</integer>
+
+    <!-- Maximum screen brightness setting allowed for VR. -->
+    <integer name="config_screenBrightnessForVrSettingMaximum">255</integer>
+
     <!-- Screen brightness used to dim the screen while dozing in a very low power state.
          May be less than the minimum allowed brightness setting
          that can be set by the user. -->
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 5c165e6..5547706 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -129,4 +129,6 @@
   <item type="id" name="remote_input_tag" />
 
   <item type="id" name="cross_task_transition" />
+
+  <item type="id" name="accessibilityActionClickOnClickableSpan" />
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b7f5a9b..b0d64577 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2868,17 +2868,6 @@
     <!-- If there is ever a ringtone set for some setting, but that ringtone can no longer be resolved, t his is shown instead.  For example, if the ringtone was on a SD card and it had been removed, this woudl be shown for ringtones on that SD card. -->
     <string name="ringtone_unknown">Unknown</string>
 
-    <!-- A notification is shown when there are open wireless networks nearby.  This is the notification's title. -->
-    <plurals name="wifi_available">
-        <item quantity="one">Wi-Fi network available</item>
-        <item quantity="other">Wi-Fi networks available</item>
-    </plurals>
-    <!-- A notification is shown when there are open wireless networks nearby.  This is the notification's message. -->
-    <plurals name="wifi_available_detailed">
-        <item quantity="one">Open Wi-Fi network available</item>
-        <item quantity="other">Open Wi-Fi networks available</item>
-    </plurals>
-
     <!-- A notification is shown when a wifi captive portal network is detected.  This is the notification's title. -->
     <string name="wifi_available_sign_in">Sign in to Wi-Fi network</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index cd3c0e3..f44b039 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -213,6 +213,7 @@
   <java-symbol type="id" name="selection_start_handle" />
   <java-symbol type="id" name="selection_end_handle" />
   <java-symbol type="id" name="insertion_handle" />
+  <java-symbol type="id" name="accessibilityActionClickOnClickableSpan" />
 
   <java-symbol type="attr" name="actionModeShareDrawable" />
   <java-symbol type="attr" name="alertDialogCenterButtons" />
@@ -1803,6 +1804,9 @@
   <java-symbol type="integer" name="config_screenBrightnessSettingMinimum" />
   <java-symbol type="integer" name="config_screenBrightnessSettingMaximum" />
   <java-symbol type="integer" name="config_screenBrightnessSettingDefault" />
+  <java-symbol type="integer" name="config_screenBrightnessForVrSettingDefault" />
+  <java-symbol type="integer" name="config_screenBrightnessForVrSettingMaximum" />
+  <java-symbol type="integer" name="config_screenBrightnessForVrSettingMinimum" />
   <java-symbol type="integer" name="config_screenBrightnessDark" />
   <java-symbol type="integer" name="config_screenBrightnessDim" />
   <java-symbol type="integer" name="config_screenBrightnessDoze" />
@@ -1816,8 +1820,6 @@
   <java-symbol type="layout" name="safe_mode" />
   <java-symbol type="layout" name="simple_list_item_2_single_choice" />
   <java-symbol type="layout" name="app_error_dialog" />
-  <java-symbol type="plurals" name="wifi_available" />
-  <java-symbol type="plurals" name="wifi_available_detailed" />
   <java-symbol type="string" name="accessibility_binding_label" />
   <java-symbol type="string" name="adb_active_notification_message" />
   <java-symbol type="string" name="adb_active_notification_title" />
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index e3a85b5..504541d 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -55,6 +55,8 @@
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
     <uses-permission android:name="android.permission.READ_CONTACTS" />
+    <uses-permission android:name="android.permission.READ_DREAM_STATE" />
+    <uses-permission android:name="android.permission.WRITE_DREAM_STATE" />
     <uses-permission android:name="android.permission.READ_LOGS"/>
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
     <uses-permission android:name="android.permission.READ_SMS"/>
@@ -831,14 +833,14 @@
             </intent-filter>
         </activity>
 
-	    <activity android:name="android.widget.listview.ListManagedCursor" android:label="ListManagedCursor">
+      <activity android:name="android.widget.listview.ListManagedCursor" android:label="ListManagedCursor">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
             </intent-filter>
         </activity>
 
-	    <activity android:name="android.widget.listview.ListWithEmptyView" android:label="ListWithEmptyView">
+      <activity android:name="android.widget.listview.ListWithEmptyView" android:label="ListWithEmptyView">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
@@ -1331,6 +1333,27 @@
             </meta-data>
         </service>
 
+        <activity
+            android:name="android.print.mockservice.SettingsActivity"
+            android:permission="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"
+            android:exported="true">
+        </activity>
+
+        <activity
+            android:name="android.os.TestVrActivity"
+            android:enableVrMode="com.android.frameworks.coretests/android.os.TestVrActivity$TestVrListenerService">
+        </activity>
+
+        <service android:name="android.os.TestVrActivity$TestVrListenerService"
+            android:exported="true"
+            android:enabled="true"
+            android:label="Test Vr Listener Service"
+            android:permission="android.permission.BIND_VR_LISTENER_SERVICE">
+            <intent-filter>
+              <action android:name="android.service.vr.VrListenerService" />
+            </intent-filter>
+        </service>
+
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/core/tests/coretests/src/android/os/PowerManagerVrTest.java b/core/tests/coretests/src/android/os/PowerManagerVrTest.java
new file mode 100644
index 0000000..e01e5fa
--- /dev/null
+++ b/core/tests/coretests/src/android/os/PowerManagerVrTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2017 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.os;
+
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.service.dreams.IDreamManager;
+import android.service.dreams.DreamService;
+import android.support.test.filters.MediumTest;
+import android.support.test.filters.SmallTest;
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+ * Tests dream aspects of PowerManager.
+ */
+@MediumTest
+public class PowerManagerVrTest extends ActivityInstrumentationTestCase2<TestVrActivity> {
+    private PowerManager mPm;
+    private IDreamManager mDm;
+    private String mOldVrListener;
+
+    public PowerManagerVrTest() {
+        super(TestVrActivity.class);
+    }
+
+    /**
+     * Setup any common data for the upcoming tests.
+     */
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        Context context = getInstrumentation().getTargetContext();
+        mPm = (PowerManager) getInstrumentation().getTargetContext().getSystemService(
+                Context.POWER_SERVICE);
+        mDm = IDreamManager.Stub.asInterface(
+                ServiceManager.getService(DreamService.DREAM_SERVICE));
+
+        mOldVrListener = setTestVrListener(new ComponentName(
+                context, TestVrActivity.TestVrListenerService.class).flattenToString());
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        if (mDm != null) {
+            mDm.awaken();  // Don't leave the device in the dream state.
+        }
+
+        setTestVrListener(mOldVrListener);
+    }
+
+    /**
+     * Confirm that the setup is good.
+     *
+     * @throws Exception
+     */
+    @SmallTest
+    public void testPreconditions() throws Exception {
+        assertNotNull(mPm);
+        assertNotNull(mDm);
+    }
+
+    /**
+     * Confirm that the system prevents napping while in VR.
+     * Dreaming is controlled by PowerManager, but we use dreamManager to access those features
+     * in order to not require DEVICE_POWER permissions which other tests expect not to have.
+     *
+     * @throws Exception
+     */
+    @SmallTest
+    public void testNap() throws Exception {
+        // For dream to work, we need to wake up the system
+        wakeUpDevice();
+
+        mDm.dream();
+        waitForDreamState(true);
+        assertTrue(mDm.isDreaming());
+        mDm.awaken();
+
+        // awaken() is not immediate so we have to wait for dreaming to stop
+        // before continuing with the test.
+        waitForDreamState(false);
+
+        // set VR Mode to true by starting our VR Activity, then retest the dream.
+        TestVrActivity activity = getActivity();
+        assertTrue(activity.waitForActivityStart());
+
+        try {
+            mDm.dream();
+            waitForDreamState(true);  // wait for dream to turn true with a timeout
+            assertFalse(mDm.isDreaming()); // ensure dream is still false after waiting.
+            mDm.awaken();
+        } finally {
+            activity.finish();
+        }
+    }
+
+    /**
+     * Waits synchronously for the system to be set to the specified dream state.
+     */
+    private void waitForDreamState(boolean isDreaming) throws Exception {
+        final int MAX_ATTEMPTS = 10;
+        final int WAIT_TIME_PER_ATTEMPT_MILLIS = 100;
+        for (int i = 0; i < MAX_ATTEMPTS; i++) {
+          if (mDm.isDreaming() == isDreaming) {
+            break;
+          }
+          Thread.sleep(WAIT_TIME_PER_ATTEMPT_MILLIS);
+        }
+    }
+
+    private void wakeUpDevice() {
+        PowerManager.WakeLock wl = mPm.newWakeLock(
+                PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP
+                | PowerManager.ON_AFTER_RELEASE, "FULL_WAKE_LOCK");
+        wl.acquire();
+        wl.release();
+    }
+
+    /**
+     * Sets a new value for the enabled VrListenerService and returns the previous value.
+     */
+    private String setTestVrListener(String newValue) {
+        final String ENABLED_VR_LISTENERS = "enabled_vr_listeners";
+        Context context = getInstrumentation().getTargetContext();
+        ContentResolver cr = context.getContentResolver();
+        String oldVrListeners = Settings.Secure.getString(cr, ENABLED_VR_LISTENERS);
+        Settings.Secure.putString(cr, ENABLED_VR_LISTENERS, newValue);
+        return oldVrListeners;
+    }
+}
diff --git a/core/tests/coretests/src/android/os/TestVrActivity.java b/core/tests/coretests/src/android/os/TestVrActivity.java
new file mode 100644
index 0000000..33ff164
--- /dev/null
+++ b/core/tests/coretests/src/android/os/TestVrActivity.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 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.os;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.service.vr.VrListenerService;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * An activity for enabling/disabling VrMode.
+ */
+public class TestVrActivity extends Activity {
+    private CountDownLatch mLatch;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mLatch = new CountDownLatch(1);
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        mLatch.countDown();
+    }
+
+    public static class TestVrListenerService extends VrListenerService {
+        @Override
+        public void onCreate() {
+            super.onCreate();
+        }
+    }
+
+    public boolean waitForActivityStart() {
+        boolean result = false;
+        try {
+            result = mLatch.await(2L, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+        }
+        return result;
+    }
+}
diff --git a/core/tests/coretests/src/android/widget/AppWidgetHostViewTest.java b/core/tests/coretests/src/android/widget/AppWidgetHostViewTest.java
new file mode 100644
index 0000000..1e55fb1
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/AppWidgetHostViewTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2017 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.widget;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetManager;
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+import android.view.ViewGroup.OnHierarchyChangeListener;
+
+import com.android.frameworks.coretests.R;
+
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Future;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for AppWidgetHostView
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class AppWidgetHostViewTest {
+
+    @Rule
+    public final ExpectedException exception = ExpectedException.none();
+
+    private Context mContext;
+    private String mPackage;
+    private AppWidgetHostView mHostView;
+
+    private ViewAddListener mViewAddListener;
+    private RemoteViews mViews;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getContext();
+        mPackage = mContext.getPackageName();
+        mHostView = new AppWidgetHostView(mContext);
+        mHostView.setAppWidget(0, AppWidgetManager.getInstance(
+                mContext).getInstalledProviders().get(0));
+
+        mViewAddListener = new ViewAddListener();
+        mHostView.setOnHierarchyChangeListener(mViewAddListener);
+
+        mViews = new RemoteViews(mPackage, R.layout.remote_views_test);
+    }
+
+    @Test
+    public void syncInflation() {
+        mHostView.updateAppWidget(mViews);
+        assertNotNull(mHostView.findViewById(R.id.image));
+    }
+
+    @Test
+    public void asyncInflation() throws Exception {
+        RunnableList executor = new RunnableList();
+        mHostView.setAsyncExecutor(executor);
+
+        mHostView.updateAppWidget(mViews);
+        assertNull(mHostView.findViewById(R.id.image));
+
+        // Task queued.
+        assertEquals(1, executor.size());
+
+        // Execute the pending task
+        executor.get(0).run();
+        mViewAddListener.addLatch.await();
+        assertNotNull(mHostView.findViewById(R.id.image));
+    }
+
+    @Test
+    public void asyncInflation_cancelled() throws Exception {
+        RunnableList executor = new RunnableList();
+        mHostView.setAsyncExecutor(executor);
+
+        mHostView.updateAppWidget(mViews.clone());
+        mHostView.updateAppWidget(mViews.clone());
+        assertNull(mHostView.findViewById(R.id.image));
+
+        // Tasks queued.
+        assertEquals(2, executor.size());
+        // First task cancelled
+        assertTrue(((Future) executor.get(0)).isCancelled());
+
+        // Execute the pending task
+        executor.get(0).run();
+        executor.get(1).run();
+        mViewAddListener.addLatch.await();
+        assertNotNull(mHostView.findViewById(R.id.image));
+    }
+
+    private static class RunnableList extends ArrayList<Runnable> implements Executor {
+
+        @Override
+        public void execute(Runnable runnable) {
+            add(runnable);
+        }
+    }
+
+    private class ViewAddListener implements OnHierarchyChangeListener {
+
+        public final CountDownLatch addLatch = new CountDownLatch(1);
+
+
+        @Override
+        public void onChildViewAdded(View parent, View child) {
+            addLatch.countDown();
+        }
+
+        @Override
+        public void onChildViewRemoved(View parent, View child) {
+        }
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/LogBuilderTest.java b/core/tests/coretests/src/com/android/internal/logging/LogBuilderTest.java
index e7d23a8..e3f754c 100644
--- a/core/tests/coretests/src/com/android/internal/logging/LogBuilderTest.java
+++ b/core/tests/coretests/src/com/android/internal/logging/LogBuilderTest.java
@@ -5,7 +5,7 @@
 public class LogBuilderTest extends TestCase {
 
     public void testSerialize() {
-        LogBuilder builder = new LogBuilder();
+        LogBuilder builder = new LogBuilder(0);
         builder.addTaggedData(1, "one");
         builder.addTaggedData(2, "two");
         Object[] out = builder.serialize();
@@ -16,7 +16,7 @@
     }
 
     public void testInvalidInputThrows() {
-        LogBuilder builder = new LogBuilder();
+        LogBuilder builder = new LogBuilder(0);
         boolean threw = false;
         try {
             builder.addTaggedData(0, new Object());
@@ -28,7 +28,7 @@
     }
 
     public void testValidInputTypes() {
-        LogBuilder builder = new LogBuilder();
+        LogBuilder builder = new LogBuilder(0);
         builder.addTaggedData(1, "onetwothree");
         builder.addTaggedData(2, 123);
         builder.addTaggedData(3, 123L);
diff --git a/libs/androidfw/BackupData.cpp b/libs/androidfw/BackupData.cpp
index ba4a4ff..76a430e 100644
--- a/libs/androidfw/BackupData.cpp
+++ b/libs/androidfw/BackupData.cpp
@@ -16,14 +16,13 @@
 
 #define LOG_TAG "backup_data"
 
-#include <androidfw/BackupHelpers.h>
-#include <utils/ByteOrder.h>
-
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 
-#include <cutils/log.h>
+#include <androidfw/BackupHelpers.h>
+#include <log/log.h>
+#include <utils/ByteOrder.h>
 
 namespace android {
 
diff --git a/libs/androidfw/BackupHelpers.cpp b/libs/androidfw/BackupHelpers.cpp
index 78e9d91..8bfe2b6 100644
--- a/libs/androidfw/BackupHelpers.cpp
+++ b/libs/androidfw/BackupHelpers.cpp
@@ -18,23 +18,22 @@
 
 #include <androidfw/BackupHelpers.h>
 
-#include <utils/KeyedVector.h>
-#include <utils/ByteOrder.h>
-#include <utils/String8.h>
-
 #include <errno.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <sys/stat.h>
-#include <sys/time.h>  // for utimes
+#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>  // for utimes
+#include <sys/uio.h>
 #include <unistd.h>
 #include <utime.h>
-#include <fcntl.h>
 #include <zlib.h>
 
-#include <cutils/log.h>
+#include <log/log.h>
+#include <utils/ByteOrder.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
 
 namespace android {
 
diff --git a/libs/androidfw/include/androidfw/CursorWindow.h b/libs/androidfw/include/androidfw/CursorWindow.h
index 8a2979a..f543565 100644
--- a/libs/androidfw/include/androidfw/CursorWindow.h
+++ b/libs/androidfw/include/androidfw/CursorWindow.h
@@ -17,11 +17,11 @@
 #ifndef _ANDROID__DATABASE_WINDOW_H
 #define _ANDROID__DATABASE_WINDOW_H
 
-#include <cutils/log.h>
 #include <stddef.h>
 #include <stdint.h>
 
 #include <binder/Parcel.h>
+#include <log/log.h>
 #include <utils/String8.h>
 
 #if LOG_NDEBUG
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 18e59e5..8f7787b 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -75,6 +75,7 @@
     FrameInfo.cpp \
     FrameInfoVisualizer.cpp \
     GammaFontRenderer.cpp \
+    GlLayer.cpp \
     GlopBuilder.cpp \
     GpuMemoryTracker.cpp \
     GradientCache.cpp \
@@ -115,6 +116,7 @@
     Texture.cpp \
     TextureCache.cpp \
     VectorDrawable.cpp \
+    VkLayer.cpp \
     protos/hwui.proto
 
 hwui_test_common_src_files := \
diff --git a/libs/hwui/AnimatorManager.cpp b/libs/hwui/AnimatorManager.cpp
index 9d5860c..f5bb821 100644
--- a/libs/hwui/AnimatorManager.cpp
+++ b/libs/hwui/AnimatorManager.cpp
@@ -142,7 +142,7 @@
 }
 
 uint32_t AnimatorManager::animateCommon(TreeInfo& info) {
-    uint32_t dirtyMask;
+    uint32_t dirtyMask = 0;
     AnimateFunctor functor(info, mAnimationHandle->context(), &dirtyMask);
     auto newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
     mAnimators.erase(newEnd, mAnimators.end());
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index b463e45..a0366de 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -17,7 +17,7 @@
 #include "Caches.h"
 
 #include "GammaFontRenderer.h"
-#include "Layer.h"
+#include "GlLayer.h"
 #include "Properties.h"
 #include "renderstate/RenderState.h"
 #include "ShadowTessellator.h"
@@ -170,9 +170,11 @@
         for (std::set<Layer*>::iterator it = mRenderState->mActiveLayers.begin();
                 it != mRenderState->mActiveLayers.end(); it++) {
             const Layer* layer = *it;
-            log.appendFormat("    Layer size %dx%d; texid=%u refs=%d\n",
+            LOG_ALWAYS_FATAL_IF(layer->getApi() != Layer::Api::OpenGL);
+            const GlLayer* glLayer = static_cast<const GlLayer*>(layer);
+            log.appendFormat("    GlLayer size %dx%d; texid=%u refs=%d\n",
                     layer->getWidth(), layer->getHeight(),
-                    layer->getTextureId(),
+                    glLayer->getTextureId(),
                     layer->getStrongCount());
             memused += layer->getWidth() * layer->getHeight() * 4;
         }
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
index 6d5833b..2b4fe17 100644
--- a/libs/hwui/DamageAccumulator.cpp
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -16,7 +16,7 @@
 
 #include "DamageAccumulator.h"
 
-#include <cutils/log.h>
+#include <log/log.h>
 
 #include "RenderNode.h"
 #include "utils/MathUtils.h"
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index a7d5f60..3e8e8a1 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -15,6 +15,8 @@
  */
 #include "DeferredLayerUpdater.h"
 
+#include "GlLayer.h"
+#include "VkLayer.h"
 #include "renderthread/EglManager.h"
 #include "renderthread/RenderTask.h"
 #include "utils/PaintUtils.h"
@@ -55,13 +57,23 @@
     mLayer->setAlpha(mAlpha, mMode);
 
     if (mSurfaceTexture.get()) {
-        if (mNeedsGLContextAttach) {
-            mNeedsGLContextAttach = false;
-            mSurfaceTexture->attachToContext(mLayer->getTextureId());
-        }
-        if (mUpdateTexImage) {
-            mUpdateTexImage = false;
-            doUpdateTexImage();
+        if (mLayer->getApi() == Layer::Api::Vulkan) {
+            if (mUpdateTexImage) {
+                mUpdateTexImage = false;
+                doUpdateVkTexImage();
+            }
+        } else {
+            LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::OpenGL,
+                                "apply surfaceTexture with non GL backend %x, GL %x, VK %x",
+                                mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
+            if (mNeedsGLContextAttach) {
+                mNeedsGLContextAttach = false;
+                mSurfaceTexture->attachToContext(static_cast<GlLayer*>(mLayer)->getTextureId());
+            }
+            if (mUpdateTexImage) {
+                mUpdateTexImage = false;
+                doUpdateTexImage();
+            }
         }
         if (mTransform) {
             mLayer->getTransform().load(*mTransform);
@@ -71,6 +83,9 @@
 }
 
 void DeferredLayerUpdater::doUpdateTexImage() {
+    LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::OpenGL,
+                        "doUpdateTexImage non GL backend %x, GL %x, VK %x",
+                        mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
     if (mSurfaceTexture->updateTexImage() == NO_ERROR) {
         float transform[16];
 
@@ -110,30 +125,53 @@
     }
 }
 
+void DeferredLayerUpdater::doUpdateVkTexImage() {
+    LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::Vulkan,
+                        "updateLayer non Vulkan backend %x, GL %x, VK %x",
+                        mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
+
+    static const mat4 identityMatrix;
+    updateLayer(false, identityMatrix.data);
+
+    VkLayer* vkLayer = static_cast<VkLayer*>(mLayer);
+    vkLayer->updateTexture();
+}
+
 void DeferredLayerUpdater::updateLayer(bool forceFilter, GLenum renderTarget,
         const float* textureTransform) {
+    LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::OpenGL,
+                        "updateLayer non GL backend %x, GL %x, VK %x",
+                        mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
+
+    updateLayer(forceFilter, textureTransform);
+
+    GlLayer* glLayer = static_cast<GlLayer*>(mLayer);
+    if (renderTarget != glLayer->getRenderTarget()) {
+        glLayer->setRenderTarget(renderTarget);
+        glLayer->bindTexture();
+        glLayer->setFilter(GL_NEAREST, false, true);
+        glLayer->setWrap(GL_CLAMP_TO_EDGE, false, true);
+    }
+}
+
+void DeferredLayerUpdater::updateLayer(bool forceFilter, const float* textureTransform) {
     mLayer->setBlend(mBlend);
     mLayer->setForceFilter(forceFilter);
     mLayer->setSize(mWidth, mHeight);
     mLayer->getTexTransform().load(textureTransform);
-
-    if (renderTarget != mLayer->getRenderTarget()) {
-        mLayer->setRenderTarget(renderTarget);
-        mLayer->bindTexture();
-        mLayer->setFilter(GL_NEAREST, false, true);
-        mLayer->setWrap(GL_CLAMP_TO_EDGE, false, true);
-    }
 }
 
 void DeferredLayerUpdater::detachSurfaceTexture() {
     if (mSurfaceTexture.get()) {
-        status_t err = mSurfaceTexture->detachFromContext();
-        if (err != 0) {
-            // TODO: Elevate to fatal exception
-            ALOGE("Failed to detach SurfaceTexture from context %d", err);
+        if (mLayer->getApi() == Layer::Api::OpenGL) {
+            status_t err = mSurfaceTexture->detachFromContext();
+            if (err != 0) {
+                // TODO: Elevate to fatal exception
+                ALOGE("Failed to detach SurfaceTexture from context %d", err);
+            }
+            static_cast<GlLayer*>(mLayer)->clearTexture();
         }
         mSurfaceTexture = nullptr;
-        mLayer->clearTexture();
     }
 }
 
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 7335008..ead8314 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -22,6 +22,9 @@
 #include <SkMatrix.h>
 #include <utils/StrongPointer.h>
 
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
 #include "Layer.h"
 #include "Rect.h"
 #include "renderthread/RenderThread.h"
@@ -110,6 +113,8 @@
     Layer* mLayer;
 
     void doUpdateTexImage();
+    void doUpdateVkTexImage();
+    void updateLayer(bool forceFilter, const float* textureTransform);
 };
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index 700642e..d180ba5 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -13,16 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include <DeviceInfo.h>
 
 #include "Extensions.h"
 
-#include <GLES2/gl2.h>
-#include <log/log.h>
-
 #include <thread>
 #include <mutex>
 
+#include <log/log.h>
+
+#include <GLES2/gl2.h>
+
 namespace android {
 namespace uirenderer {
 
diff --git a/libs/hwui/GlLayer.cpp b/libs/hwui/GlLayer.cpp
new file mode 100644
index 0000000..c0ab895
--- /dev/null
+++ b/libs/hwui/GlLayer.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include "GlLayer.h"
+
+#include "Caches.h"
+#include "RenderNode.h"
+#include "renderstate/RenderState.h"
+#include "utils/TraceUtils.h"
+
+#include <utils/Log.h>
+
+#define ATRACE_LAYER_WORK(label) \
+    ATRACE_FORMAT("%s HW Layer DisplayList %s %ux%u", \
+            label, \
+            (renderNode.get() != NULL) ? renderNode->getName() : "", \
+            getWidth(), getHeight())
+
+namespace android {
+namespace uirenderer {
+
+GlLayer::GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight)
+        : Layer(renderState, Api::OpenGL)
+        , caches(Caches::getInstance())
+        , texture(caches) {
+    texture.mWidth = layerWidth;
+    texture.mHeight = layerHeight;
+}
+
+GlLayer::~GlLayer() {
+    if (texture.mId) {
+        texture.deleteTexture();
+    }
+}
+
+void GlLayer::onGlContextLost() {
+    texture.deleteTexture();
+}
+
+void GlLayer::bindTexture() const {
+    if (texture.mId) {
+        caches.textureState().bindTexture(texture.target(), texture.mId);
+    }
+}
+
+void GlLayer::generateTexture() {
+    if (!texture.mId) {
+        glGenTextures(1, &texture.mId);
+    }
+}
+
+void GlLayer::clearTexture() {
+    // There's a rare possibility that Caches could have been destroyed already
+    // since this method is queued up as a task.
+    // Since this is a reset method, treat this as non-fatal.
+    if (caches.isInitialized()) {
+        caches.textureState().unbindTexture(texture.mId);
+    }
+    texture.mId = 0;
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/GlLayer.h b/libs/hwui/GlLayer.h
new file mode 100644
index 0000000..54bf5ad
--- /dev/null
+++ b/libs/hwui/GlLayer.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#pragma once
+
+#include "Layer.h"
+
+#include "Texture.h"
+
+namespace android {
+namespace uirenderer {
+
+// Forward declarations
+class Caches;
+
+/**
+ * A layer has dimensions and is backed by an OpenGL texture or FBO.
+ */
+class GlLayer : public Layer {
+public:
+    GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight);
+    virtual ~GlLayer();
+
+    uint32_t getWidth() const override {
+        return texture.mWidth;
+    }
+
+    uint32_t getHeight() const override {
+        return texture.mHeight;
+    }
+
+    void setSize(uint32_t width, uint32_t height) override {
+        texture.updateSize(width, height, texture.internalFormat(), texture.format(),
+                texture.target());
+    }
+
+    void setBlend(bool blend) override {
+        texture.blend = blend;
+    }
+
+    bool isBlend() const override {
+        return texture.blend;
+    }
+
+    inline GLuint getTextureId() const {
+        return texture.id();
+    }
+
+    inline Texture& getTexture() {
+        return texture;
+    }
+
+    inline GLenum getRenderTarget() const {
+        return texture.target();
+    }
+
+    inline void setRenderTarget(GLenum renderTarget) {
+        texture.mTarget = renderTarget;
+    }
+
+    inline bool isRenderable() const {
+        return texture.target() != GL_NONE;
+    }
+
+    void setWrap(GLenum wrap, bool bindTexture = false, bool force = false) {
+        texture.setWrap(wrap, bindTexture, force);
+    }
+
+    void setFilter(GLenum filter, bool bindTexture = false, bool force = false) {
+        texture.setFilter(filter, bindTexture, force);
+    }
+
+    void bindTexture() const;
+    void generateTexture();
+
+    /**
+     * When the caller frees the texture itself, the caller
+     * must call this method to tell this layer that it lost
+     * the texture.
+     */
+    void clearTexture();
+
+    /**
+     * Lost the GL context but the layer is still around, mark it invalid internally
+     * so the dtor knows not to do any GL work
+     */
+    void onGlContextLost();
+
+private:
+    Caches& caches;
+
+    /**
+     * The texture backing this layer.
+     */
+    Texture texture;
+}; // struct GlLayer
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 34e6d39..8a6e038 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -16,6 +16,7 @@
 #include "GlopBuilder.h"
 
 #include "Caches.h"
+#include "GlLayer.h"
 #include "Glop.h"
 #include "Layer.h"
 #include "Matrix.h"
@@ -440,7 +441,7 @@
     return *this;
 }
 
-GlopBuilder& GlopBuilder::setFillTextureLayer(Layer& layer, float alpha) {
+GlopBuilder& GlopBuilder::setFillTextureLayer(GlLayer& layer, float alpha) {
     TRIGGER_STAGE(kFillStage);
     REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
 
diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h
index 8a8b652..87b1568 100644
--- a/libs/hwui/GlopBuilder.h
+++ b/libs/hwui/GlopBuilder.h
@@ -28,6 +28,7 @@
 namespace uirenderer {
 
 class Caches;
+class GlLayer;
 class Matrix4;
 class Patch;
 class RenderState;
@@ -71,7 +72,7 @@
     GlopBuilder& setFillClear();
     GlopBuilder& setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
             float alpha, SkBlendMode mode, Blend::ModeOrderSwap modeUsage);
-    GlopBuilder& setFillTextureLayer(Layer& layer, float alpha);
+    GlopBuilder& setFillTextureLayer(GlLayer& layer, float alpha);
     // TODO: setFillLayer normally forces its own wrap & filter mode,
     // which isn't always correct.
     GlopBuilder& setFillExternalTexture(Texture& texture, Matrix4& textureTransform);
diff --git a/libs/hwui/GpuMemoryTracker.cpp b/libs/hwui/GpuMemoryTracker.cpp
index 4fb5701..a52ec87 100644
--- a/libs/hwui/GpuMemoryTracker.cpp
+++ b/libs/hwui/GpuMemoryTracker.cpp
@@ -67,13 +67,13 @@
     gObjectStats[static_cast<int>(mType)].count--;
 }
 
-void GpuMemoryTracker::onGLContextCreated() {
-    LOG_ALWAYS_FATAL_IF(gGpuThread != 0, "We already have a GL thread? "
-            "current = %lu, gl thread = %lu", pthread_self(), gGpuThread);
+void GpuMemoryTracker::onGpuContextCreated() {
+    LOG_ALWAYS_FATAL_IF(gGpuThread != 0, "We already have a gpu thread? "
+            "current = %lu, gpu thread = %lu", pthread_self(), gGpuThread);
     gGpuThread = pthread_self();
 }
 
-void GpuMemoryTracker::onGLContextDestroyed() {
+void GpuMemoryTracker::onGpuContextDestroyed() {
     gGpuThread = 0;
     if (CC_UNLIKELY(gObjectSet.size() > 0)) {
         std::stringstream os;
diff --git a/libs/hwui/GpuMemoryTracker.h b/libs/hwui/GpuMemoryTracker.h
index bfb1bf1..18e2330 100644
--- a/libs/hwui/GpuMemoryTracker.h
+++ b/libs/hwui/GpuMemoryTracker.h
@@ -15,10 +15,11 @@
  */
 #pragma once
 
-#include <cutils/log.h>
 #include <pthread.h>
 #include <ostream>
 
+#include <log/log.h>
+
 namespace android {
 namespace uirenderer {
 
@@ -43,8 +44,8 @@
     GpuObjectType objectType() { return mType; }
     int objectSize() { return mSize; }
 
-    static void onGLContextCreated();
-    static void onGLContextDestroyed();
+    static void onGpuContextCreated();
+    static void onGpuContextDestroyed();
     static void dump();
     static void dump(std::ostream& stream);
     static int getInstanceCount(GpuObjectType type);
diff --git a/libs/hwui/Interpolator.cpp b/libs/hwui/Interpolator.cpp
index f94a22d..d740c03 100644
--- a/libs/hwui/Interpolator.cpp
+++ b/libs/hwui/Interpolator.cpp
@@ -16,10 +16,11 @@
 
 #include "Interpolator.h"
 
-#include "utils/MathUtils.h"
-
 #include <algorithm>
-#include <cutils/log.h>
+
+#include <log/log.h>
+
+#include "utils/MathUtils.h"
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index ed6b211..0a9bf54 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -15,19 +15,21 @@
  */
 #include "JankTracker.h"
 
-#include "Properties.h"
-#include "utils/TimeUtils.h"
-
-#include <algorithm>
-#include <cutils/ashmem.h>
-#include <cutils/log.h>
-#include <cstdio>
 #include <errno.h>
 #include <inttypes.h>
-#include <limits>
+
+#include <algorithm>
 #include <cmath>
+#include <cstdio>
+#include <limits>
 #include <sys/mman.h>
 
+#include <cutils/ashmem.h>
+#include <log/log.h>
+
+#include "Properties.h"
+#include "utils/TimeUtils.h"
+
 namespace android {
 namespace uirenderer {
 
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 88817ef..331bb81 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -16,77 +16,36 @@
 
 #include "Layer.h"
 
-#include "Caches.h"
-#include "RenderNode.h"
 #include "renderstate/RenderState.h"
-#include "utils/TraceUtils.h"
 
-#include <utils/Log.h>
-
-#define ATRACE_LAYER_WORK(label) \
-    ATRACE_FORMAT("%s HW Layer DisplayList %s %ux%u", \
-            label, \
-            (renderNode.get() != NULL) ? renderNode->getName() : "", \
-            getWidth(), getHeight())
+#include <SkColorFilter.h>
 
 namespace android {
 namespace uirenderer {
 
-Layer::Layer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight)
+Layer::Layer(RenderState& renderState, Api api)
         : GpuMemoryTracker(GpuObjectType::Layer)
-        , state(State::Uncached)
-        , caches(Caches::getInstance())
-        , renderState(renderState)
-        , texture(caches) {
+        , mRenderState(renderState)
+        , mApi(api) {
     // TODO: This is a violation of Android's typical ref counting, but it
     // preserves the old inc/dec ref locations. This should be changed...
     incStrong(nullptr);
-    texture.mWidth = layerWidth;
-    texture.mHeight = layerHeight;
+
     renderState.registerLayer(this);
 }
 
 Layer::~Layer() {
-    renderState.unregisterLayer(this);
     SkSafeUnref(colorFilter);
 
-    if (texture.mId) {
-        texture.deleteTexture();
-    }
-}
-
-void Layer::onGlContextLost() {
-    texture.deleteTexture();
+    mRenderState.unregisterLayer(this);
 }
 
 void Layer::setColorFilter(SkColorFilter* filter) {
     SkRefCnt_SafeAssign(colorFilter, filter);
 }
 
-void Layer::bindTexture() const {
-    if (texture.mId) {
-        caches.textureState().bindTexture(texture.target(), texture.mId);
-    }
-}
-
-void Layer::generateTexture() {
-    if (!texture.mId) {
-        glGenTextures(1, &texture.mId);
-    }
-}
-
-void Layer::clearTexture() {
-    // There's a rare possibility that Caches could have been destroyed already
-    // since this method is queued up as a task.
-    // Since this is a reset method, treat this as non-fatal.
-    if (caches.isInitialized()) {
-        caches.textureState().unbindTexture(texture.mId);
-    }
-    texture.mId = 0;
-}
-
 void Layer::postDecStrong() {
-    renderState.postDecStrong(this);
+    mRenderState.postDecStrong(this);
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 8e71cd1..3b639ee 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -16,25 +16,13 @@
 
 #pragma once
 
-#include <cutils/compiler.h>
-#include <sys/types.h>
-#include <utils/StrongPointer.h>
 #include <utils/RefBase.h>
-#include <memory>
-
-#include <GLES2/gl2.h>
 #include <GpuMemoryTracker.h>
 
-#include <ui/Region.h>
-
 #include <SkPaint.h>
 #include <SkBlendMode.h>
 
 #include "Matrix.h"
-#include "Rect.h"
-#include "RenderBuffer.h"
-#include "Texture.h"
-#include "Vertex.h"
 
 namespace android {
 namespace uirenderer {
@@ -43,49 +31,33 @@
 // Layers
 ///////////////////////////////////////////////////////////////////////////////
 
-// Forward declarations
-class Caches;
 class RenderState;
 
 /**
- * A layer has dimensions and is backed by an OpenGL texture or FBO.
+ * A layer has dimensions and is backed by a backend specific texture or framebuffer.
  */
 class Layer : public VirtualLightRefBase, GpuMemoryTracker {
 public:
-    // layer lifecycle, controlled from outside
-    enum class State {
-        Uncached = 0,
-        InCache = 1,
-        FailedToCache = 2,
-        RemovedFromCache = 3,
-        DeletedFromCache = 4,
-        InGarbageList = 5,
+    enum class Api {
+        OpenGL = 0,
+        Vulkan = 1,
     };
-    State state; // public for logging/debugging purposes
 
-    Layer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight);
+    Api getApi() const {
+        return mApi;
+    }
+
     ~Layer();
 
-    inline uint32_t getWidth() const {
-        return texture.mWidth;
-    }
+    virtual uint32_t getWidth() const = 0;
 
-    inline uint32_t getHeight() const {
-        return texture.mHeight;
-    }
+    virtual uint32_t getHeight() const = 0;
 
-    void setSize(uint32_t width, uint32_t height) {
-        texture.updateSize(width, height, texture.internalFormat(), texture.format(),
-                texture.target());
-    }
+    virtual void setSize(uint32_t width, uint32_t height) = 0;
 
-    inline void setBlend(bool blend) {
-        texture.blend = blend;
-    }
+    virtual void setBlend(bool blend) = 0;
 
-    inline bool isBlend() const {
-        return texture.blend;
-    }
+    virtual bool isBlend() const = 0;
 
     inline void setForceFilter(bool forceFilter) {
         this->forceFilter = forceFilter;
@@ -112,50 +84,12 @@
         return mode;
     }
 
-    inline GLuint getTextureId() const {
-        return texture.id();
-    }
-
-    inline Texture& getTexture() {
-        return texture;
-    }
-
-    inline GLenum getRenderTarget() const {
-        return texture.target();
-    }
-
-    inline void setRenderTarget(GLenum renderTarget) {
-        texture.mTarget = renderTarget;
-    }
-
-    inline bool isRenderable() const {
-        return texture.target() != GL_NONE;
-    }
-
-    void setWrap(GLenum wrap, bool bindTexture = false, bool force = false) {
-        texture.setWrap(wrap, bindTexture, force);
-    }
-
-    void setFilter(GLenum filter, bool bindTexture = false, bool force = false) {
-        texture.setFilter(filter, bindTexture, force);
-    }
-
     inline SkColorFilter* getColorFilter() const {
         return colorFilter;
     }
 
     void setColorFilter(SkColorFilter* filter);
 
-    void bindTexture() const;
-    void generateTexture();
-
-    /**
-     * When the caller frees the texture itself, the caller
-     * must call this method to tell this layer that it lost
-     * the texture.
-     */
-    void clearTexture();
-
     inline mat4& getTexTransform() {
         return texTransform;
     }
@@ -170,21 +104,13 @@
      */
     void postDecStrong();
 
-    /**
-     * Lost the GL context but the layer is still around, mark it invalid internally
-     * so the dtor knows not to do any GL work
-     */
-    void onGlContextLost();
+protected:
+    Layer(RenderState& renderState, Api api);
+
+    RenderState& mRenderState;
 
 private:
-    Caches& caches;
-
-    RenderState& renderState;
-
-    /**
-     * The texture backing this layer.
-     */
-    Texture texture;
+    Api mApi;
 
     /**
      * Color filter used to draw this layer. Optional.
diff --git a/libs/hwui/OpenGLReadback.cpp b/libs/hwui/OpenGLReadback.cpp
index 938b6ef..c460c0d 100644
--- a/libs/hwui/OpenGLReadback.cpp
+++ b/libs/hwui/OpenGLReadback.cpp
@@ -19,7 +19,7 @@
 #include "Caches.h"
 #include "Image.h"
 #include "GlopBuilder.h"
-#include "Layer.h"
+#include "GlLayer.h"
 #include "renderstate/RenderState.h"
 #include "renderthread/EglManager.h"
 #include "utils/GLUtils.h"
@@ -262,7 +262,7 @@
 }
 
 bool OpenGLReadbackImpl::copyLayerInto(renderthread::RenderThread& renderThread,
-        Layer& layer, SkBitmap* bitmap) {
+        GlLayer& layer, SkBitmap* bitmap) {
     return CopyResult::Success == copyTextureInto(Caches::getInstance(),
             renderThread.renderState(), layer.getTexture(), layer.getTexTransform(),
             Rect(), bitmap);
diff --git a/libs/hwui/OpenGLReadback.h b/libs/hwui/OpenGLReadback.h
index f4ebabc..c9222cf 100644
--- a/libs/hwui/OpenGLReadback.h
+++ b/libs/hwui/OpenGLReadback.h
@@ -22,7 +22,7 @@
 namespace uirenderer {
 
 class Matrix4;
-class Layer;
+class GlLayer;
 
 class OpenGLReadback : public Readback {
 public:
@@ -49,7 +49,7 @@
     /**
      * Copies the layer's contents into the provided bitmap.
      */
-    static bool copyLayerInto(renderthread::RenderThread& renderThread, Layer& layer,
+    static bool copyLayerInto(renderthread::RenderThread& renderThread, GlLayer& layer,
             SkBitmap* bitmap);
 
 protected:
diff --git a/libs/hwui/PixelBuffer.h b/libs/hwui/PixelBuffer.h
index 9536bc8..77d5e41 100644
--- a/libs/hwui/PixelBuffer.h
+++ b/libs/hwui/PixelBuffer.h
@@ -18,7 +18,8 @@
 #define ANDROID_HWUI_PIXEL_BUFFER_H
 
 #include <GLES3/gl3.h>
-#include <cutils/log.h>
+
+#include <log/log.h>
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 848161e..a766381 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -13,17 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include "Properties.h"
-
 #include "Debug.h"
 
-#include <cutils/compiler.h>
-#include <cutils/log.h>
-#include <cutils/properties.h>
-
 #include <algorithm>
 #include <cstdlib>
 
+#include <log/log.h>
+#include <cutils/compiler.h>
+#include <cutils/properties.h>
+
 namespace android {
 namespace uirenderer {
 
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index f9a7c36f2..dea2be6 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include "font/FontUtil.h"
+#include "GlLayer.h"
 #include "Matrix.h"
 #include "Rect.h"
 #include "RenderNode.h"
@@ -413,7 +414,7 @@
 };
 
 struct TextureLayerOp : RecordedOp {
-    TextureLayerOp(BASE_PARAMS_PAINTLESS, Layer* layer)
+    TextureLayerOp(BASE_PARAMS_PAINTLESS, GlLayer* layer)
             : SUPER_PAINTLESS(TextureLayerOp)
             , layer(layer) {}
 
@@ -424,7 +425,7 @@
             , layer(op.layer) {
 
     }
-    Layer* layer;
+    GlLayer* layer;
 };
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index ee6279d..b5e5d68 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -606,13 +606,14 @@
     // We ref the DeferredLayerUpdater due to its thread-safe ref-counting semantics.
     mDisplayList->ref(layerHandle);
 
+    LOG_ALWAYS_FATAL_IF(layerHandle->backingLayer()->getApi() != Layer::Api::OpenGL);
     // Note that the backing layer has *not* yet been updated, so don't trust
     // its width, height, transform, etc...!
     addOp(alloc().create_trivial<TextureLayerOp>(
             Rect(layerHandle->getWidth(), layerHandle->getHeight()),
             *(mState.currentSnapshot()->transform),
             getRecordedClip(),
-            layerHandle->backingLayer()));
+            static_cast<GlLayer*>(layerHandle->backingLayer())));
 }
 
 void RecordingCanvas::callDrawGLFunction(Functor* functor,
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index c5156cf..f32612d 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -16,9 +16,11 @@
 
 #include "SkiaCanvasProxy.h"
 
-#include "hwui/Bitmap.h"
+#include <memory>
 
-#include <cutils/log.h>
+#include <log/log.h>
+
+#include "hwui/Bitmap.h"
 #include <SkLatticeIter.h>
 #include <SkPatchUtils.h>
 #include <SkPaint.h>
@@ -30,8 +32,6 @@
 #include <SkSurface.h>
 #include <SkTextBlobRunIterator.h>
 
-#include <memory>
-
 namespace android {
 namespace uirenderer {
 
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index fadb960..9239986 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -18,7 +18,6 @@
 
 #include "Caches.h"
 #include "Extensions.h"
-#include "Layer.h"
 #include "Matrix.h"
 #include "Texture.h"
 #include "hwui/Bitmap.h"
@@ -317,42 +316,6 @@
     return true;
 }
 
-bool tryStoreLayer(Caches& caches, const SkShader& shader, const Matrix4& modelViewMatrix,
-        GLuint* textureUnit, ProgramDescription* description,
-        SkiaShaderData::LayerShaderData* outData) {
-    Layer* layer;
-    if (!shader.asACustomShader(reinterpret_cast<void**>(&layer))) {
-        return false;
-    }
-
-    description->hasBitmap = true;
-    outData->layer = layer;
-    outData->bitmapSampler = (*textureUnit)++;
-
-    const float width = layer->getWidth();
-    const float height = layer->getHeight();
-
-    computeScreenSpaceMatrix(outData->textureTransform, SkMatrix::I(), shader.getLocalMatrix(),
-            modelViewMatrix);
-
-    outData->textureDimension[0] = 1.0f / width;
-    outData->textureDimension[1] = 1.0f / height;
-    return true;
-}
-
-void applyLayer(Caches& caches, const SkiaShaderData::LayerShaderData& data) {
-    caches.textureState().activateTexture(data.bitmapSampler);
-
-    data.layer->bindTexture();
-    data.layer->setWrap(GL_CLAMP_TO_EDGE);
-    data.layer->setFilter(GL_LINEAR);
-
-    glUniform1i(caches.program().getUniform("bitmapSampler"), data.bitmapSampler);
-    glUniformMatrix4fv(caches.program().getUniform("textureTransform"), 1,
-            GL_FALSE, &data.textureTransform.data[0]);
-    glUniform2fv(caches.program().getUniform("textureDimension"), 1, &data.textureDimension[0]);
-}
-
 void SkiaShader::store(Caches& caches, const SkShader& shader, const Matrix4& modelViewMatrix,
         GLuint* textureUnit, ProgramDescription* description,
         SkiaShaderData* outData) {
@@ -374,12 +337,6 @@
         return;
     }
 
-    if (tryStoreLayer(caches, shader, modelViewMatrix,
-            textureUnit, description, &outData->layerData)) {
-        outData->skiaShaderType = kLayer_SkiaShaderType;
-        return;
-    }
-
     // Unknown/unsupported type, so explicitly ignore shader
     outData->skiaShaderType = kNone_SkiaShaderType;
 }
@@ -394,10 +351,6 @@
     if (data.skiaShaderType & kBitmap_SkiaShaderType) {
         applyBitmap(caches, data.bitmapData);
     }
-
-    if (data.skiaShaderType == kLayer_SkiaShaderType) {
-        applyLayer(caches, data.layerData);
-    }
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index d2f37cd..ab578d5 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -29,7 +29,6 @@
 
 class Caches;
 class Extensions;
-class Layer;
 class Texture;
 struct ProgramDescription;
 
@@ -45,7 +44,6 @@
     kBitmap_SkiaShaderType = 1,
     kGradient_SkiaShaderType = 2,
     kCompose_SkiaShaderType = kBitmap_SkiaShaderType | kGradient_SkiaShaderType,
-    kLayer_SkiaShaderType = 4,
 };
 
 struct SkiaShaderData {
@@ -71,15 +69,6 @@
         GLuint gradientSampler;
         GLenum wrapST;
     } gradientData;
-    struct LayerShaderData {
-        Layer* layer;
-        GLuint bitmapSampler;
-        GLenum wrapS;
-        GLenum wrapT;
-
-        Matrix4 textureTransform;
-        float textureDimension[2];
-    } layerData;
 };
 
 class SkiaShader {
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index c75e88f..b8397cc 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -159,10 +159,10 @@
      */
     void* isInUse = nullptr;
 private:
-    // TODO: Temporarily grant private access to Layer, remove once
-    // Layer can be de-tangled from being a dual-purpose render target
+    // TODO: Temporarily grant private access to GlLayer, remove once
+    // GlLayer can be de-tangled from being a dual-purpose render target
     // and external texture wrapper
-    friend class Layer;
+    friend class GlLayer;
 
     // Returns true if the size changed, false if it was the same
     bool updateSize(uint32_t width, uint32_t height, GLint internalFormat,
diff --git a/libs/hwui/VkLayer.cpp b/libs/hwui/VkLayer.cpp
new file mode 100644
index 0000000..391acf1
--- /dev/null
+++ b/libs/hwui/VkLayer.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include "VkLayer.h"
+
+#include "renderstate/RenderState.h"
+
+#include <SkCanvas.h>
+#include <SkSurface.h>
+
+namespace android {
+namespace uirenderer {
+
+void VkLayer::updateTexture() {
+    sk_sp<SkSurface> surface;
+    SkImageInfo info = SkImageInfo::MakeS32(mWidth, mHeight, kPremul_SkAlphaType);
+    surface = SkSurface::MakeRenderTarget(mRenderState.getGrContext(), SkBudgeted::kNo, info);
+    surface->getCanvas()->clear(SK_ColorBLUE);
+    mImage = surface->makeImageSnapshot(SkBudgeted::kNo, SkSurface::kNo_ForceUnique);
+}
+
+void VkLayer::onVkContextDestroyed() {
+    mImage = nullptr;
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/VkLayer.h b/libs/hwui/VkLayer.h
new file mode 100644
index 0000000..39522b3
--- /dev/null
+++ b/libs/hwui/VkLayer.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#pragma once
+
+#include "Layer.h"
+
+#include <SkImage.h>
+
+namespace android {
+namespace uirenderer {
+/**
+ * A layer has dimensions and is backed by a VkImage.
+ */
+class VkLayer : public Layer {
+public:
+    VkLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight)
+            : Layer(renderState, Api::Vulkan) {}
+
+    virtual ~VkLayer() {}
+
+    uint32_t getWidth() const override {
+        return mWidth;
+    }
+
+    uint32_t getHeight() const override {
+        return mHeight;
+    }
+
+    void setSize(uint32_t width, uint32_t height) override {
+        mWidth = width;
+        mHeight = height;
+    }
+
+    void setBlend(bool blend) override {
+        mBlend = blend;
+    }
+
+    bool isBlend() const override {
+        return mBlend;
+    }
+
+    sk_sp<SkImage> getImage() {
+        return mImage;
+    }
+
+    void updateTexture();
+
+    // If we've destroyed the vulkan context (VkInstance, VkDevice, etc.), we must make sure to
+    // destroy any VkImages that were made with that context.
+    void onVkContextDestroyed();
+
+private:
+    int mWidth;
+    int mHeight;
+    bool mBlend;
+
+   sk_sp<SkImage> mImage;
+
+}; // struct VkLayer
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index f172473..956f66e 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -16,9 +16,10 @@
 
 #include "MinikinSkia.h"
 
+#include <log/log.h>
+
 #include <SkPaint.h>
 #include <SkTypeface.h>
-#include <cutils/log.h>
 
 namespace android {
 
diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp
index 8dd165c..713e509 100644
--- a/libs/hwui/hwui/MinikinUtils.cpp
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -13,15 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include "MinikinUtils.h"
 
+#include <string>
+
+#include <log/log.h>
+
 #include "Paint.h"
 #include "SkPathMeasure.h"
 #include "Typeface.h"
 
-#include <cutils/log.h>
-#include <string>
-
 namespace android {
 
 minikin::FontStyle MinikinUtils::prepareMinikinPaint(minikin::MinikinPaint* minikinPaint,
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index fb2134c..419c8a9 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -52,6 +52,11 @@
 
     canvas->flush();
 
+    if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
+        canvas->clear(SK_ColorRED);
+        return;
+    }
+
     SkImageInfo canvasInfo = canvas->imageInfo();
     SkMatrix44 mat4(canvas->getTotalMatrix());
 
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index f2af4a8..2ebfbcc 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -14,8 +14,12 @@
  * limitations under the License.
  */
 
+#include "GlLayer.h"
 #include "LayerDrawable.h"
+#include "VkLayer.h"
+
 #include "SkColorFilter.h"
+#include "SkSurface.h"
 #include "gl/GrGLTypes.h"
 
 namespace android {
@@ -35,16 +39,27 @@
         layer->getTransform().copyTo(transform);
         canvas->concat(transform);
     }
-    GrGLTextureInfo externalTexture;
-    externalTexture.fTarget = layer->getRenderTarget();
-    externalTexture.fID = layer->getTextureId();
-    GrBackendTextureDesc textureDescription;
-    textureDescription.fWidth = layer->getWidth();
-    textureDescription.fHeight = layer->getHeight();
-    textureDescription.fConfig = kRGBA_8888_GrPixelConfig;
-    textureDescription.fOrigin = kTopLeft_GrSurfaceOrigin;
-    textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&externalTexture);
-    sk_sp<SkImage> layerImage = SkImage::MakeFromTexture(context, textureDescription);
+
+    sk_sp<SkImage> layerImage;
+    if (layer->getApi() == Layer::Api::OpenGL) {
+        GlLayer* glLayer = static_cast<GlLayer*>(layer);
+        GrGLTextureInfo externalTexture;
+        externalTexture.fTarget = glLayer->getRenderTarget();
+        externalTexture.fID = glLayer->getTextureId();
+        GrBackendTextureDesc textureDescription;
+        textureDescription.fWidth = glLayer->getWidth();
+        textureDescription.fHeight = glLayer->getHeight();
+        textureDescription.fConfig = kRGBA_8888_GrPixelConfig;
+        textureDescription.fOrigin = kTopLeft_GrSurfaceOrigin;
+        textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&externalTexture);
+        layerImage = SkImage::MakeFromTexture(context, textureDescription);
+    } else {
+        SkASSERT(layer->getApi() == Layer::Api::Vulkan);
+        VkLayer* vkLayer = static_cast<VkLayer*>(layer);
+        canvas->clear(SK_ColorGREEN);
+        layerImage = vkLayer->getImage();
+    }
+
     if (layerImage) {
         SkPaint paint;
         paint.setAlpha(layer->getAlpha());
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index c8258f7..65a1dc3 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -17,6 +17,7 @@
 #include "SkiaOpenGLPipeline.h"
 
 #include "DeferredLayerUpdater.h"
+#include "GlLayer.h"
 #include "LayerDrawable.h"
 #include "renderthread/EglManager.h"
 #include "renderthread/Frame.h"
@@ -136,7 +137,7 @@
 
 DeferredLayerUpdater* SkiaOpenGLPipeline::createTextureLayer() {
     mEglManager.initialize();
-    Layer* layer = new Layer(mRenderThread.renderState(), 0, 0);
+    GlLayer* layer = new GlLayer(mRenderThread.renderState(), 0, 0);
     layer->generateTexture();
     return new DeferredLayerUpdater(layer);
 }
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 0d3f4ef..910c339 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -22,6 +22,7 @@
 #include "renderstate/RenderState.h"
 #include "SkiaPipeline.h"
 #include "SkiaProfileRenderer.h"
+#include "VkLayer.h"
 
 #include <SkSurface.h>
 #include <SkTypes.h>
@@ -119,7 +120,8 @@
 
 DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() {
     mVkManager.initialize();
-    Layer* layer = new Layer(mRenderThread.renderState(), 0, 0);
+
+    VkLayer* layer = new VkLayer(mRenderThread.renderState(), 0, 0);
     return new DeferredLayerUpdater(layer);
 }
 
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index 72af7c9..17ee390 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -13,6 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include "GlLayer.h"
+#include "VkLayer.h"
 #include <GpuMemoryTracker.h>
 #include "renderstate/RenderState.h"
 
@@ -40,7 +42,7 @@
 void RenderState::onGLContextCreated() {
     LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
             "State object lifecycle not managed correctly");
-    GpuMemoryTracker::onGLContextCreated();
+    GpuMemoryTracker::onGpuContextCreated();
 
     mBlend = new Blend();
     mMeshState = new MeshState();
@@ -55,7 +57,9 @@
 }
 
 static void layerLostGlContext(Layer* layer) {
-    layer->onGlContextLost();
+    LOG_ALWAYS_FATAL_IF(layer->getApi() != Layer::Api::OpenGL,
+            "layerLostGlContext on non GL layer");
+    static_cast<GlLayer*>(layer)->onGlContextLost();
 }
 
 void RenderState::onGLContextDestroyed() {
@@ -75,7 +79,29 @@
     delete mStencil;
     mStencil = nullptr;
 
-    GpuMemoryTracker::onGLContextDestroyed();
+    GpuMemoryTracker::onGpuContextDestroyed();
+}
+
+void RenderState::onVkContextCreated() {
+    LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
+            "State object lifecycle not managed correctly");
+    GpuMemoryTracker::onGpuContextCreated();
+}
+
+static void layerDestroyedVkContext(Layer* layer) {
+    LOG_ALWAYS_FATAL_IF(layer->getApi() != Layer::Api::Vulkan,
+                        "layerLostVkContext on non Vulkan layer");
+    static_cast<VkLayer*>(layer)->onVkContextDestroyed();
+}
+
+void RenderState::onVkContextDestroyed() {
+    mLayerPool.clear();
+    std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerDestroyedVkContext);
+    GpuMemoryTracker::onGpuContextDestroyed();
+}
+
+GrContext* RenderState::getGrContext() const {
+    return mRenderThread.getGrContext();
 }
 
 void RenderState::flush(Caches::FlushMode mode) {
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index 3d119dc..d183a15 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -35,6 +35,8 @@
 #include <utils/RefBase.h>
 #include <private/hwui/DrawGlInfo.h>
 
+class GrContext;
+
 namespace android {
 namespace uirenderer {
 
@@ -56,6 +58,9 @@
     void onGLContextCreated();
     void onGLContextDestroyed();
 
+    void onVkContextCreated();
+    void onVkContextDestroyed();
+
     void flush(Caches::FlushMode flushMode);
 
     void setViewport(GLsizei width, GLsizei height);
@@ -98,6 +103,8 @@
 
     OffscreenBufferPool& layerPool() { return mLayerPool; }
 
+    GrContext* getGrContext() const;
+
     void dump();
 
 private:
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index df08599..df40a44 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -19,6 +19,7 @@
 #include "DeferredLayerUpdater.h"
 #include "EglManager.h"
 #include "Frame.h"
+#include "GlLayer.h"
 #include "ProfileRenderer.h"
 #include "renderstate/RenderState.h"
 #include "OpenGLReadback.h"
@@ -120,12 +121,13 @@
 bool OpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
     ATRACE_CALL();
     layer->apply();
-    return OpenGLReadbackImpl::copyLayerInto(mRenderThread, *(layer->backingLayer()), bitmap);
+    return OpenGLReadbackImpl::copyLayerInto(mRenderThread,
+            static_cast<GlLayer&>(*layer->backingLayer()), bitmap);
 }
 
 DeferredLayerUpdater* OpenGLPipeline::createTextureLayer() {
     mEglManager.initialize();
-    Layer* layer = new Layer(mRenderThread.renderState(), 0, 0);
+    GlLayer* layer = new GlLayer(mRenderThread.renderState(), 0, 0);
     Caches::getInstance().textureState().activateTexture(0);
     layer->generateTexture();
 
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 68c04af..2b90744 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -19,6 +19,7 @@
 #include "DeviceInfo.h"
 #include "Properties.h"
 #include "RenderThread.h"
+#include "renderstate/RenderState.h"
 
 #include <GrContext.h>
 #include <GrTypes.h>
@@ -37,10 +38,14 @@
 void VulkanManager::destroy() {
     if (!hasVkContext()) return;
 
+    mRenderThread.renderState().onVkContextDestroyed();
+    mRenderThread.setGrContext(nullptr);
+
     if (VK_NULL_HANDLE != mCommandPool) {
         mDestroyCommandPool(mBackendContext->fDevice, mCommandPool, nullptr);
         mCommandPool = VK_NULL_HANDLE;
     }
+    mBackendContext.reset();
 }
 
 void VulkanManager::initialize() {
@@ -105,6 +110,8 @@
     if (Properties::enablePartialUpdates && Properties::useBufferAge) {
         mSwapBehavior = SwapBehavior::BufferAge;
     }
+
+    mRenderThread.renderState().onVkContextCreated();
 }
 
 // Returns the next BackbufferInfo to use for the next draw. The function will make sure all
@@ -156,6 +163,9 @@
         if (!createSwapchain(surface)) {
             return nullptr;
         }
+        backbuffer = getAvailableBackbuffer(surface);
+        res = mResetFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences);
+        SkASSERT(VK_SUCCESS == res);
 
         // acquire the image
         res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX,
diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
index 0326aa9..f1b8882 100644
--- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
+++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "DeferredLayerUpdater.h"
+#include "GlLayer.h"
 
 #include "renderthread/OpenGLPipeline.h"
 #include "tests/common/TestUtils.h"
@@ -32,7 +33,10 @@
 
 
     // updates are deferred so the backing layer should still be in its default state
-    EXPECT_EQ((uint32_t)GL_NONE, layerUpdater->backingLayer()->getRenderTarget());
+    if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
+        GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer());
+        EXPECT_EQ((uint32_t)GL_NONE, glLayer->getRenderTarget());
+    }
     EXPECT_EQ(0u, layerUpdater->backingLayer()->getWidth());
     EXPECT_EQ(0u, layerUpdater->backingLayer()->getHeight());
     EXPECT_FALSE(layerUpdater->backingLayer()->getForceFilter());
@@ -45,7 +49,10 @@
     layerUpdater->updateLayer(true, GL_TEXTURE_EXTERNAL_OES, scaledMatrix.data);
 
     // the backing layer should now have all the properties applied.
-    EXPECT_EQ((uint32_t)GL_TEXTURE_EXTERNAL_OES, layerUpdater->backingLayer()->getRenderTarget());
+    if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
+        GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer());
+        EXPECT_EQ((uint32_t)GL_TEXTURE_EXTERNAL_OES, glLayer->getRenderTarget());
+    }
     EXPECT_EQ(100u, layerUpdater->backingLayer()->getWidth());
     EXPECT_EQ(100u, layerUpdater->backingLayer()->getHeight());
     EXPECT_TRUE(layerUpdater->backingLayer()->getForceFilter());
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index 21394ae..71c7516 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -19,6 +19,7 @@
 #include <BakedOpState.h>
 #include <DeferredLayerUpdater.h>
 #include <FrameBuilder.h>
+#include <GlLayer.h>
 #include <LayerUpdateQueue.h>
 #include <RecordedOp.h>
 #include <RecordingCanvas.h>
@@ -698,7 +699,10 @@
 RENDERTHREAD_TEST(FrameBuilder, textureLayer_reject) {
     auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
             SkMatrix::MakeTrans(5, 5));
-    layerUpdater->backingLayer()->setRenderTarget(GL_NONE); // Should be rejected
+    if (layerUpdater->backingLayer()->getApi() != Layer::Api::OpenGL) return;
+
+    GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer());
+    glLayer->setRenderTarget(GL_NONE); // Should be rejected
 
     auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
             [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
diff --git a/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp b/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp
index aa1dcb2..8cbd24e 100644
--- a/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp
+++ b/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp
@@ -51,7 +51,7 @@
 TEST(GpuMemoryTracker, sizeCheck) {
     destroyEglContext();
 
-    GpuMemoryTracker::onGLContextCreated();
+    GpuMemoryTracker::onGpuContextCreated();
     ASSERT_EQ(0, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture));
     ASSERT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture));
     {
@@ -66,5 +66,5 @@
     }
     ASSERT_EQ(0, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture));
     ASSERT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture));
-    GpuMemoryTracker::onGLContextDestroyed();
+    GpuMemoryTracker::onGpuContextDestroyed();
 }
diff --git a/libs/hwui/utils/GLUtils.h b/libs/hwui/utils/GLUtils.h
index 94818b2..c127478 100644
--- a/libs/hwui/utils/GLUtils.h
+++ b/libs/hwui/utils/GLUtils.h
@@ -18,7 +18,7 @@
 
 #include "Debug.h"
 
-#include <cutils/log.h>
+#include <log/log.h>
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 0b22ad5..7c60467 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -15,7 +15,6 @@
  */
 
 #define LOG_TAG "PointerController"
-
 //#define LOG_NDEBUG 0
 
 // Log debug messages about pointer updates
@@ -23,8 +22,9 @@
 
 #include "PointerController.h"
 
-#include <cutils/log.h>
+#include <log/log.h>
 
+// ToDo: Fix code to be warning free
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-parameter"
 #include <SkBitmap.h>
diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp
index 18ebd47..4991f04 100644
--- a/libs/input/SpriteController.cpp
+++ b/libs/input/SpriteController.cpp
@@ -15,15 +15,15 @@
  */
 
 #define LOG_TAG "Sprites"
-
 //#define LOG_NDEBUG 0
 
 #include "SpriteController.h"
 
-#include <cutils/log.h>
+#include <log/log.h>
 #include <utils/String8.h>
 #include <gui/Surface.h>
 
+// ToDo: Fix code to be warning free
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-parameter"
 #include <SkBitmap.h>
diff --git a/media/mca/filterpacks/native/base/geometry.cpp b/media/mca/filterpacks/native/base/geometry.cpp
index 7812d502..44b13e4 100644
--- a/media/mca/filterpacks/native/base/geometry.cpp
+++ b/media/mca/filterpacks/native/base/geometry.cpp
@@ -13,10 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define LOG_TAG "geometry"
 
-#include <cutils/log.h>
 #include <cmath>
 
+#include <log/log.h>
+
 #include "geometry.h"
 
 namespace android {
diff --git a/media/mca/filterpacks/native/base/time_util.cpp b/media/mca/filterpacks/native/base/time_util.cpp
index 1a78a95..7d383df 100644
--- a/media/mca/filterpacks/native/base/time_util.cpp
+++ b/media/mca/filterpacks/native/base/time_util.cpp
@@ -13,14 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define LOG_TAG "time_util"
 
 #include "time_util.h"
 #include "utilities.h"
 
-#include <cutils/log.h>
 #include <sys/time.h>
 #include <map>
 
+#include <log/log.h>
+
 namespace android {
 namespace filterfw {
 
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 4154ef0..329514c 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -542,16 +542,27 @@
     }
 
     /**
-     * This method is part of the SurfaceHolder.Callback interface, and is
+     * This method is part of the SurfaceHolder.Callback2 interface, and is
      * not normally called or subclassed by clients of GLSurfaceView.
      */
     @Override
-    public void surfaceRedrawNeeded(SurfaceHolder holder) {
+    public void surfaceRedrawNeededAsync(SurfaceHolder holder, Runnable finishDrawing) {
         if (mGLThread != null) {
-            mGLThread.requestRenderAndWait();
+            mGLThread.requestRenderAndNotify(finishDrawing);
         }
     }
 
+    /**
+     * This method is part of the SurfaceHolder.Callback2 interface, and is
+     * not normally called or subclassed by clients of GLSurfaceView.
+     */
+    @Deprecated
+    @Override
+    public void surfaceRedrawNeeded(SurfaceHolder holder) {
+        // Since we are part of the framework we know only surfaceRedrawNeededAsync
+        // will be called.
+    }
+
 
     /**
      * Pause the rendering thread, optionally tearing down the EGL context
@@ -1305,6 +1316,7 @@
                 int w = 0;
                 int h = 0;
                 Runnable event = null;
+                Runnable finishDrawingRunnable = null;
 
                 while (true) {
                     synchronized (sGLThreadManager) {
@@ -1400,6 +1412,11 @@
                                 sGLThreadManager.notifyAll();
                             }
 
+                            if (mFinishDrawingRunnable != null) {
+                                finishDrawingRunnable = mFinishDrawingRunnable;
+                                mFinishDrawingRunnable = null;
+                            }
+
                             // Ready to draw?
                             if (readyToDraw()) {
 
@@ -1453,7 +1470,6 @@
                                     break;
                                 }
                             }
-
                             // By design, this is the only place in a GLThread thread where we wait().
                             if (LOG_THREADS) {
                                 Log.i("GLThread", "waiting tid=" + getId()
@@ -1546,6 +1562,10 @@
                             try {
                                 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onDrawFrame");
                                 view.mRenderer.onDrawFrame(gl);
+                                if (finishDrawingRunnable != null) {
+                                    finishDrawingRunnable.run();
+                                    finishDrawingRunnable = null;
+                                }
                             } finally {
                                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                             }
@@ -1625,7 +1645,7 @@
             }
         }
 
-        public void requestRenderAndWait() {
+        public void requestRenderAndNotify(Runnable finishDrawing) {
             synchronized(sGLThreadManager) {
                 // If we are already on the GL thread, this means a client callback
                 // has caused reentrancy, for example via updating the SurfaceView parameters.
@@ -1638,17 +1658,9 @@
                 mWantRenderNotification = true;
                 mRequestRender = true;
                 mRenderComplete = false;
+                mFinishDrawingRunnable = finishDrawing;
 
                 sGLThreadManager.notifyAll();
-
-                while (!mExited && !mPaused && !mRenderComplete && ableToDraw()) {
-                    try {
-                        sGLThreadManager.wait();
-                    } catch (InterruptedException ex) {
-                        Thread.currentThread().interrupt();
-                    }
-                }
-
             }
         }
 
@@ -1821,6 +1833,7 @@
         private boolean mRenderComplete;
         private ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>();
         private boolean mSizeChanged = true;
+        private Runnable mFinishDrawingRunnable = null;
 
         // End of member variables protected by the sGLThreadManager monitor.
 
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 8cf375a..cbd295e1 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -287,26 +287,23 @@
         String path = file.getAbsolutePath();
 
         // Find the most-specific root path
-        String mostSpecificId = null;
-        String mostSpecificPath = null;
-        synchronized (mRootsLock) {
-            for (int i = 0; i < mRoots.size(); i++) {
-                final String rootId = mRoots.keyAt(i);
-                final String rootPath = mRoots.valueAt(i).path.getAbsolutePath();
-                if (path.startsWith(rootPath) && (mostSpecificPath == null
-                        || rootPath.length() > mostSpecificPath.length())) {
-                    mostSpecificId = rootId;
-                    mostSpecificPath = rootPath;
-                }
-            }
+        boolean visiblePath = false;
+        RootInfo mostSpecificRoot = getMostSpecificRootForPath(path, false);
+
+        if (mostSpecificRoot == null) {
+            // Try visible path if no internal path matches. MediaStore uses visible paths.
+            visiblePath = true;
+            mostSpecificRoot = getMostSpecificRootForPath(path, true);
         }
 
-        if (mostSpecificPath == null) {
+        if (mostSpecificRoot == null) {
             throw new FileNotFoundException("Failed to find root that contains " + path);
         }
 
         // Start at first char of path under root
-        final String rootPath = mostSpecificPath;
+        final String rootPath = visiblePath
+                ? mostSpecificRoot.visiblePath.getAbsolutePath()
+                : mostSpecificRoot.path.getAbsolutePath();
         if (rootPath.equals(path)) {
             path = "";
         } else if (rootPath.endsWith("/")) {
@@ -322,7 +319,29 @@
             }
         }
 
-        return mostSpecificId + ':' + path;
+        return mostSpecificRoot.rootId + ':' + path;
+    }
+
+    private RootInfo getMostSpecificRootForPath(String path, boolean visible) {
+        // Find the most-specific root path
+        RootInfo mostSpecificRoot = null;
+        String mostSpecificPath = null;
+        synchronized (mRootsLock) {
+            for (int i = 0; i < mRoots.size(); i++) {
+                final RootInfo root = mRoots.valueAt(i);
+                final File rootFile = visible ? root.visiblePath : root.path;
+                if (rootFile != null) {
+                    final String rootPath = rootFile.getAbsolutePath();
+                    if (path.startsWith(rootPath) && (mostSpecificPath == null
+                            || rootPath.length() > mostSpecificPath.length())) {
+                        mostSpecificRoot = root;
+                        mostSpecificPath = rootPath;
+                    }
+                }
+            }
+        }
+
+        return mostSpecificRoot;
     }
 
     private File getFileForDocId(String docId) throws FileNotFoundException {
@@ -519,15 +538,13 @@
                 boolean matchesRequestedDoc = false;
                 if (DocumentsContract.isTreeUri(uri)) {
                     final String parentDocId = DocumentsContract.getTreeDocumentId(uri);
-                    File parentFile = getFileForDocId(parentDocId);
-                    if (FileUtils.contains(parentFile, doc)) {
+                    if (isChildDocument(parentDocId, docId)) {
                         treeUriPermission = uriPermission;
                         matchesRequestedDoc = true;
                     }
                 } else {
                     final String candidateDocId = DocumentsContract.getDocumentId(uri);
-                    final File candidateDoc = getFileForDocId(candidateDocId);
-                    if (Objects.equals(doc.getAbsolutePath(), candidateDoc.getAbsolutePath())) {
+                    if (Objects.equals(docId, candidateDocId)) {
                         docUriPermission = uriPermission;
                         matchesRequestedDoc = true;
                     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageManagerVolumeProvider.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageManagerVolumeProvider.java
index de76279..320494c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageManagerVolumeProvider.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageManagerVolumeProvider.java
@@ -41,4 +41,9 @@
     public List<VolumeInfo> getVolumes() {
         return mStorageManager.getVolumes();
     }
+
+    @Override
+    public VolumeInfo findEmulatedForPrivate(VolumeInfo privateVolume) {
+        return mStorageManager.findEmulatedForPrivate(privateVolume);
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageVolumeProvider.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageVolumeProvider.java
index 95bb18d..646c42f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageVolumeProvider.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageVolumeProvider.java
@@ -34,4 +34,9 @@
      * Returns a list of VolumeInfos for the device.
      */
     List<VolumeInfo> getVolumes();
+
+    /**
+     * Returns the emulated volume for a given private volume.
+     */
+    VolumeInfo findEmulatedForPrivate(VolumeInfo privateVolume);
 }
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 5574753..ff76c56 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -221,6 +221,15 @@
             </intent-filter>
         </receiver>
 
+        <receiver android:name=".SysuiRestartReceiver"
+            android:exported="false">
+            <intent-filter>
+                <action android:name="com.android.systemui.action.RESTART" />
+
+                <data android:scheme="package" />
+            </intent-filter>
+        </receiver>
+
         <service android:name=".ImageWallpaper"
                 android:permission="android.permission.BIND_WALLPAPER"
                 android:exported="true" />
@@ -483,6 +492,21 @@
             android:exported="true"
             android:enabled="@bool/config_enableKeyguardService" />
 
+        <activity android:name=".keyguard.WorkLockActivity"
+                  android:label="@string/accessibility_desc_work_lock"
+                  android:permission="android.permission.MANAGE_USERS"
+                  android:exported="false"
+                  android:launchMode="singleTop"
+                  android:excludeFromRecents="true"
+                  android:stateNotNeeded="true"
+                  android:resumeWhilePausing="true"
+                  android:theme="@android:style/Theme.Black.NoTitleBar">
+            <intent-filter>
+                <action android:name="android.app.action.CONFIRM_DEVICE_CREDENTIAL_WITH_USER" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
         <activity android:name=".Somnambulator"
             android:label="@string/start_dreams"
             android:icon="@mipmap/ic_launcher_dreams"
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
index 388c71d..7b8eae2 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -87,6 +87,21 @@
         isDebuggable = debuggable;
     }
 
+    public PluginInfo<T> getPlugin() {
+        if (Looper.myLooper() != Looper.getMainLooper()) {
+            throw new RuntimeException("Must be called from UI thread");
+        }
+        mPluginHandler.handleQueryPlugins(null /* All packages */);
+        if (mPluginHandler.mPlugins.size() > 0) {
+            mMainHandler.removeMessages(MainHandler.PLUGIN_CONNECTED);
+            PluginInfo<T> info = mPluginHandler.mPlugins.get(0);
+            PluginPrefs.setHasPlugins(mContext);
+            info.mPlugin.onCreate(mContext, info.mPluginContext);
+            return info;
+        }
+        return null;
+    }
+
     public void loadAll() {
         if (DEBUG) Log.d(TAG, "startListening");
         mPluginHandler.sendEmptyMessage(PluginHandler.QUERY_ALL);
@@ -366,11 +381,11 @@
         }
     }
 
-    private static class PluginInfo<T> {
+    static class PluginInfo<T> {
         private final Context mPluginContext;
-        private T mPlugin;
         private String mClass;
-        private String mPackage;
+        T mPlugin;
+        String mPackage;
 
         public PluginInfo(String pkg, String cls, T plugin, Context pluginContext) {
             mPlugin = plugin;
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
index 6096eaf..4714547 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
@@ -14,7 +14,10 @@
 
 package com.android.systemui.plugins;
 
+import android.app.Notification;
+import android.app.Notification.Action;
 import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -23,16 +26,20 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
 import android.net.Uri;
 import android.os.Build;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.plugins.PluginInstanceManager.PluginContextWrapper;
+import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
 
 import dalvik.system.PathClassLoader;
 
@@ -54,11 +61,14 @@
     private final ArrayMap<PluginListener<?>, PluginInstanceManager> mPluginMap
             = new ArrayMap<>();
     private final Map<String, ClassLoader> mClassLoaders = new ArrayMap<>();
+    private final ArraySet<String> mOneShotPackages = new ArraySet<>();
     private final Context mContext;
     private final PluginInstanceManagerFactory mFactory;
     private final boolean isDebuggable;
     private final PluginPrefs mPluginPrefs;
     private ClassLoaderFilter mParentClassLoader;
+    private boolean mListening;
+    private boolean mHasOneShot;
 
     private PluginManager(Context context) {
         this(context, new PluginInstanceManagerFactory(),
@@ -80,6 +90,27 @@
         Thread.setDefaultUncaughtExceptionHandler(uncaughtExceptionHandler);
     }
 
+    public <T extends Plugin> T getOneShotPlugin(String action, int version) {
+        if (!isDebuggable) {
+            // Never ever ever allow these on production builds, they are only for prototyping.
+            return null;
+        }
+        if (Looper.myLooper() != Looper.getMainLooper()) {
+            throw new RuntimeException("Must be called from UI thread");
+        }
+        PluginInstanceManager<T> p = mFactory.createPluginInstanceManager(mContext, action, null,
+                false, mBackgroundThread.getLooper(), version, this);
+        mPluginPrefs.addAction(action);
+        PluginInfo<T> info = p.getPlugin();
+        if (info != null) {
+            mOneShotPackages.add(info.mPackage);
+            mHasOneShot = true;
+            startListening();
+            return info.mPlugin;
+        }
+        return null;
+    }
+
     public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
             int version) {
         addPluginListener(action, listener, version, false);
@@ -96,9 +127,7 @@
                 allowMultiple, mBackgroundThread.getLooper(), version, this);
         p.loadAll();
         mPluginMap.put(listener, p);
-        if (mPluginMap.size() == 1) {
-            startListening();
-        }
+        startListening();
     }
 
     public void removePluginListener(PluginListener<?> listener) {
@@ -108,12 +137,12 @@
         }
         if (!mPluginMap.containsKey(listener)) return;
         mPluginMap.remove(listener).destroy();
-        if (mPluginMap.size() == 0) {
-            stopListening();
-        }
+        stopListening();
     }
 
     private void startListening() {
+        if (mListening) return;
+        mListening = true;
         IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
@@ -126,6 +155,9 @@
     }
 
     private void stopListening() {
+        // Never stop listening if a one-shot is present.
+        if (!mListening || mHasOneShot) return;
+        mListening = false;
         mContext.unregisterReceiver(this);
     }
 
@@ -147,6 +179,34 @@
         } else {
             Uri data = intent.getData();
             String pkg = data.getEncodedSchemeSpecificPart();
+            if (mOneShotPackages.contains(pkg)) {
+                int icon = mContext.getResources().getIdentifier("tuner", "drawable",
+                        mContext.getPackageName());
+                int color = Resources.getSystem().getIdentifier(
+                        "system_notification_accent_color", "color", "android");
+                String label = pkg;
+                try {
+                    PackageManager pm = mContext.getPackageManager();
+                    label = pm.getApplicationInfo(pkg, 0).loadLabel(pm).toString();
+                } catch (NameNotFoundException e) {
+                }
+                // Localization not required as this will never ever appear in a user build.
+                final Notification.Builder nb = new Notification.Builder(mContext)
+                        .setSmallIcon(icon)
+                        .setWhen(0)
+                        .setShowWhen(false)
+                        .setPriority(Notification.PRIORITY_MAX)
+                        .setVisibility(Notification.VISIBILITY_PUBLIC)
+                        .setColor(mContext.getColor(color))
+                        .setContentTitle("Plugin \"" + label + "\" has updated")
+                        .setContentText("Restart SysUI for changes to take effect.");
+                Intent i = new Intent("com.android.systemui.action.RESTART").setData(
+                            Uri.parse("package://" + pkg));
+                PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i, 0);
+                nb.addAction(new Action.Builder(null, "Restart SysUI", pi).build());
+                mContext.getSystemService(NotificationManager.class).notifyAsUser(pkg,
+                        SystemMessage.NOTE_PLUGIN, nb.build(), UserHandle.ALL);
+            }
             clearClassLoader(pkg);
             if (!Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
                 for (PluginInstanceManager manager : mPluginMap.values()) {
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-hdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-hdpi/ic_sysbar_back_dark.png
new file mode 100644
index 0000000..c3aea46
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-sw900dp-hdpi/ic_sysbar_back_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-mdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-mdpi/ic_sysbar_back_dark.png
new file mode 100644
index 0000000..470b3e2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-sw900dp-mdpi/ic_sysbar_back_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back.png
index 94cb032..965d2f5 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back_dark.png
new file mode 100644
index 0000000..e7137c6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxhdpi/ic_sysbar_back_dark.png
new file mode 100644
index 0000000..03dec15
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxhdpi/ic_sysbar_back_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxxhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxxhdpi/ic_sysbar_back_dark.png
new file mode 100644
index 0000000..e1ca853
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxxhdpi/ic_sysbar_back_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_dark.png
new file mode 100644
index 0000000..0520c49
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_ime_dark.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_ime_dark.png
new file mode 100644
index 0000000..3dc2b88
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_ime_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_docked_dark.png
new file mode 100644
index 0000000..2ba5d5b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_docked_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_home_dark.png
new file mode 100644
index 0000000..62dc2d9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_home_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_menu_dark.png
new file mode 100644
index 0000000..e718b7a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_menu_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_recent_dark.png
new file mode 100644
index 0000000..469800a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_recent_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-hdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-land-hdpi/ic_sysbar_docked_dark.png
new file mode 100644
index 0000000..42863c6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-land-hdpi/ic_sysbar_docked_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-mdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-land-mdpi/ic_sysbar_docked_dark.png
new file mode 100644
index 0000000..d9ec9d5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-land-mdpi/ic_sysbar_docked_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-xhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-land-xhdpi/ic_sysbar_docked.png
new file mode 100644
index 0000000..ea7ac93
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-land-xhdpi/ic_sysbar_docked.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-xhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-land-xhdpi/ic_sysbar_docked_dark.png
new file mode 100644
index 0000000..8ee4e43
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-land-xhdpi/ic_sysbar_docked_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-xxhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-land-xxhdpi/ic_sysbar_docked_dark.png
new file mode 100644
index 0000000..dfa8a97
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-land-xxhdpi/ic_sysbar_docked_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-xxxhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-land-xxxhdpi/ic_sysbar_docked_dark.png
new file mode 100644
index 0000000..d23abc7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-land-xxxhdpi/ic_sysbar_docked_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_dark.png
new file mode 100644
index 0000000..8e56e9c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_ime_dark.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_ime_dark.png
new file mode 100644
index 0000000..28a1465
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_ime_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_docked_dark.png
new file mode 100644
index 0000000..0fc9677
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_docked_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_home_dark.png
new file mode 100644
index 0000000..7b81eee
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_home_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_menu_dark.png
new file mode 100644
index 0000000..a6483452
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_menu_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_recent_dark.png
new file mode 100644
index 0000000..7f74521
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_recent_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back.png
index fbdc93c..3b831a3 100644
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_dark.png
new file mode 100644
index 0000000..8c99455
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_ime.png
index 419518c..3c37782 100644
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_docked.png
new file mode 100644
index 0000000..b2baa09
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_docked.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_docked_dark.png
new file mode 100644
index 0000000..b78dc9c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_docked_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home.png
index a2406b1..37590a5 100644
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home_dark.png
new file mode 100644
index 0000000..3a208aa
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_menu_dark.png
new file mode 100644
index 0000000..625ba45
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_menu_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent.png
index c449449..7ad2a29 100644
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent_dark.png
new file mode 100644
index 0000000..604397e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_dark.png
new file mode 100644
index 0000000..274e5df
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_docked_dark.png
new file mode 100644
index 0000000..ac16895
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_docked_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_home_dark.png
new file mode 100644
index 0000000..e69a037
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_home_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_ime_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_ime_dark.png
new file mode 100644
index 0000000..65a4354
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_ime_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_menu_dark.png
new file mode 100644
index 0000000..8bddcd9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_menu_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_recent_dark.png
new file mode 100644
index 0000000..38c5959
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_recent_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_dark.png
new file mode 100644
index 0000000..c6d7c98
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_ime_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_ime_dark.png
new file mode 100644
index 0000000..06c52aa
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_ime_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_docked_dark.png
new file mode 100644
index 0000000..7660997
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_docked_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_home_dark.png
new file mode 100644
index 0000000..0d9ecc2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_home_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_menu_dark.png
new file mode 100644
index 0000000..d6bb8b1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_menu_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_recent_dark.png
new file mode 100644
index 0000000..298ef3a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_recent_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/qs_customize_panel_content.xml b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
index ca0248e..04d0e65 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel_content.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
@@ -27,7 +27,7 @@
 
     <android.support.v7.widget.RecyclerView
         android:id="@android:id/list"
-        android:layout_width="@dimen/notification_panel_width"
+        android:layout_width="match_parent"
         android:layout_height="0dp"
         android:layout_weight="1"
         android:scrollIndicators="top"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 34a0397..05963ac 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -460,6 +460,8 @@
     <string name="accessibility_desc_settings">Settings</string>
     <!-- Content description for the recent apps panel (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_desc_recent_apps">Overview.</string>
+    <!-- Content description for the graphic shown instead of an activity window while the activity is locked (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_desc_work_lock">Work lock screen</string>
     <!-- Content description for the close button in the zen mode panel introduction message. [CHAR LIMIT=NONE] -->
     <string name="accessibility_desc_close">Close</string>
 
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index d109ae1..1988023 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -80,7 +80,6 @@
             ShortcutKeyDispatcher.class,
             VendorServices.class,
             LatencyTester.class,
-            DozeFactory.Initializer.class,
     };
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/SysuiRestartReceiver.java b/packages/SystemUI/src/com/android/systemui/SysuiRestartReceiver.java
new file mode 100644
index 0000000..cdeef2f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/SysuiRestartReceiver.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Process;
+
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+
+public class SysuiRestartReceiver extends BroadcastReceiver {
+
+    public static String ACTION = "com.android.systemui.action.RESTART";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (ACTION.equals(intent.getAction())) {
+            String pkg = intent.getData().toString().substring(10);
+            NotificationManager.from(context).cancel(pkg, SystemMessage.NOTE_PLUGIN);
+            Process.killProcess(Process.myPid());
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 5b10756..f0deaf0 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -34,31 +34,10 @@
 
 public class DozeFactory {
 
-    private static DozeFactory sInstance;
+    private final DozeProvider mDozePlugin;
 
-    private DozeProvider mDozePlugin;
-
-    /** Returns the singleton instance. */
-    public static DozeFactory getInstance(Context context) {
-        if (sInstance == null) {
-            sInstance = new DozeFactory();
-            PluginManager.getInstance(context).addPluginListener(DozeProvider.ACTION,
-                    new PluginListener<DozeProvider>() {
-                        @Override
-                        public void onPluginConnected(DozeProvider plugin) {
-                            sInstance.mDozePlugin = plugin;
-                        }
-
-                        @Override
-                        public void onPluginDisconnected(DozeProvider plugin) {
-                            if (sInstance.mDozePlugin == plugin) {
-                                sInstance.mDozePlugin = null;
-                            }
-                        }
-                    },
-                    DozeProvider.VERSION, false /* Only one */);
-        }
-        return sInstance;
+    public DozeFactory(DozeProvider plugin) {
+        mDozePlugin = plugin;
     }
 
     /** Creates a DozeMachine with its parts for {@code dozeService}. */
@@ -202,13 +181,4 @@
             return mInner.wrap(runnable);
         }
     }
-
-    /** Hack: We need to initialize the plugin listener before doze actually starts.
-     * This will be unnecessary once we have proper one-shot support */
-    public static class Initializer extends SystemUI {
-        @Override
-        public void start() {
-            getInstance(mContext);
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 78b96b3..52f1fb4 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -19,6 +19,10 @@
 import android.service.dreams.DreamService;
 import android.util.Log;
 
+import com.android.systemui.plugins.Plugin;
+import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.plugins.doze.DozeProvider;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
@@ -38,7 +42,9 @@
 
         setWindowless(true);
 
-        mDozeMachine = DozeFactory.getInstance(getApplication()).assembleMachine(this);
+        DozeProvider provider = PluginManager.getInstance(this)
+                .getOneShotPlugin(DozeProvider.ACTION, DozeProvider.VERSION);
+        mDozeMachine = new DozeFactory(provider).assembleMachine(this);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 8e5db97..ce89aab 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -326,6 +326,12 @@
      */
     private boolean mPendingLock;
 
+    /**
+     * Controller for showing individual "work challenge" lock screen windows inside managed profile
+     * tasks when the current user has been unlocked but the profile is still locked.
+     */
+    private WorkLockActivityController mWorkLockController;
+
     private boolean mLockLater;
 
     private boolean mWakeAndUnlocking;
@@ -708,6 +714,8 @@
 
         mHideAnimation = AnimationUtils.loadAnimation(mContext,
                 com.android.internal.R.anim.lock_screen_behind_enter);
+
+        mWorkLockController = new WorkLockActivityController(mContext);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
new file mode 100644
index 0000000..63d1cc2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.keyguard;
+
+import static android.app.ActivityManager.TaskDescription;
+
+import android.annotation.ColorInt;
+import android.annotation.UserIdInt;
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.KeyguardManager;
+import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.View;
+
+/**
+ * Bouncer between work activities and the activity used to confirm credentials before unlocking
+ * a managed profile.
+ * <p>
+ * Shows a solid color when started, based on the organization color of the user it is supposed to
+ * be blocking. Once focused, it switches to a screen to confirm credentials and auto-dismisses if
+ * credentials are accepted.
+ */
+public class WorkLockActivity extends Activity {
+    private static final String TAG = "WorkLockActivity";
+
+    /**
+     * ID of the locked user that this activity blocks access to.
+     */
+    @UserIdInt
+    private int mUserId;
+
+    /**
+     * {@see KeyguardManager}
+     */
+    private KeyguardManager mKgm;
+
+    /**
+     * {@see DevicePolicyManager}
+     */
+    private DevicePolicyManager mDpm;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mUserId = getIntent().getIntExtra(Intent.EXTRA_USER_ID, UserHandle.myUserId());
+        mDpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
+        mKgm = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
+
+        final IntentFilter lockFilter = new IntentFilter();
+        lockFilter.addAction(Intent.ACTION_DEVICE_LOCKED_CHANGED);
+        registerReceiverAsUser(mLockEventReceiver, UserHandle.ALL, lockFilter,
+                /* permission */ null, /* scheduler */ null);
+
+        // Once the receiver is registered, check whether anything happened between now and the time
+        // when this activity was launched. If it did and the user is unlocked now, just quit.
+        if (!mKgm.isDeviceLocked(mUserId)) {
+            finish();
+            return;
+        }
+
+        // Get the organization color; this is a 24-bit integer provided by a DPC, guaranteed to
+        // be completely opaque.
+        final @ColorInt int color = mDpm.getOrganizationColorForUser(mUserId);
+
+        // Draw captions overlaid on the content view, so the whole window is one solid color.
+        setOverlayWithDecorCaptionEnabled(true);
+
+        // Match task description to the task stack we are replacing so it's still recognizably the
+        // original task stack with the same icon and title text.
+        setTaskDescription(new TaskDescription(null, null, color));
+
+        // Blank out the activity. When it is on-screen it will look like a Recents thumbnail with
+        // redaction switched on.
+        final View blankView = new View(this);
+        blankView.setBackgroundColor(color);
+        setContentView(blankView);
+    }
+
+    /**
+     * Respond to focus events by showing the prompt to confirm credentials.
+     * <p>
+     * We don't have anything particularly interesting to show here (just a solid-colored page) so
+     * there is no sense in sitting in the foreground doing nothing.
+     */
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        if (hasFocus) {
+            showConfirmCredentialActivity();
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        unregisterReceiver(mLockEventReceiver);
+        super.onDestroy();
+    }
+
+    @Override
+    public void onBackPressed() {
+        // Ignore back presses.
+        return;
+    }
+
+    private final BroadcastReceiver mLockEventReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, mUserId);
+            if (userId == mUserId && !mKgm.isDeviceLocked(mUserId)) {
+                finish();
+            }
+        }
+    };
+
+    private void showConfirmCredentialActivity() {
+        if (isFinishing() || !mKgm.isDeviceLocked(mUserId)) {
+            // Don't show the confirm credentials screen if we are already unlocked / unlocking.
+            return;
+        }
+
+        final Intent credential = mKgm.createConfirmDeviceCredentialIntent(null, null, mUserId);
+        if (credential == null) {
+            return;
+        }
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchTaskId(getTaskId());
+
+        // Bring this activity back to the foreground after confirming credentials.
+        final PendingIntent target = PendingIntent.getActivity(this, /* request */ -1, getIntent(),
+                PendingIntent.FLAG_CANCEL_CURRENT |
+                PendingIntent.FLAG_ONE_SHOT |
+                PendingIntent.FLAG_IMMUTABLE, options.toBundle());
+
+        credential.putExtra(Intent.EXTRA_INTENT, target.getIntentSender());
+        try {
+            ActivityManager.getService().startConfirmDeviceCredentialIntent(credential);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to start confirm credential intent", e);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
new file mode 100644
index 0000000..22fceff
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.keyguard;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.app.KeyguardManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
+
+public class WorkLockActivityController {
+    private final Context mContext;
+
+    public WorkLockActivityController(Context context) {
+        mContext = context;
+        EventBus.getDefault().register(this);
+        SystemServicesProxy.getInstance(context).registerTaskStackListener(mLockListener);
+    }
+
+    private void startWorkChallengeInTask(int taskId, int userId) {
+        Intent intent = new Intent(KeyguardManager.ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER)
+                .setComponent(new ComponentName(mContext, WorkLockActivity.class))
+                .putExtra(Intent.EXTRA_USER_ID, userId)
+                .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+                        | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
+                        | Intent.FLAG_ACTIVITY_SINGLE_TOP);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchTaskId(taskId);
+        options.setTaskOverlay(true);
+        mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
+    }
+
+    private final TaskStackListener mLockListener = new TaskStackListener() {
+        @Override
+        public void onTaskProfileLocked(int taskId, int userId) {
+            startWorkChallengeInTask(taskId, userId);
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index d86aebf..416c7ce 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -47,13 +47,11 @@
     public FlashlightTile(Host host) {
         super(host);
         mFlashlightController = host.getFlashlightController();
-        mFlashlightController.addCallback(this);
     }
 
     @Override
     protected void handleDestroy() {
         super.handleDestroy();
-        mFlashlightController.removeCallback(this);
     }
 
     @Override
@@ -63,6 +61,11 @@
 
     @Override
     public void setListening(boolean listening) {
+        if (listening) {
+            mFlashlightController.addCallback(this);
+        } else {
+            mFlashlightController.removeCallback(this);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index ddffea2..7791132 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -154,6 +154,7 @@
         public void onPinnedStackAnimationEnded() { }
         public void onActivityForcedResizable(String packageName, int taskId) { }
         public void onActivityDismissingDockedStack() { }
+        public void onTaskProfileLocked(int taskId, int userId) { }
     }
 
     /**
@@ -197,6 +198,11 @@
         public void onActivityDismissingDockedStack() throws RemoteException {
             mHandler.sendEmptyMessage(H.ON_ACTIVITY_DISMISSING_DOCKED_STACK);
         }
+
+        @Override
+        public void onTaskProfileLocked(int taskId, int userId) {
+            mHandler.obtainMessage(H.ON_TASK_PROFILE_LOCKED, taskId, userId).sendToTarget();
+        }
     };
 
     /**
@@ -561,10 +567,10 @@
      * Cancels the current window transtion to/from Recents for the given task id.
      */
     public void cancelWindowTransition(int taskId) {
-        if (mWm == null) return;
+        if (mIam == null) return;
 
         try {
-            WindowManagerGlobal.getWindowManagerService().cancelTaskWindowTransition(taskId);
+            mIam.cancelTaskWindowTransition(taskId);
         } catch (RemoteException e) {
             e.printStackTrace();
         }
@@ -574,10 +580,10 @@
      * Cancels the current thumbnail transtion to/from Recents for the given task id.
      */
     public void cancelThumbnailTransition(int taskId) {
-        if (mWm == null) return;
+        if (mIam == null) return;
 
         try {
-            WindowManagerGlobal.getWindowManagerService().cancelTaskThumbnailTransition(taskId);
+            mIam.cancelTaskThumbnailTransition(taskId);
         } catch (RemoteException e) {
             e.printStackTrace();
         }
@@ -1155,6 +1161,7 @@
         private static final int ON_PINNED_STACK_ANIMATION_ENDED = 4;
         private static final int ON_ACTIVITY_FORCED_RESIZABLE = 5;
         private static final int ON_ACTIVITY_DISMISSING_DOCKED_STACK = 6;
+        private static final int ON_TASK_PROFILE_LOCKED = 7;
 
         @Override
         public void handleMessage(Message msg) {
@@ -1196,6 +1203,12 @@
                     }
                     break;
                 }
+                case ON_TASK_PROFILE_LOCKED: {
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onTaskProfileLocked(msg.arg1, msg.arg2);
+                    }
+                    break;
+                }
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
index e8039c3..3059a05 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@@ -30,6 +30,9 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.service.vr.IVrManager;
+import android.service.vr.IVrStateCallbacks;
+import android.util.Log;
 import android.widget.ImageView;
 
 import com.android.internal.logging.MetricsLogger;
@@ -52,9 +55,12 @@
     private static final int MSG_SET_CHECKED = 2;
     private static final int MSG_ATTACH_LISTENER = 3;
     private static final int MSG_DETACH_LISTENER = 4;
+    private static final int MSG_VR_MODE_CHANGED = 5;
 
     private final int mMinimumBacklight;
     private final int mMaximumBacklight;
+    private final int mMinimumBacklightForVr;
+    private final int mMaximumBacklightForVr;
 
     private final Context mContext;
     private final ImageView mIcon;
@@ -62,6 +68,7 @@
     private final boolean mAutomaticAvailable;
     private final IPowerManager mPower;
     private final CurrentUserTracker mUserTracker;
+    private final IVrManager mVrManager;
 
     private Handler mBackgroundHandler;
     private final BrightnessObserver mBrightnessObserver;
@@ -69,7 +76,8 @@
     private ArrayList<BrightnessStateChangeCallback> mChangeCallbacks =
             new ArrayList<BrightnessStateChangeCallback>();
 
-    private volatile boolean mAutomatic;
+    private volatile boolean mAutomatic;  // Brightness adjusted automatically using ambient light.
+    private volatile boolean mIsVrModeEnabled;
     private boolean mListening;
     private boolean mExternalChange;
 
@@ -84,6 +92,8 @@
                 Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE);
         private final Uri BRIGHTNESS_URI =
                 Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
+        private final Uri BRIGHTNESS_FOR_VR_URI =
+                Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_FOR_VR);
         private final Uri BRIGHTNESS_ADJ_URI =
                 Settings.System.getUriFor(Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ);
 
@@ -105,6 +115,8 @@
                 mBackgroundHandler.post(mUpdateSliderRunnable);
             } else if (BRIGHTNESS_URI.equals(uri) && !mAutomatic) {
                 mBackgroundHandler.post(mUpdateSliderRunnable);
+            } else if (BRIGHTNESS_FOR_VR_URI.equals(uri)) {
+                mBackgroundHandler.post(mUpdateSliderRunnable);
             } else if (BRIGHTNESS_ADJ_URI.equals(uri) && mAutomatic) {
                 mBackgroundHandler.post(mUpdateSliderRunnable);
             } else {
@@ -126,6 +138,9 @@
                     BRIGHTNESS_URI,
                     false, this, UserHandle.USER_ALL);
             cr.registerContentObserver(
+                    BRIGHTNESS_FOR_VR_URI,
+                    false, this, UserHandle.USER_ALL);
+            cr.registerContentObserver(
                     BRIGHTNESS_ADJ_URI,
                     false, this, UserHandle.USER_ALL);
         }
@@ -191,7 +206,14 @@
     private final Runnable mUpdateSliderRunnable = new Runnable() {
         @Override
         public void run() {
-            if (mAutomatic) {
+            if (mIsVrModeEnabled) {
+                int value = Settings.System.getIntForUser(mContext.getContentResolver(),
+                        Settings.System.SCREEN_BRIGHTNESS_FOR_VR, mMaximumBacklight,
+                        UserHandle.USER_CURRENT);
+                mHandler.obtainMessage(MSG_UPDATE_SLIDER,
+                        mMaximumBacklightForVr - mMinimumBacklightForVr,
+                        value - mMinimumBacklightForVr).sendToTarget();
+            } else if (mAutomatic) {
                 float value = Settings.System.getFloatForUser(mContext.getContentResolver(),
                         Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0,
                         UserHandle.USER_CURRENT);
@@ -208,6 +230,14 @@
         }
     };
 
+    private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
+        @Override
+        public void onVrStateChanged(boolean enabled) {
+            mHandler.obtainMessage(MSG_VR_MODE_CHANGED, enabled ? 1 : 0, 0)
+                    .sendToTarget();
+        }
+    };
+
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -230,6 +260,9 @@
                     case MSG_DETACH_LISTENER:
                         mControl.setOnChangedListener(null);
                         break;
+                    case MSG_VR_MODE_CHANGED:
+                        updateVrMode(msg.arg1 != 0);
+                        break;
                     default:
                         super.handleMessage(msg);
                 }
@@ -256,10 +289,13 @@
         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         mMinimumBacklight = pm.getMinimumScreenBrightnessSetting();
         mMaximumBacklight = pm.getMaximumScreenBrightnessSetting();
+        mMinimumBacklightForVr = pm.getMinimumScreenBrightnessForVrSetting();
+        mMaximumBacklightForVr = pm.getMaximumScreenBrightnessForVrSetting();
 
         mAutomaticAvailable = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_automatic_brightness_available);
         mPower = IPowerManager.Stub.asInterface(ServiceManager.getService("power"));
+        mVrManager = IVrManager.Stub.asInterface(ServiceManager.getService("vrmanager"));
     }
 
     public void setBackgroundLooper(Looper backgroundLooper) {
@@ -284,6 +320,15 @@
             return;
         }
 
+        if (mVrManager != null) {
+            try {
+                mVrManager.registerListener(mVrStateCallbacks);
+                mIsVrModeEnabled = mVrManager.getVrModeState();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to register VR mode state listener: ", e);
+            }
+        }
+
         mBackgroundHandler.post(mStartListeningRunnable);
         mListening = true;
     }
@@ -294,6 +339,14 @@
             return;
         }
 
+        if (mVrManager != null) {
+            try {
+                mVrManager.unregisterListener(mVrStateCallbacks);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to unregister VR mode state listener: ", e);
+            }
+        }
+
         mBackgroundHandler.post(mStopListeningRunnable);
         mListening = false;
     }
@@ -304,7 +357,22 @@
         updateIcon(mAutomatic);
         if (mExternalChange) return;
 
-        if (!mAutomatic) {
+        if (mIsVrModeEnabled) {
+            final int val = value + mMinimumBacklightForVr;
+            if (stopTracking) {
+                MetricsLogger.action(mContext, MetricsEvent.ACTION_BRIGHTNESS_FOR_VR, val);
+            }
+            setBrightness(val);
+            if (!tracking) {
+                AsyncTask.execute(new Runnable() {
+                        public void run() {
+                            Settings.System.putIntForUser(mContext.getContentResolver(),
+                                    Settings.System.SCREEN_BRIGHTNESS_FOR_VR, val,
+                                    UserHandle.USER_CURRENT);
+                        }
+                    });
+            }
+        } else if (!mAutomatic) {
             final int val = value + mMinimumBacklight;
             if (stopTracking) {
                 MetricsLogger.action(mContext, MetricsEvent.ACTION_BRIGHTNESS, val);
@@ -368,4 +436,11 @@
                     com.android.systemui.R.drawable.ic_qs_brightness_auto_off);
         }
     }
+
+    private void updateVrMode(boolean isEnabled) {
+        if (mIsVrModeEnabled != isEnabled) {
+            mIsVrModeEnabled = isEnabled;
+            mBackgroundHandler.post(mUpdateSliderRunnable);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index 088f538..c7adb60 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -313,7 +313,7 @@
         } else if (mHighImportanceButton.isChecked()) {
             return NotificationManager.IMPORTANCE_HIGH;
         } else {
-            return NotificationManager.IMPORTANCE_NONE;
+            return NotificationManager.IMPORTANCE_UNSPECIFIED;
         }
     }
 
@@ -333,10 +333,10 @@
 
         // Set to current importance setting
         switch (importance) {
+            case NotificationManager.IMPORTANCE_UNSPECIFIED:
             case NotificationManager.IMPORTANCE_NONE:
                 break;
             case NotificationManager.IMPORTANCE_MIN:
-            case NotificationManager.IMPORTANCE_UNSPECIFIED:
                 mMinImportanceButton.setChecked(true);
                 break;
             case NotificationManager.IMPORTANCE_LOW:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
index 008d837..f0cfa2c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
@@ -121,6 +121,8 @@
             }
             cleanUpListenersLocked(l);
             mListeners.add(new WeakReference<>(l));
+            l.onFlashlightAvailabilityChanged(mTorchAvailable);
+            l.onFlashlightChanged(mFlashlightEnabled);
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
index 01fd97c..d529ee1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
@@ -15,6 +15,7 @@
 package com.android.systemui.plugins;
 
 import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.Matchers.any;
@@ -39,11 +40,13 @@
 import android.content.pm.ServiceInfo;
 import android.os.HandlerThread;
 import android.os.UserHandle;
+import android.support.test.annotation.UiThreadTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
 
 import org.junit.After;
 import org.junit.Before;
@@ -92,6 +95,15 @@
         sMockPlugin = null;
     }
 
+    @UiThreadTest
+    @Test
+    public void testGetPlugin() throws Exception {
+        setupFakePmQuery();
+        PluginInfo p = mPluginInstanceManager.getPlugin();
+        assertNotNull(p.mPlugin);
+        verify(sMockPlugin).onCreate(any(), any());
+    }
+
     @Test
     public void testNoPlugins() throws Exception {
         when(mMockPm.queryIntentServices(any(), anyInt())).thenReturn(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
index d5ada67..a58407b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
@@ -13,6 +13,8 @@
  */
 package com.android.systemui.plugins;
 
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -24,11 +26,13 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.net.Uri;
+import android.support.test.annotation.UiThreadTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
 import com.android.systemui.plugins.PluginManager.PluginInstanceManagerFactory;
 
 import org.junit.Before;
@@ -66,6 +70,16 @@
         mMockListener = mock(PluginListener.class);
     }
 
+    @UiThreadTest
+    @Test
+    public void testOneShot() {
+        Plugin mockPlugin = mock(Plugin.class);
+        when(mMockPluginInstance.getPlugin()).thenReturn(new PluginInfo(null, null, mockPlugin,
+                null));
+        Plugin result = mPluginManager.getOneShotPlugin("myAction", 1);
+        assertTrue(result == mockPlugin);
+    }
+
     @Test
     public void testAddListener() {
         mPluginManager.addPluginListener("myAction", mMockListener, 1);
@@ -86,9 +100,12 @@
         mPluginManager = new PluginManager(getContext(), mMockFactory, false,
                 mMockExceptionHandler);
         resetExceptionHandler();
-        mPluginManager.addPluginListener("myAction", mMockListener, 1);
 
+        mPluginManager.addPluginListener("myAction", mMockListener, 1);
         verify(mMockPluginInstance, Mockito.never()).loadAll();
+
+        assertNull(mPluginManager.getOneShotPlugin("myPlugin", 1));
+        verify(mMockPluginInstance, Mockito.never()).getPlugin();
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsTest.java
index 2cd6dbd..c65f7150 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsTest.java
@@ -210,6 +210,18 @@
 
     @Test
     @UiThreadTest
+    public void testCloseControls_DoesNotUpdateNotificationChannelIfUnspecified() throws Exception {
+        mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_UNSPECIFIED);
+        mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+                mMockStatusBarNotification, null, null, null);
+
+        mNotificationGuts.closeControls(-1, -1, true);
+        verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
+                anyString(), anyInt(), any());
+    }
+
+    @Test
+    @UiThreadTest
     public void testCloseControls_CallsUpdateNotificationChannelIfChanged() throws Exception {
         mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
         mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
diff --git a/proto/src/ipconnectivity.proto b/proto/src/ipconnectivity.proto
index cf372bc..b5afc40 100644
--- a/proto/src/ipconnectivity.proto
+++ b/proto/src/ipconnectivity.proto
@@ -17,14 +17,26 @@
   optional int32 network_id = 1;
 };
 
-// Transport describes a physical technology used by a network. It is a subset
-// of the TRANSPORT_* constants defined in android.net.NetworkCapabilities.
-enum Transport {
+// LinkLayer describes a physical link layer technology used by a network.
+// It is not intended to map one to one to the TRANSPORT_* constants defined in
+// android.net.NetworkCapabilities. Instead it is intended to be used as
+// a dimension field for metrics events and aggregated metrics.
+// Next tag: 7
+enum LinkLayer {
+  // An unknown link layer technology.
   UNKNOWN   = 0;
+
   BLUETOOTH = 1;
   CELLULAR  = 2;
   ETHERNET  = 3;
   WIFI      = 4;
+
+  // Indicates that the link layer dimension is not relevant for the metrics or
+  // event considered.
+  NONE      = 5;
+
+  // Indicates that the metrics or event considered may involve several links.
+  MULTIPLE  = 6;
 };
 
 // A pair of (key, value) integers for describing histogram-like statistics.
@@ -65,7 +77,7 @@
 // This message is associated to android.net.metrics.IpReachabilityEvent.
 message IpReachabilityEvent {
   // The interface name (wlan, rmnet, lo, ...) on which the probe was sent.
-  // Deprecated since version 2, replaced by transport field.
+  // Deprecated since version 2, to be replaced by link_layer field.
   optional string if_name = 1 [deprecated = true];
 
   // The event type code of the probe, represented by constants defined in
@@ -179,7 +191,7 @@
 // android.net.metrics.DhcpErrorEvent.
 message DHCPEvent {
   // The interface name (wlan, rmnet, lo, ...) on which the event happened.
-  // Deprecated since version 2, replaced by transport field.
+  // Deprecated since version 2, to be replaced by link_layer field.
   optional string if_name = 1 [deprecated = true];
 
   oneof value {
@@ -284,7 +296,7 @@
 // This message is associated to android.net.metrics.IpManagerEvent.
 message IpProvisioningEvent {
   // The interface name (wlan, rmnet, lo, ...) on which the probe was sent.
-  // Deprecated since version 2, replaced by transport field.
+  // Deprecated since version 2, to be replaced by link_layer field.
   optional string if_name = 1 [deprecated = true];
 
   // The code of the IP provisioning event, represented by constants defined in
@@ -296,19 +308,21 @@
 }
 
 // Represents one of the IP connectivity event defined in this file.
-// Next tag: 15
+// Next tag: 16
 message IpConnectivityEvent {
   // Time in ms when the event was recorded.
   optional int64 time_ms = 1;
 
-  // Physical transport of the network on which the event happened.
+  // Physical link layer of the network on which the event happened.
+  // Acts as a dimension key.
   // Since version 2.
-  optional Transport transport = 12;
+  optional LinkLayer link_layer = 15;
 
   // Event type.
   oneof event {
 
     // An event about the system default network.
+    // The link_layer field is not relevant for this event and set to NONE.
     DefaultNetworkEvent default_network_event = 2;
 
     // An IP reachability probe event.
@@ -318,7 +332,8 @@
     NetworkEvent network_event = 4;
 
     // A batch of DNS lookups.
-    // Deprecated in the nyc-mr2 release since version 2, and replaced by dns_latencies.
+    // Deprecated in the nyc-mr2 release since version 2,and replaced by
+    // dns_latencies.
     DNSLookupBatch dns_lookup_batch = 5 [deprecated = true];
 
     // DNS lookup latency statistics.
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 57c4565..21139da 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3105,6 +3105,12 @@
     // PACKAGE: The package name of the app the permission was revoked for
     ACTION_PERMISSION_REVOKE_READ_PHONE_NUMBER = 739;
 
+    // ACTION: QS Brightness Slider (with auto brightness disabled, and VR enabled)
+    //   SUBTYPE: slider value
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    ACTION_BRIGHTNESS_FOR_VR = 498;
+
     // ACTION: A captive portal was detected during network validation
     // CATEGORY: NOTIFICATION
     // OS: N-MR2
@@ -3175,6 +3181,11 @@
     // user accepted
     ACTION_SKIP_DISCLAIMER_SELECTED = 760;
 
+    // Enclosing category for group of APP_TRANSITION_FOO events,
+    // logged when we execute an app transition.
+    APP_TRANSITION = 761;
+
+
     // ---- End O Constants, all O constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
index 6a16131..87eaf29 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
@@ -18,28 +18,23 @@
 
 import static android.Manifest.permission.MANAGE_AUTO_FILL;
 import static android.content.Context.AUTO_FILL_MANAGER_SERVICE;
-import static android.view.View.ASSIST_FLAG_SANITIZED_TEXT;
-import static android.view.View.ASSIST_FLAG_NON_SANITIZED_TEXT;
+import static android.view.View.AUTO_FILL_FLAG_TYPE_FILL;
+import static android.view.View.AUTO_FILL_FLAG_TYPE_SAVE;
+
+import static com.android.server.autofill.AutoFillUI.MSG_SHOW_ALL_NOTIFICATIONS;
+import static com.android.server.autofill.AutoFillUI.SHOW_ALL_NOTIFICATIONS_DELAY_MS;
 
 import android.Manifest;
 import android.app.AppGlobals;
-import android.app.Notification;
-import android.app.Notification.Action;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
@@ -48,7 +43,6 @@
 import android.os.ShellCallback;
 import android.os.SystemClock;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.provider.Settings;
 import android.service.autofill.IAutoFillManagerService;
 import android.text.TextUtils;
@@ -65,7 +59,6 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.List;
 
 /**
  * Entry point service for auto-fill management.
@@ -86,6 +79,7 @@
     protected static final int MSG_UNBIND = 1;
 
     private final AutoFillManagerServiceStub mServiceStub;
+    private final AutoFillUI mUi;
     private final Context mContext;
     private final ContentResolver mResolver;
 
@@ -99,7 +93,7 @@
                     removeStaleServiceForUser(msg.arg1);
                     return;
                 case MSG_SHOW_ALL_NOTIFICATIONS:
-                    showAllNotifications();
+                    mUi.showAllNotifications();
                     return;
                 default:
                     Slog.w(TAG, "Invalid message: " + msg);
@@ -129,6 +123,7 @@
         super(context);
 
         mContext = context;
+        mUi = new AutoFillUI(context, this, mLock);
         mResolver = context.getContentResolver();
         mServiceStub = new AutoFillManagerServiceStub();
     }
@@ -176,8 +171,9 @@
             Slog.w(TAG, "no service info for " + serviceComponent);
             return null;
         }
-        return new AutoFillManagerServiceImpl(this, mContext, mLock, FgThread.getHandler(), userId,
-                serviceInfo.applicationInfo.uid, serviceComponent, SERVICE_BINDING_LIFETIME_MS);
+        return new AutoFillManagerServiceImpl(this, mUi, mContext, mLock, FgThread.getHandler(),
+                userId, serviceInfo.applicationInfo.uid, serviceComponent,
+                SERVICE_BINDING_LIFETIME_MS);
     }
 
     /**
@@ -186,7 +182,8 @@
      * <p>First it tries to return the existing instance from the cache; if it's not cached, it
      * creates a new instance and caches it.
      */
-    private AutoFillManagerServiceImpl getServiceForUserLocked(int userId) {
+    // TODO(b/33197203): make private once AutoFillUi does not uses notifications
+    AutoFillManagerServiceImpl getServiceForUserLocked(int userId) {
         AutoFillManagerServiceImpl service = mServicesCache.get(userId);
         if (service != null) {
             if (DEBUG) Log.d(TAG, "reusing cached service for userId " + userId);
@@ -251,14 +248,14 @@
     final class AutoFillManagerServiceStub extends IAutoFillManagerService.Stub {
 
         @Override
-        public void requestAutoFill(IBinder activityToken, int userId, int flags) {
+        public void requestAutoFill(IBinder activityToken, int userId, Bundle extras, int flags) {
             if (DEBUG) Slog.d(TAG, "requestAutoFill: flags=" + flags + ", userId=" + userId);
             mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
 
             synchronized (mLock) {
                 final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId);
                 if (service != null) {
-                    service.requestAutoFill(activityToken, flags);
+                    service.requestAutoFill(activityToken, extras, flags);
                 }
             }
         }
@@ -310,147 +307,8 @@
             if (DEBUG) Slog.d(TAG, "settings (" + uri + " changed for " + userId);
             synchronized (mLock) {
                 removeCachedServiceForUserLocked(userId);
-                final ComponentName serviceComponent = getProviderForUser(userId);
-                if (serviceComponent == null) {
-                    cancelNotificationLocked(userId);
-                } else {
-                    showNotification(serviceComponent, userId);
-                }
+                mUi.updateNotification(userId);
             }
         }
     }
-
-    ////////////////////////////////////////////////////////////////////////////
-    // TODO: temporary code using a notification to request auto-fill.        //
-    // Will be removed once UX decide the right way to present it to the user //
-    ////////////////////////////////////////////////////////////////////////////
-
-    // TODO: remove from frameworks/base/core/res/AndroidManifest.xml once it's not used anymore
-    private static final String NOTIFICATION_AUTO_FILL_INTENT =
-            "com.android.internal.autofill.action.REQUEST_AUTOFILL";
-    private static final String EXTRA_USER_ID = "user_id";
-    private static final String EXTRA_FLAGS = "flags";
-
-    private static final int MSG_SHOW_ALL_NOTIFICATIONS = 42;
-    private static final int SHOW_ALL_NOTIFICATIONS_DELAY_MS = 5000;
-
-    private BroadcastReceiver mNotificationReceiver;
-
-    final class NotificationReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            final int userId = intent.getIntExtra(EXTRA_USER_ID, -1);
-            final int flags = intent.getIntExtra(EXTRA_FLAGS, 0);
-            if (DEBUG) Slog.d(TAG, "Requesting autofill by notification for user " + userId);
-            synchronized (mLock) {
-                final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId);
-                if (service == null) {
-                    Slog.w(TAG, "no auto-fill service for user " + userId);
-                } else {
-                    service.requestAutoFill(null, flags);
-                }
-            }
-        }
-    }
-
-    private ComponentName getProviderForUser(int userId) {
-        ComponentName serviceComponent = null;
-        ServiceInfo serviceInfo = null;
-        final String componentName = Settings.Secure.getStringForUser(
-                mResolver, Settings.Secure.AUTO_FILL_SERVICE, userId);
-        if (!TextUtils.isEmpty(componentName)) {
-            try {
-                serviceComponent = ComponentName.unflattenFromString(componentName);
-                serviceInfo =
-                        AppGlobals.getPackageManager().getServiceInfo(serviceComponent, 0, userId);
-            } catch (RuntimeException | RemoteException e) {
-                Slog.wtf(TAG, "Bad auto-fill service name " + componentName, e);
-                return null;
-            }
-        }
-
-        if (DEBUG) Slog.d(TAG, "getServiceComponentForUser(" + userId + "): component="
-                + serviceComponent + ", info: " + serviceInfo);
-        if (serviceInfo == null) {
-            Slog.w(TAG, "no service info for " + serviceComponent);
-            return null;
-        }
-        return serviceComponent;
-    }
-
-    private void showAllNotifications() {
-        final UserManager userManager =
-                (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-
-        final List<UserInfo> allUsers = userManager.getUsers(true);
-
-        for (UserInfo user : allUsers) {
-            final ComponentName serviceComponent = getProviderForUser(user.id);
-            if (serviceComponent != null) {
-                showNotification(serviceComponent, user.id);
-            }
-        }
-    }
-
-    private void showNotification(ComponentName serviceComponent, int userId) {
-        if (DEBUG) Log.d(TAG, "showNotification() for " + userId + ": " + serviceComponent);
-
-        synchronized (mLock) {
-            if (mNotificationReceiver == null) {
-                mNotificationReceiver = new NotificationReceiver();
-                mContext.registerReceiver(mNotificationReceiver,
-                        new IntentFilter(NOTIFICATION_AUTO_FILL_INTENT));
-            }
-        }
-
-        final Intent fillIntent = new Intent(NOTIFICATION_AUTO_FILL_INTENT);
-        fillIntent.putExtra(EXTRA_USER_ID, userId);
-        fillIntent.putExtra(EXTRA_FLAGS, ASSIST_FLAG_SANITIZED_TEXT);
-        final PendingIntent fillPendingIntent = PendingIntent.getBroadcast(mContext,
-                ASSIST_FLAG_SANITIZED_TEXT, fillIntent, PendingIntent.FLAG_UPDATE_CURRENT);
-        final Action fillAction = new Action.Builder(null, "FILL", fillPendingIntent).build();
-
-        final Intent saveIntent = new Intent(NOTIFICATION_AUTO_FILL_INTENT);
-        saveIntent.putExtra(EXTRA_USER_ID, userId);
-        saveIntent.putExtra(EXTRA_FLAGS, ASSIST_FLAG_NON_SANITIZED_TEXT);
-        final PendingIntent savePendingIntent = PendingIntent.getBroadcast(mContext,
-                ASSIST_FLAG_NON_SANITIZED_TEXT, saveIntent, PendingIntent.FLAG_UPDATE_CURRENT);
-        final Action saveAction = new Action.Builder(null, "SAVE", savePendingIntent).build();
-
-        final String packageName = serviceComponent.getPackageName();
-        String providerName = null;
-        final PackageManager pm = mContext.getPackageManager();
-        try {
-            final ApplicationInfo info = pm.getApplicationInfoAsUser(packageName, 0, userId);
-            if (info != null) {
-                providerName = pm.getApplicationLabel(info).toString();
-            }
-        } catch (Exception e) {
-            providerName = packageName;
-        }
-        final String title = "AutoFill actions";
-        final String subTitle = "Provider: " + providerName + "\n" + "User: " + userId;
-
-        final Notification notification = new Notification.Builder(mContext)
-                .setCategory(Notification.CATEGORY_SYSTEM)
-                .setOngoing(true)
-                .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
-                .setLocalOnly(true)
-                .setColor(mContext.getColor(
-                        com.android.internal.R.color.system_notification_accent_color))
-                .setContentTitle(title)
-                .setStyle(new Notification.BigTextStyle().bigText(subTitle))
-                .setActions(fillAction, saveAction)
-                .build();
-        NotificationManager.from(mContext).notify(userId, notification);
-    }
-
-    private void cancelNotificationLocked(int userId) {
-        if (DEBUG) Log.d(TAG, "cancelNotificationLocked(): " + userId);
-        NotificationManager.from(mContext).cancel(userId);
-    }
-
-    /////////////////////////////////////////
-    // End of temporary notification code. //
-    /////////////////////////////////////////
 }
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
index 82356c8..3de8a8b 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
@@ -18,9 +18,12 @@
 
 import static com.android.server.autofill.AutoFillManagerService.DEBUG;
 
+import android.annotation.Nullable;
+import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.IActivityManager;
+import android.app.assist.AssistStructure;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -29,6 +32,7 @@
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.icu.text.DateFormat;
+import android.os.Bundle;
 import android.os.DeadObjectException;
 import android.os.Handler;
 import android.os.IBinder;
@@ -37,16 +41,24 @@
 import android.os.UserHandle;
 import android.service.autofill.AutoFillService;
 import android.service.autofill.AutoFillServiceInfo;
+import android.service.autofill.IAutoFillAppCallback;
+import android.service.autofill.IAutoFillServerCallback;
 import android.service.autofill.IAutoFillService;
-import android.util.Log;
+import android.service.voice.VoiceInteractionSession;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.TimeUtils;
+import android.view.autofill.AutoFillId;
+import android.view.autofill.Dataset;
+import android.view.autofill.FillResponse;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.IResultReceiver;
 import com.android.server.LocalServices;
 
 import java.io.PrintWriter;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
@@ -60,6 +72,9 @@
 
     private static final String TAG = "AutoFillManagerServiceImpl";
 
+    /** Used do assign ids to new ServerCallback instances. */
+    private static int sServerCallbackCounter = 0;
+
     private final int mUserId;
     private final int mUid;
     private final ComponentName mComponent;
@@ -68,6 +83,7 @@
     private final Object mLock;
     private final AutoFillServiceInfo mInfo;
     private final AutoFillManagerService mManagerService;
+    private final AutoFillUI mUi;
 
     // TODO(b/33197203): improve its usage
     // - set maximum number of entries
@@ -89,10 +105,19 @@
         }
     };
 
+    /**
+     * Cache of pending ServerCallbacks, keyed by {@link ServerCallback#id}.
+     *
+     * <p>They're kept until the AutoFillService handles a request, or an error occurs.
+     */
+    // TODO(b/33197203): need to make sure service is bound while callback is pending
+    @GuardedBy("mLock")
+    private static final SparseArray<ServerCallback> mServerCallbacks = new SparseArray<>();
+
     private final ServiceConnection mConnection = new ServiceConnection() {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
-            if (DEBUG) Log.d(TAG, "onServiceConnected():" + name);
+            if (DEBUG) Slog.d(TAG, "onServiceConnected():" + name);
             synchronized (mLock) {
                 mService = IAutoFillService.Stub.asInterface(service);
                 try {
@@ -102,17 +127,18 @@
                     return;
                 }
                 if (!mQueuedRequests.isEmpty()) {
-                    if (DEBUG) Log.d(TAG, "queued requests:" + mQueuedRequests.size());
+                    if (DEBUG) Slog.d(TAG, "queued requests:" + mQueuedRequests.size());
                 }
                 for (final QueuedRequest request: mQueuedRequests) {
-                    requestAutoFillLocked(request.activityToken, request.flags, false);
+                    requestAutoFillLocked(request.activityToken, request.extras, request.flags,
+                            false);
                 }
             }
         }
 
         @Override
         public void onServiceDisconnected(ComponentName name) {
-            if (DEBUG) Log.d(TAG, name + " disconnected");
+            if (DEBUG) Slog.d(TAG, name + " disconnected");
             synchronized (mLock) {
                 mService = null;
                 mManagerService.removeCachedServiceForUserLocked(mUserId);
@@ -120,6 +146,39 @@
         }
     };
 
+
+    /**
+     * Receiver of assist data from the app's {@link Activity}, uses the {@code resultData} as
+     * the {@link ServerCallback#id}.
+     */
+    private final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
+        @Override
+        public void send(int resultCode, Bundle resultData) throws RemoteException {
+            if (DEBUG) Slog.d(TAG, "resultCode on mAssistReceiver: " + resultCode);
+
+            final IBinder appBinder = resultData.getBinder(AutoFillService.KEY_CALLBACK);
+            if (appBinder == null) {
+                Slog.w(TAG, "no app callback on mAssistReceiver's resultData");
+                return;
+            }
+            final AssistStructure structure = resultData
+                    .getParcelable(VoiceInteractionSession.KEY_STRUCTURE);
+            final Bundle data = resultData.getBundle(VoiceInteractionSession.KEY_RECEIVER_EXTRAS);
+            final int flags = resultData.getInt(VoiceInteractionSession.KEY_FLAGS, 0);
+
+            final ServerCallback serverCallback;
+            synchronized (mLock) {
+                serverCallback = mServerCallbacks.get(resultCode);
+                if (serverCallback == null) {
+                    Slog.w(TAG, "no server callback for id " + resultCode);
+                    return;
+                }
+                serverCallback.appCallback = IAutoFillAppCallback.Stub.asInterface(appBinder);
+            }
+            mService.autoFill(structure, serverCallback, serverCallback.extras, flags);
+        }
+    };
+
     @GuardedBy("mLock")
     private IAutoFillService mService;
     private boolean mBound;
@@ -128,9 +187,11 @@
     // Estimated time when the service will be evicted from the cache.
     long mEstimateTimeOfDeath;
 
-    AutoFillManagerServiceImpl(AutoFillManagerService managerService, Context context, Object lock,
-            Handler handler, int userId, int uid,ComponentName component, long ttl) {
+    AutoFillManagerServiceImpl(AutoFillManagerService managerService, AutoFillUI ui,
+            Context context, Object lock, Handler handler, int userId, int uid,
+            ComponentName component, long ttl) {
         mManagerService = managerService;
+        mUi = ui;
         mContext = context;
         mLock = lock;
         mUserId = userId;
@@ -180,7 +241,14 @@
         if (DEBUG) Slog.d(TAG, "Bound to " + mComponent);
     }
 
-    void requestAutoFill(IBinder activityToken, int flags) {
+    /**
+     * Asks service to auto-fill an activity.
+     *
+     * @param activityToken activity token
+     * @param extras bundle to be passed to the {@link AutoFillService} method.
+     * @param flags optional flags.
+     */
+    void requestAutoFill(@Nullable IBinder activityToken, @Nullable Bundle extras, int flags) {
         synchronized (mLock) {
             if (!mBound) {
                 Slog.w(TAG, "requestAutoFill() failed because it's not bound to service");
@@ -211,21 +279,26 @@
                 DateFormat.getDateTimeInstance().format(new Date()) + " - " + activityToken;
         synchronized (mLock) {
             mRequestHistory.add(historyItem);
-            requestAutoFillLocked(activityToken, flags, true);
+            requestAutoFillLocked(activityToken, extras, flags, true);
         }
     }
 
-    private void requestAutoFillLocked(IBinder activityToken, int flags, boolean queueIfNecessary) {
+    private void requestAutoFillLocked(IBinder activityToken, @Nullable Bundle extras, int flags,
+            boolean queueIfNecessary) {
         if (mService == null) {
             if (!queueIfNecessary) {
                 Slog.w(TAG, "requestAutoFillLocked(): service is null");
                 return;
             }
             if (DEBUG) Slog.d(TAG, "requestAutoFill(): service not set yet, queuing it");
-            mQueuedRequests.add(new QueuedRequest(activityToken, flags));
+            mQueuedRequests.add(new QueuedRequest(activityToken, extras, flags));
             return;
         }
 
+        final int callbackId = ++sServerCallbackCounter;
+        final ServerCallback serverCallback = new ServerCallback(callbackId, extras);
+        mServerCallbacks.put(callbackId, serverCallback);
+
         /*
          * TODO(b/33197203): apply security checks below:
          * - checks if disabled by secure settings / device policy
@@ -235,8 +308,7 @@
          */
         try {
             // TODO(b/33197203): add MetricsLogger call
-            if (!mAm.requestAutoFillData(mService.getAssistReceiver(), null, activityToken,
-                    flags)) {
+            if (!mAm.requestAutoFillData(mAssistReceiver, null, callbackId, activityToken, flags)) {
                 // TODO(b/33197203): might need a way to warn user (perhaps a new method on
                 // AutoFillService).
                 Slog.w(TAG, "failed to request auto-fill data for " + activityToken);
@@ -251,7 +323,7 @@
 
         // Sanity check.
         if (mService == null) {
-            Log.w(TAG, "service already null on shutdown");
+            Slog.w(TAG, "service already null on shutdown");
             return;
         }
         try {
@@ -273,6 +345,44 @@
         }
     }
 
+    /**
+     * Called by {@link AutoFillUI} to fill an activity after the user selected a dataset.
+     */
+    void autoFillApp(int callbackId, Dataset dataset) {
+        // TODO(b/33197203): add MetricsLogger call
+
+        if (dataset == null) {
+            Slog.w(TAG, "autoFillApp(): no dataset for callback id " + callbackId);
+            return;
+        }
+
+        final ServerCallback serverCallback;
+        synchronized (mLock) {
+            serverCallback = mServerCallbacks.get(callbackId);
+            if (serverCallback == null) {
+                Slog.w(TAG, "autoFillApp(): no server callback with id " + callbackId);
+                return;
+            }
+            if (serverCallback.appCallback == null) {
+                Slog.w(TAG, "autoFillApp(): no app callback for server callback " + callbackId);
+                return;
+            }
+            // TODO(b/33197203): use a handler?
+            try {
+                if (DEBUG) Slog.d(TAG, "autoFillApp(): the buck is on the app: " + dataset);
+                serverCallback.appCallback.autoFill(dataset);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Error auto-filling activity: " + e);
+            }
+            removeServerCallbackLocked(callbackId);
+        }
+    }
+
+    void removeServerCallbackLocked(int id) {
+        if (DEBUG) Slog.d(TAG, "Removing " + id + " from server callbacks");
+        mServerCallbacks.remove(id);
+    }
+
     void dumpLocked(String prefix, PrintWriter pw) {
         if (!mValid) {
             pw.print("  NOT VALID: ");
@@ -284,6 +394,8 @@
             return;
         }
 
+        final String prefix2 = prefix + "  ";
+
         pw.print(prefix); pw.print("mUserId="); pw.println(mUserId);
         pw.print(prefix); pw.print("mUid="); pw.println(mUid);
         pw.print(prefix); pw.print("mComponent="); pw.println(mComponent.flattenToShortString());
@@ -303,7 +415,6 @@
             pw.print(prefix); pw.println("No history");
         } else {
             pw.print(prefix); pw.println("History:");
-            final String prefix2 = prefix + prefix;
             for (int i = 0; i < mRequestHistory.size(); i++) {
                 pw.print(prefix2); pw.print(i); pw.print(": "); pw.println(mRequestHistory.get(i));
             }
@@ -312,11 +423,28 @@
             pw.print(prefix); pw.println("No queued requests");
         } else {
             pw.print(prefix); pw.println("Queued requests:");
-            final String prefix2 = prefix + prefix;
             for (int i = 0; i < mQueuedRequests.size(); i++) {
                 pw.print(prefix2); pw.print(i); pw.print(": "); pw.println(mQueuedRequests.get(i));
             }
         }
+
+        pw.print(prefix); pw.print("sServerCallbackCounter="); pw.println(sServerCallbackCounter);
+        final int size = mServerCallbacks.size();
+        if (size == 0) {
+            pw.print(prefix); pw.println("No server callbacks");
+        } else {
+            pw.print(prefix); pw.print(size); pw.println(" server callbacks:");
+            for (int i = 0; i < size; i++) {
+                pw.print(prefix2); pw.print(mServerCallbacks.keyAt(i));
+                final ServerCallback callback = mServerCallbacks.valueAt(i);
+                if (callback.appCallback == null) {
+                    pw.println("(no appCallback)");
+                } else {
+                    pw.print(" (app callback: "); pw.print(callback.appCallback) ; pw.println(")");
+                }
+            }
+            pw.println();
+        }
     }
 
     @Override
@@ -327,10 +455,12 @@
 
     private static final class QueuedRequest {
         final IBinder activityToken;
+        final Bundle extras;
         final int flags;
 
-        QueuedRequest(IBinder activityToken, int flags) {
+        QueuedRequest(IBinder activityToken, Bundle extras, int flags) {
             this.activityToken = activityToken;
+            this.extras = extras;
             this.flags = flags;
         }
 
@@ -339,4 +469,54 @@
             return "flags: " + flags + " token: " + activityToken;
         }
     }
+
+    /**
+     * A bridge between the {@link AutoFillService} implementation and the activity being
+     * auto-filled (represented through the {@link IAutoFillAppCallback}).
+     */
+    private final class ServerCallback extends IAutoFillServerCallback.Stub {
+
+        private final int id;
+        private final Bundle extras;
+        private IAutoFillAppCallback appCallback;
+
+        private ServerCallback(int id, Bundle extras) {
+            this.id = id;
+            this.extras = extras;
+        }
+
+        @Override
+        public void showResponse(FillResponse response) {
+            // TODO(b/33197203): add MetricsLogger call
+            if (DEBUG) Slog.d(TAG, "showResponse(): " + response);
+
+            mUi.showOptions(mUserId, id, response);
+        }
+
+        @Override
+        public void showError(String message) {
+            // TODO(b/33197203): add MetricsLogger call
+            if (DEBUG) Slog.d(TAG, "showError(): " + message);
+
+            mUi.showError(message);
+
+            removeSelf();
+        }
+
+        @Override
+        public void highlightSavedFields(AutoFillId[] ids) {
+            // TODO(b/33197203): add MetricsLogger call
+            if (DEBUG) Slog.d(TAG, "showSaved(): " + Arrays.toString(ids));
+
+            mUi.highlightSavedFields(ids);
+
+            removeSelf();
+        }
+
+        private void removeSelf() {
+            synchronized (mLock) {
+                removeServerCallbackLocked(id);
+            }
+        }
+    }
 }
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
index aa3503b..26f2451 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
@@ -16,10 +16,11 @@
 
 package com.android.server.autofill;
 
-import static android.view.View.ASSIST_FLAG_SANITIZED_TEXT;
-import static android.view.View.ASSIST_FLAG_NON_SANITIZED_TEXT;
+import static android.view.View.AUTO_FILL_FLAG_TYPE_FILL;
+import static android.view.View.AUTO_FILL_FLAG_TYPE_SAVE;
 
 import android.app.ActivityManager;
+import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ShellCommand;
 import android.os.UserHandle;
@@ -44,9 +45,9 @@
         try {
             switch (cmd) {
                 case "fill":
-                    return requestAutoFill(ASSIST_FLAG_SANITIZED_TEXT);
+                    return requestAutoFill(AUTO_FILL_FLAG_TYPE_FILL);
                 case "save":
-                    return requestAutoFill(ASSIST_FLAG_NON_SANITIZED_TEXT);
+                    return requestAutoFill(AUTO_FILL_FLAG_TYPE_SAVE);
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -73,7 +74,7 @@
 
     private int requestAutoFill(int flags) throws RemoteException {
         final int userId = getUserIdFromArgs();
-        mService.requestAutoFill(null, userId, flags);
+        mService.requestAutoFill(null, userId, null, flags);
         return 0;
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/AutoFillUI.java
new file mode 100644
index 0000000..08e81d3
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/AutoFillUI.java
@@ -0,0 +1,471 @@
+/*
+ * Copyright (C) 2016 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.server.autofill;
+
+import static android.view.View.AUTO_FILL_FLAG_TYPE_SAVE;
+import static android.view.View.AUTO_FILL_FLAG_TYPE_FILL;
+
+import static com.android.server.autofill.AutoFillManagerService.DEBUG;
+
+import android.app.Activity;
+import android.app.AppGlobals;
+import android.app.Notification;
+import android.app.Notification.Action;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.service.autofill.AutoFillService;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.view.autofill.Dataset;
+import android.view.autofill.AutoFillId;
+import android.view.autofill.FillResponse;
+import android.widget.Toast;
+
+import com.android.server.UiThread;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Handles all auto-fill related UI tasks.
+ */
+// TODO(b/33197203): document exactly what once the auto-fill bar is implemented
+final class AutoFillUI {
+
+    private static final String TAG = "AutoFillUI";
+
+    private final Context mContext;
+
+    AutoFillUI(Context context, AutoFillManagerService service, Object lock) {
+        mContext = context;
+        mResolver = context.getContentResolver();
+        mService = service;
+        mLock = lock;
+    }
+
+    /**
+     * Displays an error message to the user.
+     */
+    void showError(String message) {
+        // TODO(b/33197203): proper implementation
+        UiThread.getHandler().runWithScissors(() -> {
+            Toast.makeText(mContext, "AutoFill error: " + message, Toast.LENGTH_LONG).show();
+        }, 0);
+    }
+
+    /**
+     * Highlights in the {@link Activity} the fields saved by the service.
+     */
+    void highlightSavedFields(AutoFillId[] ids) {
+        // TODO(b/33197203): proper implementation (must be handled by activity)
+        UiThread.getHandler().runWithScissors(() -> {
+            Toast.makeText(mContext, "AutoFill: service saved ids " + Arrays.toString(ids),
+                    Toast.LENGTH_LONG).show();
+        }, 0);
+    }
+
+    /**
+     * Shows the options from a {@link FillResponse} so the user can pick up the proper
+     * {@link Dataset} (when the response has one).
+     */
+    void showOptions(int userId, int callbackId, FillResponse response) {
+        // TODO(b/33197203): proper implementation
+        // TODO(b/33197203): make sure if removes the callback from cache
+        showOptionsNotification(userId, callbackId, response);
+    }
+
+    /////////////////////////////////////////////////////////////////////////////////
+    // TODO(b/33197203): temporary code using a notification to request auto-fill. //
+    // Will be removed once UX decide the right way to present it to the user.     //
+    /////////////////////////////////////////////////////////////////////////////////
+
+    // TODO(b/33197203): remove from frameworks/base/core/res/AndroidManifest.xml once not used
+    private static final String NOTIFICATION_AUTO_FILL_INTENT =
+            "com.android.internal.autofill.action.REQUEST_AUTOFILL";
+
+    // Extras used in the notification intents
+    private static final String EXTRA_USER_ID = "user_id";
+    private static final String EXTRA_NOTIFICATION_TYPE = "notification_type";
+    private static final String EXTRA_CALLBACK_ID = "callback_id";
+    private static final String EXTRA_FILL_RESPONSE = "fill_response";
+    private static final String EXTRA_DATASET = "dataset";
+
+    private static final String TYPE_EMULATE = "emulate";
+    private static final String TYPE_OPTIONS = "options";
+    private static final String TYPE_DELETE_CALLBACK = "delete_callback";
+    private static final String TYPE_PICK_DATASET = "pick_dataset";
+    private static final String TYPE_SAVE = "save";
+
+    static final int MSG_SHOW_ALL_NOTIFICATIONS = 42;
+    static final int SHOW_ALL_NOTIFICATIONS_DELAY_MS = 5000;
+
+    private BroadcastReceiver mNotificationReceiver;
+    private final ContentResolver mResolver;
+    private final AutoFillManagerService mService;
+    private final Object mLock;
+
+    // Hack used to generate unique pending intents
+    static int sResultCode = 0;
+
+    final class NotificationReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final int userId = intent.getIntExtra(EXTRA_USER_ID, -1);
+
+            final AutoFillManagerServiceImpl service = mService.getServiceForUserLocked(userId);
+            if (service == null) {
+                Slog.w(TAG, "no auto-fill service for user " + userId);
+                return;
+            }
+
+            final int callbackId = intent.getIntExtra(EXTRA_CALLBACK_ID, -1);
+            final String type = intent.getStringExtra(EXTRA_NOTIFICATION_TYPE);
+            if (type == null) {
+                Slog.wtf(TAG, "No extra " + EXTRA_NOTIFICATION_TYPE + " on intent " + intent);
+                return;
+            }
+            final FillResponse fillData = intent.getParcelableExtra(EXTRA_FILL_RESPONSE);
+            final Dataset dataset = intent.getParcelableExtra(EXTRA_DATASET);
+            final Bundle datasetArgs = dataset == null ? null : dataset.getExtras();
+            final Bundle fillDataArgs = fillData == null ? null : fillData.getExtras();
+
+            // Bundle sent on AutoFillService methods - only set if service provided a bundle
+            final Bundle extras = (datasetArgs == null && fillDataArgs == null)
+                    ? null : new Bundle();
+
+            if (DEBUG) Slog.d(TAG, "Notification received: type=" + type + ", userId=" + userId
+                    + ", callbackId=" + callbackId);
+            synchronized (mLock) {
+                switch (type) {
+                    case TYPE_EMULATE:
+                        service.requestAutoFill(null, extras, AUTO_FILL_FLAG_TYPE_FILL);
+                        break;
+                    case TYPE_SAVE:
+                        if (datasetArgs != null) {
+                            if (DEBUG) Log.d(TAG, "filldata args on save notificataion: " +
+                                    bundleToString(fillDataArgs));
+                            extras.putBundle(AutoFillService.EXTRA_RESPONSE_EXTRAS, fillDataArgs);
+                        }
+                        if (dataset != null) {
+                            if (DEBUG) Log.d(TAG, "dataset args on save notificataion: " +
+                                    bundleToString(datasetArgs));
+                            extras.putBundle(AutoFillService.EXTRA_DATASET_EXTRAS, datasetArgs);
+                        }
+                        service.requestAutoFill(null, extras, AUTO_FILL_FLAG_TYPE_SAVE);
+                        break;
+                    case TYPE_DELETE_CALLBACK:
+                        service.removeServerCallbackLocked(callbackId);
+                        break;
+                    case TYPE_PICK_DATASET:
+                        service.autoFillApp(callbackId, dataset);
+                        // Must cancel notification because it might be comming from action
+                        if (DEBUG) Log.d(TAG, "Cancelling notification");
+                        NotificationManager.from(mContext).cancel(TYPE_OPTIONS, userId);
+
+                        if (datasetArgs != null) {
+                            if (DEBUG) Log.d(TAG, "adding dataset's extra_data on save intent: "
+                                    + bundleToString(datasetArgs));
+                            extras.putBundle(AutoFillService.EXTRA_DATASET_EXTRAS, datasetArgs);
+                        }
+
+                        // Also show notification with option to save the data
+                        showSaveNotification(userId, fillData, dataset);
+                        break;
+                    default: {
+                        Slog.w(TAG, "Unknown notification type: " + type);
+                    }
+                }
+            }
+        }
+    }
+
+    private ComponentName getProviderForUser(int userId) {
+        ComponentName serviceComponent = null;
+        ServiceInfo serviceInfo = null;
+        final String componentName = Settings.Secure.getStringForUser(
+                mResolver, Settings.Secure.AUTO_FILL_SERVICE, userId);
+        if (!TextUtils.isEmpty(componentName)) {
+            try {
+                serviceComponent = ComponentName.unflattenFromString(componentName);
+                serviceInfo =
+                        AppGlobals.getPackageManager().getServiceInfo(serviceComponent, 0, userId);
+            } catch (RuntimeException | RemoteException e) {
+                Slog.wtf(TAG, "Bad auto-fill service name " + componentName, e);
+                return null;
+            }
+        }
+
+        if (DEBUG) Slog.d(TAG, "getServiceComponentForUser(" + userId + "): component="
+                + serviceComponent + ", info: " + serviceInfo);
+        if (serviceInfo == null) {
+            Slog.w(TAG, "no service info for " + serviceComponent);
+            return null;
+        }
+        return serviceComponent;
+    }
+
+    void showAllNotifications() {
+        final UserManager userManager =
+                (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+
+        final List<UserInfo> allUsers = userManager.getUsers(true);
+
+        for (UserInfo user : allUsers) {
+            final ComponentName serviceComponent = getProviderForUser(user.id);
+            if (serviceComponent != null) {
+                showMainNotification(serviceComponent, user.id);
+            }
+        }
+    }
+
+    void updateNotification(int userId) {
+        final ComponentName serviceComponent = getProviderForUser(userId);
+        if (serviceComponent == null) {
+            cancelMainNotification(userId);
+        } else {
+            showMainNotification(serviceComponent, userId);
+        }
+    }
+
+    private static Intent newNotificationIntent(int userId, String type) {
+        final Intent intent = new Intent(NOTIFICATION_AUTO_FILL_INTENT);
+        intent.putExtra(EXTRA_USER_ID, userId);
+        intent.putExtra(EXTRA_NOTIFICATION_TYPE, type);
+        return intent;
+    }
+
+    private PendingIntent newPickDatasetPI(int userId, int callbackId, FillResponse response,
+            Dataset dataset) {
+        final int resultCode = ++ sResultCode;
+        if (DEBUG) Log.d(TAG, "newPickDatasetPI: userId=" + userId + ", callback=" + callbackId
+                + ", resultCode=" + resultCode);
+
+        final Intent intent = newNotificationIntent(userId, TYPE_PICK_DATASET);
+        intent.putExtra(EXTRA_CALLBACK_ID, callbackId);
+        intent.putExtra(EXTRA_FILL_RESPONSE, response);
+        intent.putExtra(EXTRA_DATASET, dataset);
+        return PendingIntent.getBroadcast(mContext, resultCode, intent,
+                PendingIntent.FLAG_ONE_SHOT);
+    }
+
+    private static String bundleToString(Bundle bundle) {
+        if (bundle == null) {
+            return "null";
+        }
+        final Set<String> keySet = bundle.keySet();
+        final StringBuilder builder = new StringBuilder("[Bundle with ").append(keySet.size())
+                .append(" keys:");
+        for (String key : keySet) {
+            final Object value = bundle.get(key);
+            builder.append(' ').append(key).append('=');
+            builder.append((value instanceof Object[])
+                    ? Arrays.toString((Objects[]) value) : value);
+        }
+        return builder.append(']').toString();
+    }
+
+    /**
+     * Shows a permanent notification that triggers the auto-fill workflow for the given user.
+     *
+     * <p>It emulates calling the auto-fill service when the IME is shown.
+     */
+    private void showMainNotification(ComponentName serviceComponent, int userId) {
+        if (DEBUG) Log.d(TAG, "showNotification() for " + userId + ": " + serviceComponent);
+
+        synchronized (mLock) {
+            if (mNotificationReceiver == null) {
+                mNotificationReceiver = new NotificationReceiver();
+                mContext.registerReceiver(mNotificationReceiver,
+                        new IntentFilter(NOTIFICATION_AUTO_FILL_INTENT));
+            }
+        }
+
+        final Intent fillIntent = newNotificationIntent(userId, TYPE_EMULATE);
+        final PendingIntent fillPendingIntent = PendingIntent.getBroadcast(mContext,
+                -1, fillIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+
+        final String packageName = serviceComponent.getPackageName();
+        String providerName = null;
+        final PackageManager pm = mContext.getPackageManager();
+        try {
+            final ApplicationInfo info = pm.getApplicationInfoAsUser(packageName, 0, userId);
+            if (info != null) {
+                providerName = pm.getApplicationLabel(info).toString();
+            }
+        } catch (Exception e) {
+            providerName = packageName;
+        }
+        final String title = "AutoFill IME Emulation";
+        final String subTitle = "Tap notification to start auto-fill workflow (by '" + providerName
+                + "' on top activity on user " + userId + ".\n"
+                + "Once provider replies, a new notification will show your options.";
+
+        final Notification notification = new Notification.Builder(mContext)
+                .setCategory(Notification.CATEGORY_SYSTEM)
+                .setOngoing(true)
+                .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+                .setLocalOnly(true)
+                .setColor(mContext.getColor(
+                        com.android.internal.R.color.system_notification_accent_color))
+                .setContentTitle(title)
+                .setStyle(new Notification.BigTextStyle().bigText(subTitle))
+                .setContentIntent(fillPendingIntent)
+                .build();
+        NotificationManager.from(mContext).notify(TYPE_EMULATE, userId, notification);
+    }
+
+    /**
+     * Cancels the permament notification created by
+     * {@link #showMainNotification(ComponentName, int)}.
+     */
+    private void cancelMainNotification(int userId) {
+        if (DEBUG) Log.d(TAG, "cancelNotificationLocked(): " + userId);
+        NotificationManager.from(mContext).cancel(TYPE_EMULATE, userId);
+    }
+
+    /**
+     * Shows a notification with the results of an auto-fill request, using notications actions
+     * to emulate the auto-fill bar buttons displaying the dataset names.
+     */
+    private void showOptionsNotification(int userId, int callbackId, FillResponse response) {
+        final long token = Binder.clearCallingIdentity();
+        try {
+            showOptionsNotificationAsSystem(userId, callbackId, response);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    private void showOptionsNotificationAsSystem(int userId, int callbackId,
+            FillResponse response) {
+        // Make sure server callback is removed from cache if user cancels the notification.
+        final Intent deleteIntent = newNotificationIntent(userId, TYPE_DELETE_CALLBACK);
+        deleteIntent.putExtra(EXTRA_CALLBACK_ID, callbackId);
+        final PendingIntent deletePendingIntent = PendingIntent.getBroadcast(mContext,
+                ++sResultCode, deleteIntent, PendingIntent.FLAG_ONE_SHOT);
+
+        final String title = "AutoFill Options";
+
+        final Notification.Builder notification = new Notification.Builder(mContext)
+                .setCategory(Notification.CATEGORY_SYSTEM)
+                .setOngoing(false)
+                .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+                .setLocalOnly(true)
+                .setColor(mContext.getColor(
+                        com.android.internal.R.color.system_notification_accent_color))
+                .setDeleteIntent(deletePendingIntent)
+                .setContentTitle(title);
+
+        boolean autoCancel = true;
+        final String subTitle;
+        final List<Dataset> datasets;
+        final AutoFillId[] savableIds;
+        if (response != null) {
+            datasets = response.getDatasets();
+            savableIds = response.getSavableIds();
+        } else {
+            datasets = null;
+            savableIds = null;
+        }
+        boolean showSave = false;
+        if (datasets == null ) {
+            subTitle = "No options to auto-fill this activity.";
+        } else if (datasets.isEmpty()) {
+            if (savableIds.length == 0) {
+                subTitle = "No options to auto-fill this activity.";
+            } else {
+                subTitle = "No options to auto-fill this activity, but provider can save ids:\n"
+                        + Arrays.toString(savableIds);
+                showSave = true;
+            }
+        } else {
+            final AutoFillManagerServiceImpl service = mService.getServiceForUserLocked(userId);
+            if (service == null) {
+                subTitle = "No auto-fill service for user " + userId;
+                Slog.w(TAG, subTitle);
+            } else {
+                autoCancel = false;
+                final int size = datasets.size();
+                subTitle = "There are " + size + " option(s).\n"
+                        + "Use the notification action(s) to select the proper one.";
+                for (Dataset dataset : datasets) {
+                    final CharSequence name = dataset.getName();
+                    final PendingIntent pi = newPickDatasetPI(userId, callbackId, response, dataset);
+                    notification.addAction(new Action.Builder(null, name, pi).build());
+                }
+            }
+        }
+
+        notification.setAutoCancel(autoCancel);
+        notification.setStyle(new Notification.BigTextStyle().bigText(subTitle));
+
+        NotificationManager.from(mContext).notify(TYPE_OPTIONS, userId, notification.build());
+
+        if (showSave) {
+            showSaveNotification(userId, response, null);
+        }
+    }
+
+    private void showSaveNotification(int userId, FillResponse response, Dataset dataset) {
+        final Intent saveIntent = newNotificationIntent(userId, TYPE_SAVE);
+        saveIntent.putExtra(EXTRA_FILL_RESPONSE, response);
+        if (dataset != null) {
+            saveIntent.putExtra(EXTRA_DATASET, dataset);
+        }
+        final PendingIntent savePendingIntent = PendingIntent.getBroadcast(mContext,
+                ++sResultCode, saveIntent, PendingIntent.FLAG_ONE_SHOT);
+
+        final String title = "AutoFill Save";
+        final String subTitle = "Tap notification to ask provider to save fields: \n"
+                + Arrays.toString(response.getSavableIds());
+
+        final Notification notification = new Notification.Builder(mContext)
+                .setCategory(Notification.CATEGORY_SYSTEM)
+                .setAutoCancel(true)
+                .setOngoing(false)
+                .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+                .setLocalOnly(true)
+                .setColor(mContext.getColor(
+                        com.android.internal.R.color.system_notification_accent_color))
+                .setContentTitle(title)
+                .setContentIntent(savePendingIntent)
+                .setStyle(new Notification.BigTextStyle().bigText(subTitle))
+                .build();
+        NotificationManager.from(mContext).notify(TYPE_SAVE, userId, notification);
+    }
+
+    /////////////////////////////////////////
+    // End of temporary notification code. //
+    /////////////////////////////////////////
+}
diff --git a/services/core/Android.mk b/services/core/Android.mk
index efadbef..1366b3b 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -24,7 +24,7 @@
     android.hardware.power@1.0-java \
     android.hardware.tv.cec@1.0-java
 
-LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update
+LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update2
 
 ifneq ($(INCREMENTAL_BUILDS),)
     LOCAL_PROGUARD_ENABLED := disabled
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index e7f1d16..2ca1b4e 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -218,6 +218,11 @@
         @Override
         public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
                 Bundle prevRestrictions) {
+            if (!newRestrictions.containsKey(UserManager.DISALLOW_BLUETOOTH)
+                    && !prevRestrictions.containsKey(UserManager.DISALLOW_BLUETOOTH)) {
+                // The relevant restriction has not changed - do nothing.
+                return;
+            }
             final boolean bluetoothDisallowed =
                     newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH);
             if ((mEnable || mEnableExternal) && bluetoothDisallowed) {
@@ -228,6 +233,7 @@
                             e);
                 }
             }
+            updateOppLauncherComponentState(bluetoothDisallowed);
         }
     };
 
@@ -953,7 +959,9 @@
         UserManagerInternal userManagerInternal =
                 LocalServices.getService(UserManagerInternal.class);
         userManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
-        if (isBluetoothDisallowed()) {
+        final boolean isBluetoothDisallowed = isBluetoothDisallowed();
+        updateOppLauncherComponentState(isBluetoothDisallowed);
+        if (isBluetoothDisallowed) {
             return;
         }
         if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
@@ -2011,6 +2019,24 @@
         }
     }
 
+    /**
+     * Disables BluetoothOppLauncherActivity component, so the Bluetooth sharing option is not
+     * offered to the user if Bluetooth is disallowed. Puts the component to its default state if
+     * Bluetooth is not disallowed.
+     *
+     * @param bluetoothDisallowed whether the {@link UserManager.DISALLOW_BLUETOOTH} user
+     * restriction was set.
+     */
+    private void updateOppLauncherComponentState(boolean bluetoothDisallowed) {
+        final ComponentName oppLauncherComponent = new ComponentName("com.android.bluetooth",
+                "com.android.bluetooth.opp.BluetoothOppLauncherActivity");
+        final int newState = bluetoothDisallowed
+                ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+                : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+        mContext.getPackageManager()
+                .setComponentEnabledSetting(oppLauncherComponent, newState, 0);
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index cef459a..e23844c 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -301,7 +301,8 @@
 
                 // If we're not connected at all then create a new connection.
                 if (mServiceConnection == null) {
-                    mServiceConnection = new ScoringServiceConnection(componentName);
+                    mServiceConnection = new ScoringServiceConnection(componentName,
+                            scorerData.packageUid);
                 }
 
                 // Make sure the connection is connected (idempotent)
@@ -325,7 +326,7 @@
 
     @Override
     public boolean updateScores(ScoredNetwork[] networks) {
-        if (!mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid())) {
+        if (!isCallerActiveScorer(getCallingUid())) {
             throw new SecurityException("Caller with UID " + getCallingUid() +
                     " is not the active scorer.");
         }
@@ -389,7 +390,7 @@
     @Override
     public boolean clearScores() {
         // Only the active scorer or the system should be allowed to flush all scores.
-        if (mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid()) || isCallerSystemUid()) {
+        if (isCallerActiveScorer(getCallingUid()) || isCallerSystemUid()) {
             final long token = Binder.clearCallingIdentity();
             try {
                 clearInternal();
@@ -418,10 +419,39 @@
         return false;
     }
 
+    /**
+     * Determine whether the application with the given UID is the enabled scorer.
+     *
+     * @param callingUid the UID to check
+     * @return true if the provided UID is the active scorer, false otherwise.
+     */
+    @Override
+    public boolean isCallerActiveScorer(int callingUid) {
+        synchronized (mServiceConnectionLock) {
+            return mServiceConnection != null && mServiceConnection.mScoringAppUid == callingUid;
+        }
+    }
+
+    /**
+     * Obtain the package name of the current active network scorer.
+     *
+     * @return the full package name of the current active scorer, or null if there is no active
+     *         scorer.
+     */
+    @Override
+    public String getActiveScorerPackage() {
+        synchronized (mServiceConnectionLock) {
+            if (mServiceConnection != null) {
+                return mServiceConnection.mComponentName.getPackageName();
+            }
+        }
+        return null;
+    }
+
     @Override
     public void disableScoring() {
         // Only the active scorer or the system should be allowed to disable scoring.
-        if (mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid()) || isCallerSystemUid()) {
+        if (isCallerActiveScorer(getCallingUid()) || isCallerSystemUid()) {
             // no-op for now but we could write to the setting if needed.
         } else {
             throw new SecurityException(
@@ -623,12 +653,14 @@
 
     private static class ScoringServiceConnection implements ServiceConnection {
         private final ComponentName mComponentName;
+        private final int mScoringAppUid;
         private volatile boolean mBound = false;
         private volatile boolean mConnected = false;
         private volatile INetworkRecommendationProvider mRecommendationProvider;
 
-        ScoringServiceConnection(ComponentName componentName) {
+        ScoringServiceConnection(ComponentName componentName, int scoringAppUid) {
             mComponentName = componentName;
+            mScoringAppUid = scoringAppUid;
         }
 
         void connect(Context context) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 026c77a..04d1c8f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -367,6 +367,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.FORCE_NEW_TASK_FLAGS;
+import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED;
 import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
 import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
 import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
@@ -690,19 +691,21 @@
         public AssistStructure structure = null;
         public AssistContent content = null;
         public Bundle receiverExtras;
+        public int resultCode;
         public int flags;
 
         public PendingAssistExtras(ActivityRecord _activity, Bundle _extras, Intent _intent,
-                String _hint, IResultReceiver _receiver, Bundle _receiverExtras, int _flags,
-                int _userHandle) {
+                String _hint, IResultReceiver _receiver, Bundle _receiverExtras, int _resultCode,
+                int _userHandle, int _flags) {
             activity = _activity;
             extras = _extras;
             intent = _intent;
             hint = _hint;
             receiver = _receiver;
             receiverExtras = _receiverExtras;
-            flags = _flags;
+            resultCode = _resultCode;
             userHandle = _userHandle;
+            flags = _flags;
         }
         @Override
         public void run() {
@@ -9525,12 +9528,7 @@
                 Slog.w(TAG, "setTaskResizeable: taskId=" + taskId + " not found");
                 return;
             }
-            if (task.mResizeMode != resizeableMode) {
-                task.mResizeMode = resizeableMode;
-                mWindowManager.setTaskResizeable(taskId, resizeableMode);
-                mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
-                mStackSupervisor.resumeFocusedStackTopActivityLocked();
-            }
+            task.setResizeMode(resizeableMode);
         }
     }
 
@@ -9563,13 +9561,12 @@
                 }
                 boolean preserveWindow = (resizeMode & RESIZE_MODE_PRESERVE_WINDOW) != 0;
                 if (stackId != task.getStackId()) {
-                    mStackSupervisor.moveTaskToStackUncheckedLocked(
-                            task, stackId, ON_TOP, !FORCE_FOCUS, "resizeTask");
+                    mStackSupervisor.moveTaskToStackUncheckedLocked(task, stackId, ON_TOP,
+                            !FORCE_FOCUS, "resizeTask", true /* allowStackOnTop */);
                     preserveWindow = false;
                 }
 
-                mStackSupervisor.resizeTaskLocked(task, bounds, resizeMode, preserveWindow,
-                        false /* deferResume */);
+                task.resize(bounds, resizeMode, preserveWindow, false /* deferResume */);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -9592,7 +9589,7 @@
                 if (task.getStack() != null) {
                     // Return the bounds from window manager since it will be adjusted for various
                     // things like the presense of a docked stack for tasks that aren't resizeable.
-                    mWindowManager.getTaskBounds(task.taskId, rect);
+                    task.getWindowContainerBounds(rect);
                 } else {
                     // Task isn't in window manager yet since it isn't associated with a stack.
                     // Return the persist value from activity manager
@@ -9610,6 +9607,44 @@
     }
 
     @Override
+    public void cancelTaskWindowTransition(int taskId) {
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "cancelTaskWindowTransition()");
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(
+                        taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);
+                if (task == null) {
+                    Slog.w(TAG, "cancelTaskWindowTransition: taskId=" + taskId + " not found");
+                    return;
+                }
+                task.cancelWindowTransition();
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
+    public void cancelTaskThumbnailTransition(int taskId) {
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "cancelTaskThumbnailTransition()");
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(
+                        taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);
+                if (task == null) {
+                    Slog.w(TAG, "cancelTaskThumbnailTransition: taskId=" + taskId + " not found");
+                    return;
+                }
+                task.cancelThumbnailTransition();
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
     public Bitmap getTaskDescriptionIcon(String filePath, int userId) {
         if (userId != UserHandle.getCallingUserId()) {
             enforceCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
@@ -9947,7 +9982,7 @@
                 // Defer the resume so resume/pausing while moving stacks is dangerous.
                 mStackSupervisor.moveTaskToStackLocked(topTask.taskId, DOCKED_STACK_ID,
                         false /* toTop */, !FORCE_FOCUS, "swapDockedAndFullscreenStack",
-                        ANIMATE, true /* deferResume */);
+                        ANIMATE, true /* deferResume */, true /* allowStackOnTop */);
                 final int size = tasks.size();
                 for (int i = 0; i < size; i++) {
                     final int id = tasks.get(i).taskId;
@@ -9956,7 +9991,8 @@
                     }
                     mStackSupervisor.moveTaskToStackLocked(id,
                             FULLSCREEN_WORKSPACE_STACK_ID, true /* toTop */, !FORCE_FOCUS,
-                            "swapDockedAndFullscreenStack", ANIMATE, true /* deferResume */);
+                            "swapDockedAndFullscreenStack", ANIMATE, true /* deferResume */,
+                            true /* allowStackOnTop */);
                 }
 
                 // Because we deferred the resume, to avoid conflicts with stack switches while
@@ -9997,7 +10033,7 @@
                 mWindowManager.setDockedStackCreateState(createMode, initialBounds);
                 final boolean moved = mStackSupervisor.moveTaskToStackLocked(
                         taskId, DOCKED_STACK_ID, toTop, !FORCE_FOCUS, "moveTaskToDockedStack",
-                        animate, DEFER_RESUME);
+                        animate, DEFER_RESUME, true /* allowStackOnTop */);
                 if (moved) {
                     if (moveHomeStackFront) {
                         mStackSupervisor.moveHomeStackToFront("moveTaskToDockedStack");
@@ -10111,10 +10147,12 @@
         synchronized (this) {
             long ident = Binder.clearCallingIdentity();
             try {
-                if (DEBUG_STACK) Slog.d(TAG_STACK,
-                        "positionTaskInStack: positioning task=" + taskId
-                        + " in stackId=" + stackId + " at position=" + position);
-                mStackSupervisor.positionTaskInStackLocked(taskId, stackId, position);
+                if (DEBUG_STACK) Slog.d(TAG_STACK, "positionTaskInStack: positioning task="
+                        + taskId + " in stackId=" + stackId + " at position=" + position);
+                final ActivityStack stack = mStackSupervisor.getStack(stackId, CREATE_IF_NEEDED,
+                        !ON_TOP);
+
+                stack.positionChildAt(taskId, position);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -11837,20 +11875,20 @@
         }
 
         synchronized (this) {
-            if (mStackSupervisor.isUserLockedProfile(userId)) {
-                final long ident = Binder.clearCallingIdentity();
-                try {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                if (mUserController.shouldConfirmCredentials(userId)) {
                     final int currentUserId = mUserController.getCurrentUserIdLocked();
-                    if (mUserController.isLockScreenDisabled(currentUserId)) {
-                        // If there is no device lock, we will show the profile's credential page.
-                        mActivityStarter.showConfirmDeviceCredential(userId);
+                    if (!mKeyguardController.isKeyguardLocked()) {
+                        // If the device is not locked, we will prompt for credentials immediately.
+                        mStackSupervisor.lockAllProfileTasks(userId);
                     } else {
                         // Showing launcher to avoid user entering credential twice.
                         startHomeActivityLocked(currentUserId, "notifyLockedProfile");
                     }
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
                 }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
             }
         }
     }
@@ -12193,7 +12231,7 @@
     @Override
     public Bundle getAssistContextExtras(int requestType) {
         PendingAssistExtras pae = enqueueAssistContext(requestType, null, null, null,
-                null, null, true /* focused */, true /* newSessionId */,
+                null, 0, null, true /* focused */, true /* newSessionId */,
                 UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT, 0);
         if (pae == null) {
             return null;
@@ -12261,22 +12299,37 @@
             Bundle receiverExtras,
             IBinder activityToken, boolean focused, boolean newSessionId) {
         return enqueueAssistContext(requestType, null, null, receiver, receiverExtras,
-                activityToken, focused, newSessionId,
-                UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_LONG_TIMEOUT, 0)
-                != null;
+                0, activityToken, focused, newSessionId, UserHandle.getCallingUserId(), null,
+                PENDING_ASSIST_EXTRAS_LONG_TIMEOUT, 0) != null;
     }
 
     @Override
     public boolean requestAutoFillData(IResultReceiver receiver, Bundle receiverExtras,
-            IBinder activityToken, int flags) {
-        return enqueueAssistContext(ActivityManager.ASSIST_CONTEXT_FULL, null, null, receiver,
-                receiverExtras, activityToken, true, true,
-                UserHandle.getCallingUserId(), null, PENDING_AUTO_FILL_ASSIST_STRUCTURE_TIMEOUT,
-                flags) != null;
+            int resultCode, IBinder activityToken, int flags) {
+        final boolean forFill = (flags & View.AUTO_FILL_FLAG_TYPE_FILL) != 0;
+        final boolean forSave = (flags & View.AUTO_FILL_FLAG_TYPE_SAVE) != 0;
+        if ((forFill && forSave) || (!forFill) && !(forSave)) {
+            // There can be only one!
+            Slog.w(TAG,  "requestAutoFillData(): invalid flags (" + flags + ")");
+            return false;
+        }
+
+        // NOTE: we could always use ActivityManager.ASSIST_CONTEXT_FULL and let ActivityThread
+        // rely on the flags to decide whether the handleRequestAssistContextExtras() is for
+        // auto-fill, but it's safer to explicitly use new AutoFill types, in case the Assist
+        // requests use flags in the future as well (since their flags value might collide with the
+        // auto-fill flag values).
+        final int type = forFill?
+                ActivityManager.ASSIST_CONTEXT_AUTO_FILL :
+                    ActivityManager.ASSIST_CONTEXT_AUTO_FILL_SAVE;
+
+        return enqueueAssistContext(type, null, null, receiver, receiverExtras, resultCode,
+                activityToken, true, true, UserHandle.getCallingUserId(), null,
+                PENDING_AUTO_FILL_ASSIST_STRUCTURE_TIMEOUT, flags) != null;
     }
 
     private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint,
-            IResultReceiver receiver, Bundle receiverExtras, IBinder activityToken,
+            IResultReceiver receiver, Bundle receiverExtras, int resultCode, IBinder activityToken,
             boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout,
             int flags) {
         enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
@@ -12317,7 +12370,7 @@
             extras.putString(Intent.EXTRA_ASSIST_PACKAGE, activity.packageName);
             extras.putInt(Intent.EXTRA_ASSIST_UID, activity.app.uid);
             pae = new PendingAssistExtras(activity, extras, intent, hint, receiver, receiverExtras,
-                    flags, userHandle);
+                    resultCode, userHandle, flags);
             // Increment the sessionId if necessary
             if (newSessionId) {
                 mViSessionId++;
@@ -12403,17 +12456,15 @@
                 if (pae.flags > 0) {
                     sendBundle.putInt(VoiceInteractionSession.KEY_FLAGS, pae.flags);
                 }
-                IBinder autoFillCallback =
-                        extras.getBinder(AutoFillService.KEY_CALLBACK);
-                if (autoFillCallback != null) {
-                    sendBundle.putBinder(AutoFillService.KEY_CALLBACK,
-                            autoFillCallback);
+                IBinder cb = extras.getBinder(AutoFillService.KEY_CALLBACK);
+                if (cb != null) {
+                    sendBundle.putBinder(AutoFillService.KEY_CALLBACK, cb);
                 }
             }
         }
         if (sendReceiver != null) {
             try {
-                sendReceiver.send(0, sendBundle);
+                sendReceiver.send(pae.resultCode, sendBundle);
             } catch (RemoteException e) {
             }
             return;
@@ -12438,9 +12489,9 @@
 
     public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle,
             Bundle args) {
-        return enqueueAssistContext(requestType, intent, hint, null, null, null,
-                true /* focused */, true /* newSessionId */,
-                userHandle, args, PENDING_ASSIST_EXTRAS_TIMEOUT, 0) != null;
+        return enqueueAssistContext(requestType, intent, hint, null, null, 0, null,
+                true /* focused */, true /* newSessionId */, userHandle, args,
+                PENDING_ASSIST_EXTRAS_TIMEOUT, 0) != null;
     }
 
     public void registerProcessObserver(IProcessObserver observer) {
@@ -17878,6 +17929,11 @@
 
     private void checkBroadcastFromSystem(Intent intent, ProcessRecord callerApp,
             String callerPackage, int callingUid, boolean isProtectedBroadcast, List receivers) {
+        if ((intent.getFlags() & Intent.FLAG_RECEIVER_FROM_SHELL) != 0) {
+            // Don't yell about broadcasts sent via shell
+            return;
+        }
+
         final String action = intent.getAction();
         if (isProtectedBroadcast
                 || Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
@@ -18021,11 +18077,7 @@
             case Process.PHONE_UID:
             case Process.BLUETOOTH_UID:
             case Process.NFC_UID:
-                if ((intent.getFlags() & Intent.FLAG_RECEIVER_FROM_SHELL) != 0) {
-                    isCallerSystem = false;
-                } else {
-                    isCallerSystem = true;
-                }
+                isCallerSystem = true;
                 break;
             default:
                 isCallerSystem = (callerApp != null) && callerApp.persistent;
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 3f166fe..e46d204 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -172,7 +172,7 @@
         MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS,
                 (int) (SystemClock.uptimeMillis() / 1000));
 
-        LogBuilder builder = new LogBuilder();
+        LogBuilder builder = new LogBuilder(MetricsEvent.APP_TRANSITION);
         builder.addTaggedData(MetricsEvent.APP_TRANSITION_COMPONENT_NAME, componentName);
         builder.addTaggedData(MetricsEvent.APP_TRANSITION_PROCESS_RUNNING, processRunning ? 1 : 0);
         builder.addTaggedData(MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS,
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 0e4ab96..2963ad1 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -41,7 +41,6 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
 import static android.os.Build.VERSION_CODES.HONEYCOMB;
 import static android.os.Process.SYSTEM_UID;
-import static android.view.Display.DEFAULT_DISPLAY;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SCREENSHOTS;
@@ -75,7 +74,6 @@
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.IBinder;
@@ -103,6 +101,7 @@
 import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
 import com.android.server.wm.AppWindowContainerController;
 import com.android.server.wm.AppWindowContainerListener;
+import com.android.server.wm.TaskWindowContainerController;
 
 import java.io.File;
 import java.io.IOException;
@@ -724,6 +723,10 @@
                 null : ComponentName.unflattenFromString(aInfo.requestedVrComponent);
     }
 
+    AppWindowContainerController getWindowContainerController() {
+        return mWindowContainerController;
+    }
+
     void createWindowContainer() {
         if (mWindowContainerController != null) {
             throw new IllegalArgumentException("Window container=" + mWindowContainerController
@@ -734,9 +737,10 @@
         inHistory = true;
 
         task.updateOverrideConfigurationFromLaunchBounds();
+        final TaskWindowContainerController taskController = task.getWindowContainerController();
 
-        mWindowContainerController = new AppWindowContainerController(appToken, this, task.taskId,
-                Integer.MAX_VALUE /* add on top */, info.screenOrientation, fullscreen,
+        mWindowContainerController = new AppWindowContainerController(taskController, appToken,
+                this, Integer.MAX_VALUE /* add on top */, info.screenOrientation, fullscreen,
                 (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, info.configChanges,
                 task.voiceSession != null, mLaunchTaskBehind, isAlwaysFocusable(),
                 appInfo.targetSdkVersion, mRotationAnimationHint,
@@ -749,12 +753,7 @@
 
     void removeWindowContainer() {
         mWindowContainerController.removeContainer(getDisplayId());
-    }
-
-    // TODO: Remove once task record is converted to use controller in which case we can use
-    // positionChildAt()
-    void positionWindowContainerAt(int index) {
-        mWindowContainerController.positionAt(task.taskId, index);
+        mWindowContainerController = null;
     }
 
     private boolean isHomeIntent(Intent intent) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index f7c3cea..ab65eb1 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -737,7 +737,7 @@
 
         task = topTask();
         if (task != null) {
-            mWindowManager.moveTaskToTop(task.taskId);
+            task.moveWindowContainerToTop(true /* includingParents */);
         }
     }
 
@@ -756,7 +756,7 @@
             mTaskHistory.remove(task);
             mTaskHistory.add(0, task);
             updateTaskMovement(task, false);
-            mWindowManager.moveTaskToBottom(task.taskId);
+            task.moveWindowContainerToBottom();
         }
     }
 
@@ -2557,10 +2557,16 @@
         position = Math.min(position, maxPosition);
         mTaskHistory.remove(task);
         mTaskHistory.add(position, task);
+        task.positionWindowContainerAt(mStackId, position);
         updateTaskMovement(task, true);
     }
 
     private void insertTaskAtTop(TaskRecord task, ActivityRecord newActivity) {
+        insertTaskAtTop(task, newActivity, true /* allowStackOnTop */);
+    }
+
+    private void insertTaskAtTop(TaskRecord task, ActivityRecord newActivity,
+            boolean allowStackOnTop) {
         boolean isLastTaskOverHome = false;
         // If the moving task is over home stack, transfer its return type to next task
         if (task.isOverHomeStack()) {
@@ -2619,7 +2625,7 @@
         }
         mTaskHistory.add(taskNdx, task);
         updateTaskMovement(task, true);
-        mWindowManager.moveTaskToTop(task.taskId);
+        task.moveWindowContainerToTop(allowStackOnTop /* includingParents */);
     }
 
     final void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
@@ -2863,7 +2869,7 @@
                     targetTask.addActivityAtBottom(p);
                 }
 
-                mWindowManager.moveTaskToBottom(targetTask.taskId);
+                targetTask.moveWindowContainerToBottom();
                 replyChainEnd = -1;
             } else if (forceReset || finishOnTaskLaunch || clearWhenTaskReset) {
                 // If the activity should just be removed -- either
@@ -2999,7 +3005,7 @@
                         if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Pulling activity " + p
                                 + " from " + srcPos + " in to resetting task " + task);
                     }
-                    mWindowManager.moveTaskToTop(taskId);
+                    task.moveWindowContainerToTop(true /* includingParents */);
 
                     // Now we've moved it in to place...  but what if this is
                     // a singleTop activity and we have put it on top of another
@@ -4368,7 +4374,7 @@
         }
 
         mWindowManager.prepareAppTransition(TRANSIT_TASK_TO_BACK, false);
-        mWindowManager.moveTaskToBottom(taskId);
+        tr.moveWindowContainerToBottom();
 
         final TaskRecord task = mResumedActivity != null ? mResumedActivity.task : null;
         if (prevIsHome || (task == tr && canGoHome) || (numTasks <= 1 && isOnHomeDisplay())) {
@@ -4800,14 +4806,7 @@
      */
     void removeTask(TaskRecord task, String reason, int mode) {
         if (mode == REMOVE_TASK_MODE_DESTROYING) {
-            mStackSupervisor.removeLockedTaskLocked(task);
-            mWindowManager.removeTask(task.taskId);
-            if (!StackId.persistTaskBounds(mStackId)) {
-                // Reset current bounds for task whose bounds shouldn't be persisted so it uses
-                // default configuration the next time it launches.
-                task.updateOverrideConfiguration(null);
-            }
-            mService.mTaskChangeNotificationController.notifyTaskRemoved(task.taskId);
+            task.removeWindowContainer();
         }
 
         final ActivityRecord r = mResumedActivity;
@@ -4879,11 +4878,7 @@
                 && !isLockscreenShown) {
             task.updateOverrideConfiguration(mBounds);
         }
-        final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();
-        final boolean showForAllUsers = (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0;
-        mWindowManager.addTask(taskId, mStackId, task.userId, bounds,
-                task.getOverrideConfiguration(), task.mResizeMode, task.isHomeTask(),
-                task.isOnTopLauncher(), toTop, showForAllUsers);
+        task.createWindowContainer(toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
         return task;
     }
 
@@ -4900,11 +4895,16 @@
     }
 
     void addTask(final TaskRecord task, final boolean toTop, String reason) {
+        addTask(task, toTop, reason, true /* allowStackOnTop */);
+    }
+
+    void addTask(final TaskRecord task, final boolean toTop, String reason,
+            boolean allowStackOnTop) {
         final ActivityStack prevStack = preAddTask(task, reason, toTop);
 
         task.setStack(this);
         if (toTop) {
-            insertTaskAtTop(task, null);
+            insertTaskAtTop(task, null, allowStackOnTop);
         } else {
             mTaskHistory.add(0, task);
             updateTaskMovement(task, false);
@@ -4912,13 +4912,20 @@
         postAddTask(task, prevStack);
     }
 
-    /** @see ActivityManagerService#positionTaskInStack(int, int, int). */
-    void positionTask(final TaskRecord task, int position) {
+    void positionChildAt(int taskId, int index) {
+        final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
+        if (task == null) {
+            Slog.w(TAG, "positionTaskInStackLocked: no task for id=" + taskId);
+            return;
+        }
+
+        task.updateOverrideConfigurationForStack(this);
+
         final ActivityRecord topRunningActivity = task.topRunningActivityLocked();
         final boolean wasResumed = topRunningActivity == task.getStack().mResumedActivity;
         final ActivityStack prevStack = preAddTask(task, "positionTask", !ON_TOP);
         task.setStack(this);
-        insertTaskAtPosition(task, position);
+        insertTaskAtPosition(task, index);
         postAddTask(task, prevStack);
         if (wasResumed) {
             if (mResumedActivity != null) {
@@ -4928,6 +4935,11 @@
             }
             mResumedActivity = topRunningActivity;
         }
+
+        // The task might have already been running and its visibility needs to be synchronized with
+        // the visibility of the stack / windows.
+        ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+        mStackSupervisor.resumeFocusedStackTopActivityLocked();
     }
 
     private ActivityStack preAddTask(TaskRecord task, String reason, boolean toTop) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 8bd7c90..8cf0708 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -89,6 +89,8 @@
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
 import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS;
+import static java.lang.Integer.MAX_VALUE;
+import static java.lang.Integer.MIN_VALUE;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -175,7 +177,6 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import java.util.Objects;
 import java.util.Set;
 
 public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener {
@@ -763,43 +764,52 @@
     }
 
     /**
-     * TODO: Handle freefom mode.
-     * @return true when credential confirmation is needed for the user and there is any
-     *         activity started by the user in any visible stack.
+     * Detects whether we should show a lock screen in front of this task for a locked user.
+     * <p>
+     * We'll do this if either of the following holds:
+     * <ul>
+     *   <li>The top activity explicitly belongs to {@param userId}.</li>
+     *   <li>The top activity returns a result to an activity belonging to {@param userId}.</li>
+     * </ul>
+     *
+     * @return {@code true} if the top activity looks like it belongs to {@param userId}.
      */
-    boolean isUserLockedProfile(@UserIdInt int userId) {
-        if (!mService.mUserController.shouldConfirmCredentials(userId)) {
-            return false;
-        }
-        final ActivityStack fullScreenStack = getStack(FULLSCREEN_WORKSPACE_STACK_ID);
-        final ActivityStack dockedStack = getStack(DOCKED_STACK_ID);
-        final ActivityStack[] activityStacks = new ActivityStack[] {fullScreenStack, dockedStack};
-        for (final ActivityStack activityStack : activityStacks) {
-            if (activityStack == null) {
-                continue;
-            }
-            if (activityStack.topRunningActivityLocked() == null) {
-                continue;
-            }
-            if (activityStack.getStackVisibilityLocked(null) == STACK_INVISIBLE) {
-                continue;
-            }
-            if (activityStack.isDockedStack() && mIsDockMinimized) {
-                continue;
-            }
-            final TaskRecord topTask = activityStack.topTask();
-            if (topTask == null) {
-                continue;
-            }
-            // To handle the case that work app is in the task but just is not the top one.
-            for (int i = topTask.mActivities.size() - 1; i >= 0; i--) {
-                final ActivityRecord activityRecord = topTask.mActivities.get(i);
-                if (activityRecord.userId == userId) {
-                    return true;
+    private boolean taskTopActivityIsUser(TaskRecord task, @UserIdInt int userId) {
+        // To handle the case that work app is in the task but just is not the top one.
+        final ActivityRecord activityRecord = task.getTopActivity();
+        final ActivityRecord resultTo = (activityRecord != null ? activityRecord.resultTo : null);
+
+        return (activityRecord != null && activityRecord.userId == userId)
+                || (resultTo != null && resultTo.userId == userId);
+    }
+
+    /**
+     * Find all visible task stacks containing {@param userId} and intercept them with an activity
+     * to block out the contents and possibly start a credential-confirming intent.
+     *
+     * @param userId user handle for the locked managed profile.
+     */
+    void lockAllProfileTasks(@UserIdInt int userId) {
+        mWindowManager.deferSurfaceLayout();
+        try {
+            final List<ActivityStack> stacks = getStacks();
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; stackNdx--) {
+                final List<TaskRecord> tasks = stacks.get(stackNdx).getAllTasks();
+                for (int taskNdx = tasks.size() - 1; taskNdx >= 0; taskNdx--) {
+                    final TaskRecord task = tasks.get(taskNdx);
+
+                    // Check the task for a top activity belonging to userId, or returning a result
+                    // to an activity belonging to userId. Example case: a document picker for
+                    // personal files, opened by a work app, should still get locked.
+                    if (taskTopActivityIsUser(task, userId)) {
+                        mService.mTaskChangeNotificationController.notifyTaskProfileLocked(
+                                task.taskId, userId);
+                    }
                 }
             }
+        } finally {
+            mWindowManager.continueSurfaceLayout();
         }
-        return false;
     }
 
     void setNextTaskIdForUserLocked(int taskId, int userId) {
@@ -1923,7 +1933,7 @@
                 }
                 if (stackId != currentStack.mStackId) {
                     currentStack = moveTaskToStackUncheckedLocked(task, stackId, ON_TOP,
-                            !FORCE_FOCUS, reason);
+                            !FORCE_FOCUS, reason, true /* allowStackOnTop */);
                     stackId = currentStack.mStackId;
                     // moveTaskToStackUncheckedLocked() should already placed the task on top,
                     // still need moveTaskToFrontLocked() below for any transition settings.
@@ -1936,9 +1946,7 @@
                     // WM resizeTask must be done after the task is moved to the correct stack,
                     // because Task's setBounds() also updates dim layer's bounds, but that has
                     // dependency on the stack.
-                    mWindowManager.resizeTask(task.taskId, task.mBounds,
-                            task.getOverrideConfiguration(), false /* relayout */,
-                            false /* forced */);
+                    task.resizeWindowContainer();
                 }
             }
         }
@@ -2164,8 +2172,10 @@
         continueUpdateBounds(HOME_STACK_ID);
         for (int i = mResizingTasksDuringAnimation.size() - 1; i >= 0; i--) {
             final int taskId = mResizingTasksDuringAnimation.valueAt(i);
-            if (anyTaskForIdLocked(taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID) != null) {
-                mWindowManager.setTaskDockedResizing(taskId, false);
+            final TaskRecord task =
+                    anyTaskForIdLocked(taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);
+            if (task != null) {
+                task.setTaskDockedResizing(false);
             }
         }
         mResizingTasksDuringAnimation.clear();
@@ -2211,7 +2221,7 @@
                 // display because it no longer contains any tasks.
                 mAllowDockedStackResize = false;
             }
-            final ActivityStack fullscreenStack = getStack(FULLSCREEN_WORKSPACE_STACK_ID);
+            ActivityStack fullscreenStack = getStack(FULLSCREEN_WORKSPACE_STACK_ID);
             final boolean isFullscreenStackVisible = fullscreenStack != null &&
                     fullscreenStack.getStackVisibilityLocked(null) == STACK_VISIBLE;
             final ArrayList<TaskRecord> tasks = stack.getAllTasks();
@@ -2228,15 +2238,18 @@
                     }
                     moveTaskToStackLocked(tasks.get(i).taskId,
                             FULLSCREEN_WORKSPACE_STACK_ID, onTop, onTop /*forceFocus*/,
-                            "moveTasksToFullscreenStack", ANIMATE, DEFER_RESUME);
+                            "moveTasksToFullscreenStack - onTop", ANIMATE, DEFER_RESUME,
+                            true /* allowStackOnTop */);
                 }
 
                 ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
                 resumeFocusedStackTopActivityLocked();
             } else {
-                for (int i = size - 1; i >= 0; i--) {
-                    positionTaskInStackLocked(tasks.get(i).taskId,
-                            FULLSCREEN_WORKSPACE_STACK_ID, 0 /* position */);
+                for (int i = 0; i < size; i++) {
+                    moveTaskToStackLocked(tasks.get(i).taskId, FULLSCREEN_WORKSPACE_STACK_ID,
+                            true /* onTop */, false /* forceFocus */,
+                            "moveTasksToFullscreenStack - NOT_onTop", !ANIMATE, DEFER_RESUME,
+                            false /* allowStackOnTop */);
                 }
             }
         } finally {
@@ -2337,71 +2350,6 @@
         }
     }
 
-    boolean resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow,
-            boolean deferResume) {
-        if (!task.isResizeable()) {
-            Slog.w(TAG, "resizeTask: task " + task + " not resizeable.");
-            return true;
-        }
-
-        // If this is a forced resize, let it go through even if the bounds is not changing,
-        // as we might need a relayout due to surface size change (to/from fullscreen).
-        final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
-        if (Objects.equals(task.mBounds, bounds) && !forced) {
-            // Nothing to do here...
-            return true;
-        }
-        bounds = TaskRecord.validateBounds(bounds);
-
-        if (!mWindowManager.isValidTaskId(task.taskId)) {
-            // Task doesn't exist in window manager yet (e.g. was restored from recents).
-            // All we can do for now is update the bounds so it can be used when the task is
-            // added to window manager.
-            task.updateOverrideConfiguration(bounds);
-            if (task.getStackId() != FREEFORM_WORKSPACE_STACK_ID) {
-                // re-restore the task so it can have the proper stack association.
-                restoreRecentTaskLocked(task, FREEFORM_WORKSPACE_STACK_ID);
-            }
-            return true;
-        }
-
-        if (!task.canResizeToBounds(bounds)) {
-            throw new IllegalArgumentException("resizeTaskLocked: Can not resize task=" + task
-                    + " to bounds=" + bounds + " resizeMode=" + task.mResizeMode);
-        }
-
-        // Do not move the task to another stack here.
-        // This method assumes that the task is already placed in the right stack.
-        // we do not mess with that decision and we only do the resize!
-
-        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + task.taskId);
-
-        final boolean updatedConfig = task.updateOverrideConfiguration(bounds);
-        // This variable holds information whether the configuration didn't change in a significant
-        // way and the activity was kept the way it was. If it's false, it means the activity had
-        // to be relaunched due to configuration change.
-        boolean kept = true;
-        if (updatedConfig) {
-            final ActivityRecord r = task.topRunningActivityLocked();
-            if (r != null) {
-                kept = r.ensureActivityConfigurationLocked(0 /* globalChanges */, preserveWindow);
-
-                if (!deferResume) {
-                    // All other activities must be made visible with their correct configuration.
-                    ensureActivitiesVisibleLocked(r, 0, !PRESERVE_WINDOWS);
-                    if (!kept) {
-                        resumeFocusedStackTopActivityLocked();
-                    }
-                }
-            }
-        }
-        mWindowManager.resizeTask(task.taskId, task.mBounds, task.getOverrideConfiguration(), kept,
-                forced);
-
-        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
-        return kept;
-    }
-
     ActivityStack createStackOnDisplay(int stackId, int displayId, boolean onTop) {
         ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
         if (activityDisplay == null) {
@@ -2415,7 +2363,7 @@
     }
 
     /**
-     * Removes the stack associed with the given {@param stackId}.  If the {@param stackId} is the
+     * Removes the stack associated with the given {@param stackId}.  If the {@param stackId} is the
      * pinned stack, then its tasks are not explicitly removed when the stack is destroyed, but
      * instead moved back onto the fullscreen stack.
      */
@@ -2437,8 +2385,7 @@
                     final int insertPosition = isFullscreenStackVisible
                             ? Math.max(0, fullscreenStack.getChildCount() - 1)
                             : fullscreenStack.getChildCount();
-                    positionTaskInStackLocked(tasks.get(i).taskId, FULLSCREEN_WORKSPACE_STACK_ID,
-                            insertPosition);
+                    fullscreenStack.positionChildAt(tasks.get(i).taskId, insertPosition);
                 }
                 ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                 resumeFocusedStackTopActivityLocked();
@@ -2568,7 +2515,7 @@
      *                or is not a static stack).
      * @return true if the task has been restored successfully.
      */
-    private boolean restoreRecentTaskLocked(TaskRecord task, int stackId) {
+    boolean restoreRecentTaskLocked(TaskRecord task, int stackId) {
         if (!StackId.isStaticStack(stackId)) {
             // If stack is not static (or stack id is invalid) - use the default one.
             // This means that tasks that were on external displays will be restored on the
@@ -2603,10 +2550,8 @@
         }
 
         stack.addTask(task, false /* toTop */, "restoreRecentTask");
-        final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();
-        mWindowManager.addTask(task.taskId, stack.mStackId, task.userId, bounds,
-                task.getOverrideConfiguration(), task.mResizeMode, task.isHomeTask(),
-                task.isOnTopLauncher(), false /* toTop */, true /* showForAllUsers */);
+        // TODO: move call for creation here and other place into Stack.addTask()
+        task.createWindowContainer(false /* toTop */, true /* showForAllUsers */);
         if (DEBUG_RECENTS) Slog.v(TAG_RECENTS,
                 "Added restored task=" + task + " to stack=" + stack);
         final ArrayList<ActivityRecord> activities = task.mActivities;
@@ -2660,10 +2605,13 @@
      * @param toTop True if the task should be placed at the top of the stack.
      * @param forceFocus if focus should be moved to the new stack
      * @param reason Reason the task is been moved.
+     * @param allowStackOnTop If stack movement should be moved to the top due to the addition of
+     *                        the task to the stack. E.g. Moving the stack to the front because it
+     *                        should be focused because it now contains the focused activity.
      * @return The stack the task was moved to.
      */
-    ActivityStack moveTaskToStackUncheckedLocked(
-            TaskRecord task, int stackId, boolean toTop, boolean forceFocus, String reason) {
+    ActivityStack moveTaskToStackUncheckedLocked(TaskRecord task, int stackId, boolean toTop,
+            boolean forceFocus, String reason, boolean allowStackOnTop) {
 
         if (StackId.isMultiWindowStack(stackId) && !mService.mSupportsMultiWindow) {
             throw new IllegalStateException("moveTaskToStackUncheckedLocked: Device doesn't "
@@ -2694,15 +2642,15 @@
         // if a docked stack is created below which will lead to the stack we are moving from and
         // its resizeable tasks being resized.
         task.mTemporarilyUnresizable = true;
-        final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop);
+        final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop && allowStackOnTop);
         task.mTemporarilyUnresizable = false;
-        mWindowManager.moveTaskToStack(task.taskId, stack.mStackId, toTop);
-        stack.addTask(task, toTop, reason);
+        task.reparentWindowContainer(stack.mStackId, toTop ? MAX_VALUE : MIN_VALUE);
+        stack.addTask(task, toTop, reason, allowStackOnTop);
 
         // If the task had focus before (or we're requested to move focus),
         // move focus to the new stack by moving the stack to the front.
         stack.moveToFrontAndResumeStateIfNeeded(
-                r, forceFocus || wasFocused || wasFront, wasResumed, reason);
+                r, allowStackOnTop && (forceFocus || wasFocused || wasFront), wasResumed, reason);
 
         return stack;
     }
@@ -2710,11 +2658,11 @@
     boolean moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus,
             String reason, boolean animate) {
         return moveTaskToStackLocked(taskId, stackId, toTop, forceFocus, reason, animate,
-                false /* deferResume */);
+                false /* deferResume */, true /* allowStackOnTop */);
     }
 
     boolean moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus,
-            String reason, boolean animate, boolean deferResume) {
+            String reason, boolean animate, boolean deferResume, boolean allowStackOnTop) {
         final TaskRecord task = anyTaskForIdLocked(taskId);
         if (task == null) {
             Slog.w(TAG, "moveTaskToStack: no task for id=" + taskId);
@@ -2754,7 +2702,7 @@
         boolean kept = true;
         try {
             final ActivityStack stack = moveTaskToStackUncheckedLocked(
-                    task, stackId, toTop, forceFocus, reason + " moveTaskToStack");
+                    task, stackId, toTop, forceFocus, reason + " moveTaskToStack", allowStackOnTop);
             stackId = stack.mStackId;
 
             if (!animate) {
@@ -2766,19 +2714,18 @@
 
             // Make sure the task has the appropriate bounds/size for the stack it is in.
             if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) {
-                kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM,
-                        !mightReplaceWindow, deferResume);
+                kept = task.resize(stack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow,
+                        deferResume);
             } else if (stackId == FREEFORM_WORKSPACE_STACK_ID) {
                 Rect bounds = task.getLaunchBounds();
                 if (bounds == null) {
                     stack.layoutTaskInStack(task, null);
                     bounds = task.mBounds;
                 }
-                kept = resizeTaskLocked(task, bounds, RESIZE_MODE_FORCED, !mightReplaceWindow,
-                        deferResume);
+                kept = task.resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume);
             } else if (stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID) {
-                kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM,
-                        !mightReplaceWindow, deferResume);
+                kept = task.resize(stack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow,
+                        deferResume);
             }
         } finally {
             mWindowManager.continueSurfaceLayout();
@@ -2908,28 +2855,6 @@
         return true;
     }
 
-    /** @see ActivityManagerService#positionTaskInStack(int, int, int). */
-    void positionTaskInStackLocked(int taskId, int stackId, int position) {
-        final TaskRecord task = anyTaskForIdLocked(taskId);
-        if (task == null) {
-            Slog.w(TAG, "positionTaskInStackLocked: no task for id=" + taskId);
-            return;
-        }
-        final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, !ON_TOP);
-
-        task.updateOverrideConfigurationForStack(stack);
-
-        // TODO: Return final position from WM for AM to use instead of duplicating computations in
-        // ActivityStack#insertTaskAtPosition.
-        mWindowManager.positionTaskInStack(
-                taskId, stackId, position, task.mBounds, task.getOverrideConfiguration());
-        stack.positionTask(task, position);
-        // The task might have already been running and its visibility needs to be synchronized with
-        // the visibility of the stack / windows.
-        stack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
-        resumeFocusedStackTopActivityLocked();
-    }
-
     ActivityRecord findTaskLocked(ActivityRecord r) {
         mTmpFindTaskResult.r = null;
         mTmpFindTaskResult.matchedByRootAffinity = false;
@@ -3352,7 +3277,7 @@
                 stack.switchUserLocked(userId);
                 TaskRecord task = stack.topTask();
                 if (task != null) {
-                    mWindowManager.moveTaskToTop(task.taskId);
+                    task.moveWindowContainerToTop(true /* includingParents */);
                 }
             }
         }
@@ -3813,7 +3738,7 @@
                     : task.getTopActivity() != null ? task.getTopActivity().packageName
                     : "unknown";
             taskBounds[i] = new Rect();
-            mWindowManager.getTaskBounds(task.taskId, taskBounds[i]);
+            task.getWindowContainerBounds(taskBounds[i]);
             taskUserIds[i] = task.userId;
         }
         info.taskIds = taskIds;
@@ -4768,11 +4693,11 @@
     /**
      * Puts a task into resizing mode during the next app transition.
      *
-     * @param taskId the id of the task to put into resizing mode
+     * @param task The task to put into resizing mode
      */
-    private void setResizingDuringAnimation(int taskId) {
-        mResizingTasksDuringAnimation.add(taskId);
-        mWindowManager.setTaskDockedResizing(taskId, true);
+    private void setResizingDuringAnimation(TaskRecord task) {
+        mResizingTasksDuringAnimation.add(task.taskId);
+        task.setTaskDockedResizing(true);
     }
 
     final int startActivityFromRecentsInner(int taskId, Bundle bOptions) {
@@ -4837,7 +4762,7 @@
             // the window renders full-screen with the background filling the void. Also only
             // call this at the end to make sure that tasks exists on the window manager side.
             if (launchStackId == DOCKED_STACK_ID) {
-                setResizingDuringAnimation(taskId);
+                setResizingDuringAnimation(task);
             }
 
             mService.mActivityStarter.postStartActivityUncheckedProcessing(task.getTopActivity(),
@@ -4854,7 +4779,7 @@
         int result = mService.startActivityInPackage(callingUid, callingPackage, intent, null,
                 null, null, 0, 0, bOptions, userId, null, task);
         if (launchStackId == DOCKED_STACK_ID) {
-            setResizingDuringAnimation(task.taskId);
+            setResizingDuringAnimation(task);
         }
         return result;
     }
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 007a478..61e3ad5 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1770,8 +1770,8 @@
             mInTask.updateOverrideConfiguration(mLaunchBounds);
             int stackId = mInTask.getLaunchStackId();
             if (stackId != mInTask.getStackId()) {
-                final ActivityStack stack = mSupervisor.moveTaskToStackUncheckedLocked(
-                        mInTask, stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront");
+                final ActivityStack stack = mSupervisor.moveTaskToStackUncheckedLocked(mInTask,
+                        stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront", true /* allowStackOnTop */);
                 stackId = stack.mStackId;
             }
             if (StackId.resizeStackWithLaunchBounds(stackId)) {
@@ -1824,7 +1824,7 @@
                 mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId), mStartActivity.info,
                 mIntent, null, null, true, mStartActivity.mActivityType);
         mStartActivity.setTask(task, null);
-        mWindowManager.moveTaskToTop(mStartActivity.task.taskId);
+        mStartActivity.task.moveWindowContainerToTop(true /* includingParents */);
         if (DEBUG_TASKS) Slog.v(TAG_TASKS,
                 "Starting new activity " + mStartActivity + " in new guessed " + mStartActivity.task);
     }
diff --git a/services/core/java/com/android/server/am/TaskChangeNotificationController.java b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
index fd248c6..fbdbb1b 100644
--- a/services/core/java/com/android/server/am/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
@@ -39,6 +39,7 @@
     static final int NOTIFY_TASK_DESCRIPTION_CHANGED_LISTENERS_MSG = 11;
     static final int NOTIFY_ACTIVITY_REQUESTED_ORIENTATION_CHANGED_LISTENERS = 12;
     static final int NOTIFY_TASK_REMOVAL_STARTED_LISTENERS = 13;
+    static final int NOTIFY_TASK_PROFILE_LOCKED_LISTENERS_MSG = 14;
 
     // Delay in notifying task stack change listeners (in millis)
     static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
@@ -110,6 +111,9 @@
                 case NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG:
                     forAllListeners((listener) -> listener.onActivityDismissingDockedStack());
                     break;
+                case NOTIFY_TASK_PROFILE_LOCKED_LISTENERS_MSG:
+                    forAllListeners((listener) -> listener.onTaskProfileLocked(msg.arg1, msg.arg2));
+                    break;
             }
         }
     }
@@ -228,4 +232,13 @@
         mHandler.obtainMessage(NOTIFY_TASK_REMOVAL_STARTED_LISTENERS, taskId, 0 /* unused */)
                 .sendToTarget();
     }
+
+    /**
+     * Notify listeners that the task has been put in a locked state because one or more of the
+     * activities inside it belong to a managed profile user that has been locked.
+     */
+    void notifyTaskProfileLocked(int taskId, int userId) {
+        mHandler.obtainMessage(NOTIFY_TASK_PROFILE_LOCKED_LISTENERS_MSG, taskId, userId)
+                .sendToTarget();
+    }
 }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index a17cf3b..0d8829e 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -39,6 +39,7 @@
 import android.os.Debug;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.voice.IVoiceInteractionSession;
@@ -48,6 +49,7 @@
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.util.XmlUtils;
 
+import com.android.server.wm.TaskWindowContainerController;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -58,6 +60,7 @@
 import java.util.ArrayList;
 import java.util.Objects;
 
+import static android.app.ActivityManager.RESIZE_MODE_FORCED;
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
@@ -80,6 +83,7 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
@@ -95,6 +99,7 @@
 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.STARTING_WINDOW_SHOWN;
+import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
 
 final class TaskRecord extends ConfigurationContainer {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
@@ -280,6 +285,8 @@
     /** Helper object used for updating override configuration. */
     private Configuration mTmpConfig = new Configuration();
 
+    private TaskWindowContainerController mWindowContainerController;
+
     TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
             IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, int type) {
         mService = service;
@@ -389,6 +396,155 @@
         mService.mTaskChangeNotificationController.notifyTaskCreated(_taskId, realActivity);
     }
 
+    TaskWindowContainerController getWindowContainerController() {
+        return mWindowContainerController;
+    }
+
+    void createWindowContainer(boolean onTop, boolean showForAllUsers) {
+        if (mWindowContainerController != null) {
+            throw new IllegalArgumentException("Window container=" + mWindowContainerController
+                    + " already created for task=" + this);
+        }
+
+        final Rect bounds = updateOverrideConfigurationFromLaunchBounds();
+        final Configuration overrideConfig = getOverrideConfiguration();
+        mWindowContainerController = new TaskWindowContainerController(taskId, getStackId(), userId,
+                bounds, overrideConfig, mResizeMode, isHomeTask(), isOnTopLauncher(), onTop,
+                showForAllUsers);
+    }
+
+    void removeWindowContainer() {
+        mService.mStackSupervisor.removeLockedTaskLocked(this);
+        mWindowContainerController.removeContainer();
+        if (!StackId.persistTaskBounds(getStackId())) {
+            // Reset current bounds for task whose bounds shouldn't be persisted so it uses
+            // default configuration the next time it launches.
+            updateOverrideConfiguration(null);
+        }
+        mService.mTaskChangeNotificationController.notifyTaskRemoved(taskId);
+        mWindowContainerController = null;
+    }
+
+    void setResizeMode(int resizeMode) {
+        if (mResizeMode == resizeMode) {
+            return;
+        }
+        mResizeMode = resizeMode;
+        mWindowContainerController.setResizeable(resizeMode);
+        mService.mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+        mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
+    }
+
+    void setTaskDockedResizing(boolean resizing) {
+        mWindowContainerController.setTaskDockedResizing(resizing);
+    }
+
+    boolean resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume) {
+        if (!isResizeable()) {
+            Slog.w(TAG, "resizeTask: task " + this + " not resizeable.");
+            return true;
+        }
+
+        // If this is a forced resize, let it go through even if the bounds is not changing,
+        // as we might need a relayout due to surface size change (to/from fullscreen).
+        final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
+        if (Objects.equals(mBounds, bounds) && !forced) {
+            // Nothing to do here...
+            return true;
+        }
+        bounds = validateBounds(bounds);
+
+        if (mWindowContainerController == null) {
+            // Task doesn't exist in window manager yet (e.g. was restored from recents).
+            // All we can do for now is update the bounds so it can be used when the task is
+            // added to window manager.
+            updateOverrideConfiguration(bounds);
+            if (getStackId() != FREEFORM_WORKSPACE_STACK_ID) {
+                // re-restore the task so it can have the proper stack association.
+                mService.mStackSupervisor.restoreRecentTaskLocked(this,
+                        FREEFORM_WORKSPACE_STACK_ID);
+            }
+            return true;
+        }
+
+        if (!canResizeToBounds(bounds)) {
+            throw new IllegalArgumentException("resizeTask: Can not resize task=" + this
+                    + " to bounds=" + bounds + " resizeMode=" + mResizeMode);
+        }
+
+        // Do not move the task to another stack here.
+        // This method assumes that the task is already placed in the right stack.
+        // we do not mess with that decision and we only do the resize!
+
+        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + taskId);
+
+        final boolean updatedConfig = updateOverrideConfiguration(bounds);
+        // This variable holds information whether the configuration didn't change in a significant
+        // way and the activity was kept the way it was. If it's false, it means the activity had
+        // to be relaunched due to configuration change.
+        boolean kept = true;
+        if (updatedConfig) {
+            final ActivityRecord r = topRunningActivityLocked();
+            if (r != null) {
+                kept = r.ensureActivityConfigurationLocked(0 /* globalChanges */, preserveWindow);
+
+                if (!deferResume) {
+                    // All other activities must be made visible with their correct configuration.
+                    mService.mStackSupervisor.ensureActivitiesVisibleLocked(r, 0, !PRESERVE_WINDOWS);
+                    if (!kept) {
+                        mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
+                    }
+                }
+            }
+        }
+        mWindowContainerController.resize(mBounds, getOverrideConfiguration(), kept, forced);
+
+        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+        return kept;
+    }
+
+    // TODO: Investigate combining with the resize() method above.
+    void resizeWindowContainer() {
+        mWindowContainerController.resize(mBounds, getOverrideConfiguration(), false /* relayout */,
+                false /* forced */);
+    }
+
+    // TODO: Remove once we have a stack controller.
+    void positionWindowContainerAt(int stackId, int index) {
+        mWindowContainerController.positionAt(stackId, index, mBounds, getOverrideConfiguration());
+    }
+
+    // TODO: Replace with moveChildToTop?
+    void moveWindowContainerToTop(boolean includingParents) {
+        if (mWindowContainerController != null) {
+            mWindowContainerController.moveToTop(includingParents);
+        }
+    }
+
+    // TODO: Replace with moveChildToBottom?
+    void moveWindowContainerToBottom() {
+        if (mWindowContainerController != null) {
+            mWindowContainerController.moveToBottom();
+        }
+    }
+
+    void getWindowContainerBounds(Rect bounds) {
+        mWindowContainerController.getBounds(bounds);
+    }
+
+    // TODO: make this part of adding it to the stack?
+    void reparentWindowContainer(int stackId, int position) {
+        mWindowContainerController.reparent(stackId, position);
+    }
+
+    void cancelWindowTransition() {
+        mWindowContainerController.cancelWindowTransition();
+    }
+
+    void cancelThumbnailTransition() {
+        mWindowContainerController.cancelThumbnailTransition();
+    }
+
     void touchActiveTime() {
         lastActiveTime = System.currentTimeMillis();
         if (firstActiveTime == 0) {
@@ -852,7 +1008,7 @@
 
         // Sync. with window manager
         updateOverrideConfigurationFromLaunchBounds();
-        r.positionWindowContainerAt(index);
+        mWindowContainerController.positionChildAt(r.getWindowContainerController(), index);
         r.onOverrideConfigurationSent();
     }
 
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 6d96a10..79567d5 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -199,7 +199,8 @@
         mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
         mTetherMasterSM.start();
 
-        mUpstreamNetworkMonitor = new UpstreamNetworkMonitor();
+        mUpstreamNetworkMonitor = new UpstreamNetworkMonitor(
+                mContext, mTetherMasterSM, TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
 
         mStateReceiver = new StateReceiver();
         IntentFilter filter = new IntentFilter();
@@ -1027,38 +1028,6 @@
     }
 
     /**
-     * A NetworkCallback class that relays information of interest to the
-     * tethering master state machine thread for subsequent processing.
-     */
-    class UpstreamNetworkCallback extends NetworkCallback {
-        @Override
-        public void onAvailable(Network network) {
-            mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
-                    UpstreamNetworkMonitor.EVENT_ON_AVAILABLE, 0, network);
-        }
-
-        @Override
-        public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) {
-            mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
-                    UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES, 0,
-                    new NetworkState(null, null, newNc, network, null, null));
-        }
-
-        @Override
-        public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
-            mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
-                    UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES, 0,
-                    new NetworkState(null, newLp, null, network, null, null));
-        }
-
-        @Override
-        public void onLost(Network network) {
-            mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
-                    UpstreamNetworkMonitor.EVENT_ON_LOST, 0, network);
-        }
-    }
-
-    /**
      * A class to centralize all the network and link properties information
      * pertaining to the current and any potential upstream network.
      *
@@ -1072,21 +1041,31 @@
      * TODO: Investigate whether more "upstream-specific" logic/functionality
      * could/should be moved here.
      */
-    class UpstreamNetworkMonitor {
-        static final int EVENT_ON_AVAILABLE      = 1;
-        static final int EVENT_ON_CAPABILITIES   = 2;
-        static final int EVENT_ON_LINKPROPERTIES = 3;
-        static final int EVENT_ON_LOST           = 4;
+    public class UpstreamNetworkMonitor {
+        public static final int EVENT_ON_AVAILABLE      = 1;
+        public static final int EVENT_ON_CAPABILITIES   = 2;
+        public static final int EVENT_ON_LINKPROPERTIES = 3;
+        public static final int EVENT_ON_LOST           = 4;
 
-        final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
-        NetworkCallback mDefaultNetworkCallback;
-        NetworkCallback mDunTetheringCallback;
+        private final Context mContext;
+        private final StateMachine mTarget;
+        private final int mWhat;
+        private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
+        private ConnectivityManager mCM;
+        private NetworkCallback mDefaultNetworkCallback;
+        private NetworkCallback mDunTetheringCallback;
 
-        void start() {
+        public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, int what) {
+            mContext = ctx;
+            mTarget = tgt;
+            mWhat = what;
+        }
+
+        public void start() {
             stop();
 
             mDefaultNetworkCallback = new UpstreamNetworkCallback();
-            getConnectivityManager().registerDefaultNetworkCallback(mDefaultNetworkCallback);
+            cm().registerDefaultNetworkCallback(mDefaultNetworkCallback);
 
             final NetworkRequest dunTetheringRequest = new NetworkRequest.Builder()
                     .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
@@ -1094,29 +1073,28 @@
                     .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
                     .build();
             mDunTetheringCallback = new UpstreamNetworkCallback();
-            getConnectivityManager().registerNetworkCallback(
-                    dunTetheringRequest, mDunTetheringCallback);
+            cm().registerNetworkCallback(dunTetheringRequest, mDunTetheringCallback);
         }
 
-        void stop() {
+        public void stop() {
             if (mDefaultNetworkCallback != null) {
-                getConnectivityManager().unregisterNetworkCallback(mDefaultNetworkCallback);
+                cm().unregisterNetworkCallback(mDefaultNetworkCallback);
                 mDefaultNetworkCallback = null;
             }
 
             if (mDunTetheringCallback != null) {
-                getConnectivityManager().unregisterNetworkCallback(mDunTetheringCallback);
+                cm().unregisterNetworkCallback(mDunTetheringCallback);
                 mDunTetheringCallback = null;
             }
 
             mNetworkMap.clear();
         }
 
-        NetworkState lookup(Network network) {
+        public NetworkState lookup(Network network) {
             return (network != null) ? mNetworkMap.get(network) : null;
         }
 
-        NetworkState processCallback(int arg1, Object obj) {
+        public NetworkState processCallback(int arg1, Object obj) {
             switch (arg1) {
                 case EVENT_ON_AVAILABLE: {
                     final Network network = (Network) obj;
@@ -1128,7 +1106,7 @@
                                 new NetworkState(null, null, null, network, null, null));
                     }
 
-                    final ConnectivityManager cm = getConnectivityManager();
+                    final ConnectivityManager cm = cm();
 
                     if (mDefaultNetworkCallback != null) {
                         cm.requestNetworkCapabilities(mDefaultNetworkCallback);
@@ -1199,6 +1177,42 @@
                     return null;
             }
         }
+
+        // Fetch (and cache) a ConnectivityManager only if and when we need one.
+        private ConnectivityManager cm() {
+            if (mCM == null) {
+                mCM = mContext.getSystemService(ConnectivityManager.class);
+            }
+            return mCM;
+        }
+
+        /**
+         * A NetworkCallback class that relays information of interest to the
+         * tethering master state machine thread for subsequent processing.
+         */
+        private class UpstreamNetworkCallback extends NetworkCallback {
+            @Override
+            public void onAvailable(Network network) {
+                mTarget.sendMessage(mWhat, EVENT_ON_AVAILABLE, 0, network);
+            }
+
+            @Override
+            public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) {
+                mTarget.sendMessage(mWhat, EVENT_ON_CAPABILITIES, 0,
+                        new NetworkState(null, null, newNc, network, null, null));
+            }
+
+            @Override
+            public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
+                mTarget.sendMessage(mWhat, EVENT_ON_LINKPROPERTIES, 0,
+                        new NetworkState(null, newLp, null, network, null, null));
+            }
+
+            @Override
+            public void onLost(Network network) {
+                mTarget.sendMessage(mWhat, EVENT_ON_LOST, 0, network);
+            }
+        }
     }
 
     // Needed because the canonical source of upstream truth is just the
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 477ecdf..015345c 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -577,6 +577,9 @@
                     brightness = mPowerRequest.dozeScreenBrightness;
                 }
                 break;
+            case DisplayPowerRequest.POLICY_VR:
+                state = Display.STATE_VR;
+                break;
             case DisplayPowerRequest.POLICY_DIM:
             case DisplayPowerRequest.POLICY_BRIGHT:
             default:
@@ -618,6 +621,7 @@
         // Animate the screen state change unless already animating.
         // The transition may be deferred, so after this point we will use the
         // actual state instead of the desired one.
+        final int oldState = mPowerState.getScreenState();
         animateScreenStateChange(state, performScreenOffTransition);
         state = mPowerState.getScreenState();
 
@@ -717,9 +721,10 @@
         }
 
         // Animate the screen brightness when the screen is on or dozing.
-        // Skip the animation when the screen is off or suspended.
+        // Skip the animation when the screen is off or suspended or transition to/from VR.
         if (!mPendingScreenOff) {
-            if (state == Display.STATE_ON || state == Display.STATE_DOZE) {
+            boolean wasOrWillBeInVr = (state == Display.STATE_VR || oldState == Display.STATE_VR);
+            if ((state == Display.STATE_ON || state == Display.STATE_DOZE) && !wasOrWillBeInVr) {
                 animateScreenBrightness(brightness,
                         slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast);
             } else {
@@ -903,6 +908,23 @@
                 mPowerState.setColorFadeLevel(1.0f);
                 mPowerState.dismissColorFade();
             }
+        } else if (target == Display.STATE_VR) {
+            // Wait for brightness animation to complete beforehand when entering VR
+            // from screen on to prevent a perceptible jump because brightness may operate
+            // differently when the display is configured for dozing.
+            if (mScreenBrightnessRampAnimator.isAnimating()
+                    && mPowerState.getScreenState() == Display.STATE_ON) {
+                return;
+            }
+
+            // Set screen state.
+            if (!setScreenState(Display.STATE_VR)) {
+                return; // screen on blocked
+            }
+
+            // Dismiss the black surface without fanfare.
+            mPowerState.setColorFadeLevel(1.0f);
+            mPowerState.dismissColorFade();
         } else if (target == Display.STATE_DOZE) {
             // Want screen dozing.
             // Wait for brightness animation to complete beforehand when entering doze
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 61c2eac..8673225 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -471,6 +471,16 @@
                             }
                         }
 
+                        // If the state change was from or to VR, then we need to tell the light
+                        // so that it can apply appropriate VR brightness settings. This should
+                        // happen prior to changing the brightness but also if there is no
+                        // brightness change at all.
+                        if ((state == Display.STATE_VR || currentState == Display.STATE_VR) &&
+                                currentState != state) {
+                            setVrMode(state == Display.STATE_VR);
+                        }
+
+
                         // Apply brightness changes given that we are in a non-suspended state.
                         if (brightnessChanged) {
                             setDisplayBrightness(brightness);
@@ -482,6 +492,15 @@
                         }
                     }
 
+                    private void setVrMode(boolean isVrEnabled) {
+                        if (DEBUG) {
+                            Slog.d(TAG, "setVrMode("
+                                    + "id=" + displayId
+                                    + ", state=" + Display.stateToString(state) + ")");
+                        }
+                        mBacklight.setVrMode(isVrEnabled);
+                    }
+
                     private void setDisplayState(int state) {
                         if (DEBUG) {
                             Slog.d(TAG, "setDisplayState("
diff --git a/services/core/java/com/android/server/lights/Light.java b/services/core/java/com/android/server/lights/Light.java
index 0bab86b..b5ec603 100644
--- a/services/core/java/com/android/server/lights/Light.java
+++ b/services/core/java/com/android/server/lights/Light.java
@@ -46,4 +46,5 @@
     public abstract void pulse();
     public abstract void pulse(int color, int onMS);
     public abstract void turnOff();
+    public abstract void setVrMode(boolean enabled);
 }
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index bba0a50..e07156e 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
+/* * Copyright (C) 2008 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.
@@ -17,18 +16,13 @@
 package com.android.server.lights;
 
 import com.android.server.SystemService;
-import com.android.server.vr.VrManagerService;
 
 import android.app.ActivityManager;
 import android.content.Context;
 import android.os.Handler;
 import android.os.Message;
-import android.os.RemoteException;
 import android.os.Trace;
-import android.os.UserHandle;
 import android.provider.Settings;
-import android.service.vr.IVrManager;
-import android.service.vr.IVrStateCallbacks;
 import android.util.Slog;
 
 public class LightsService extends SystemService {
@@ -36,7 +30,6 @@
     static final boolean DEBUG = false;
 
     final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT];
-    private boolean mVrModeEnabled;
 
     private final class LightImpl extends Light {
 
@@ -52,6 +45,13 @@
         @Override
         public void setBrightness(int brightness, int brightnessMode) {
             synchronized (this) {
+                // LOW_PERSISTENCE cannot be manually set
+                if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
+                    Slog.w(TAG, "setBrightness with LOW_PERSISTENCE unexpected #" + mId +
+                            ": brightness=0x" + Integer.toHexString(brightness));
+                    return;
+                }
+
                 int color = brightness & 0x000000ff;
                 color = 0xff000000 | (color << 16) | (color << 8) | color;
                 setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
@@ -80,11 +80,9 @@
         @Override
         public void pulse(int color, int onMS) {
             synchronized (this) {
-                if (mBrightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
-                    return;
-                }
                 if (mColor == 0 && !mFlashing) {
-                    setLightLocked(color, LIGHT_FLASH_HARDWARE, onMS, 1000, BRIGHTNESS_MODE_USER);
+                    setLightLocked(color, LIGHT_FLASH_HARDWARE, onMS, 1000,
+                            BRIGHTNESS_MODE_USER);
                     mColor = 0;
                     mH.sendMessageDelayed(Message.obtain(mH, 1, this), onMS);
                 }
@@ -98,17 +96,23 @@
             }
         }
 
-        void enableLowPersistence() {
-            synchronized(this) {
-                setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, BRIGHTNESS_MODE_LOW_PERSISTENCE);
-                mLocked = true;
-            }
-        }
+        @Override
+        public void setVrMode(boolean enabled) {
+            synchronized (this) {
+                if (mVrModeEnabled != enabled) {
+                    mVrModeEnabled = enabled;
 
-        void disableLowPersistence() {
-            synchronized(this) {
-                mLocked = false;
-                setLightLocked(mLastColor, LIGHT_FLASH_NONE, 0, 0, mLastBrightnessMode);
+                    mUseLowPersistenceForVR =
+                            (getVrDisplayMode() == Settings.Secure.VR_DISPLAY_MODE_LOW_PERSISTENCE);
+                    if (shouldBeInLowPersistenceMode()) {
+                        mLastBrightnessMode = mBrightnessMode;
+                    }
+
+                    // NOTE: We do not trigger a call to setLightLocked here.  We do not know the
+                    // current brightness or other values when leaving VR so we avoid any incorrect
+                    // jumps. The code that calls this method will immediately issue a brightness
+                    // update which is when the change will occur.
+                }
             }
         }
 
@@ -119,7 +123,13 @@
         }
 
         private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
-            if (!mLocked && (color != mColor || mode != mMode || onMS != mOnMS || offMS != mOffMS ||
+            if (shouldBeInLowPersistenceMode()) {
+                brightnessMode = BRIGHTNESS_MODE_LOW_PERSISTENCE;
+            } else if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
+                brightnessMode = mLastBrightnessMode;
+            }
+
+            if ((color != mColor || mode != mMode || onMS != mOnMS || offMS != mOffMS ||
                     mBrightnessMode != brightnessMode)) {
                 if (DEBUG) Slog.v(TAG, "setLight #" + mId + ": color=#"
                         + Integer.toHexString(color) + ": brightnessMode=" + brightnessMode);
@@ -128,7 +138,6 @@
                 mMode = mode;
                 mOnMS = onMS;
                 mOffMS = offMS;
-                mLastBrightnessMode = mBrightnessMode;
                 mBrightnessMode = brightnessMode;
                 Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLight(" + mId + ", 0x"
                         + Integer.toHexString(color) + ")");
@@ -140,6 +149,10 @@
             }
         }
 
+        private boolean shouldBeInLowPersistenceMode() {
+            return mVrModeEnabled && mUseLowPersistenceForVR;
+        }
+
         private int mId;
         private int mColor;
         private int mMode;
@@ -149,7 +162,8 @@
         private int mBrightnessMode;
         private int mLastBrightnessMode;
         private int mLastColor;
-        private boolean mLocked;
+        private boolean mVrModeEnabled;
+        private boolean mUseLowPersistenceForVR;
     }
 
     public LightsService(Context context) {
@@ -167,17 +181,6 @@
 
     @Override
     public void onBootPhase(int phase) {
-        if (phase == PHASE_SYSTEM_SERVICES_READY) {
-            IVrManager vrManager =
-                    (IVrManager) getBinderService(VrManagerService.VR_MANAGER_BINDER_SERVICE);
-            if (vrManager != null) {
-                try {
-                    vrManager.registerListener(mVrStateCallbacks);
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Failed to register VR mode state listener: " + e);
-                }
-            }
-        }
     }
 
     private int getVrDisplayMode() {
@@ -188,30 +191,6 @@
                 currentUser);
     }
 
-    private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
-        @Override
-        public void onVrStateChanged(boolean enabled) throws RemoteException {
-            LightImpl l = mLights[LightsManager.LIGHT_ID_BACKLIGHT];
-            int vrDisplayMode = getVrDisplayMode();
-
-            // User leaves VR mode before altering display settings.
-            if (enabled && vrDisplayMode == Settings.Secure.VR_DISPLAY_MODE_LOW_PERSISTENCE) {
-                if (!mVrModeEnabled) {
-                    if (DEBUG)
-                        Slog.v(TAG, "VR mode enabled, setting brightness to low persistence");
-                    l.enableLowPersistence();
-                    mVrModeEnabled = true;
-                }
-            } else {
-                if (mVrModeEnabled) {
-                    if (DEBUG) Slog.v(TAG, "VR mode disabled, resetting brightnes");
-                    l.disableLowPersistence();
-                    mVrModeEnabled = false;
-                }
-            }
-        }
-    };
-
     private final LightsManager mService = new LightsManager() {
         @Override
         public Light getLight(int id) {
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 2e0199b..8c4a95c 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -217,26 +217,11 @@
                             dexoptNeeded);
                 }
 
-                final String dexoptType;
-                String oatDir = null;
-                boolean isOdexLocation = (dexoptNeeded < 0);
-                switch (Math.abs(dexoptNeeded)) {
-                    case DexFile.NO_DEXOPT_NEEDED:
-                        continue;
-                    case DexFile.DEX2OAT_FROM_SCRATCH:
-                    case DexFile.DEX2OAT_FOR_BOOT_IMAGE:
-                    case DexFile.DEX2OAT_FOR_FILTER:
-                    case DexFile.DEX2OAT_FOR_RELOCATION:
-                        dexoptType = "dex2oat";
-                        oatDir = createOatDirIfSupported(pkg, dexCodeInstructionSet);
-                        break;
-                    case DexFile.PATCHOAT_FOR_RELOCATION:
-                        dexoptType = "patchoat";
-                        break;
-                    default:
-                        throw new IllegalStateException("Invalid dexopt:" + dexoptNeeded);
+                if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) {
+                    continue;
                 }
 
+                String oatDir = createOatDirIfSupported(pkg, dexCodeInstructionSet);
                 String sharedLibrariesPath = null;
                 if (sharedLibraries != null && sharedLibraries.length != 0) {
                     StringBuilder sb = new StringBuilder();
@@ -248,7 +233,7 @@
                     }
                     sharedLibrariesPath = sb.toString();
                 }
-                Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg="
+                Log.i(TAG, "Running dexopt on: " + path + " pkg="
                         + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
                         + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
                         + " target-filter=" + targetCompilerFilter + " oatDir=" + oatDir
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index ddbc5fa..3085c9c 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -361,6 +361,11 @@
             }
             oldShortcut.setTimestamp(mShortcutUser.mService.injectCurrentTimeMillis());
 
+            // See ShortcutRequestPinProcessor.directPinShortcut().
+            if (mShortcutUser.mService.isDummyMainActivity(oldShortcut.getActivity())) {
+                oldShortcut.setActivity(null);
+            }
+
             return oldShortcut;
         } else {
             deleteShortcutInner(shortcutId);
@@ -1515,6 +1520,8 @@
 
         boolean failed = false;
 
+        final ShortcutService s = mShortcutUser.mService;
+
         final ArrayMap<ComponentName, ArrayList<ShortcutInfo>> all =
                 sortShortcutsToActivities();
 
@@ -1554,10 +1561,10 @@
                 Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
                         + " is both dynamic and manifest at the same time.");
             }
-            if (si.getActivity() == null) {
+            if (si.getActivity() == null && !si.isFloating()) {
                 failed = true;
                 Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
-                        + " has null activity.");
+                        + " has null activity, but not floating.");
             }
             if ((si.isDynamic() || si.isManifestShortcut()) && !si.isEnabled()) {
                 failed = true;
@@ -1579,6 +1586,11 @@
                 Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
                         + " has both resource and bitmap icons");
             }
+            if (s.isDummyMainActivity(si.getActivity())) {
+                failed = true;
+                Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
+                        + " has a dummy target activity");
+            }
         }
 
         if (failed) {
diff --git a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
index e815f0a..c8ddf0a 100644
--- a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
+++ b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
@@ -16,7 +16,6 @@
 package com.android.server.pm;
 
 import android.annotation.Nullable;
-import android.app.PendingIntent;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -209,7 +208,7 @@
         final boolean existsAlready = existing != null;
 
         if (DEBUG) {
-            Slog.d(TAG, "requestPinnedShortcut package=" + inShortcut.getPackage()
+            Slog.d(TAG, "requestPinnedShortcut: package=" + inShortcut.getPackage()
                     + " existsAlready=" + existsAlready
                     + " shortcut=" + inShortcut.toInsecureString());
         }
@@ -237,6 +236,14 @@
             // FLAG_PINNED is still set, if it's pinned by other launchers.
             shortcutForLauncher.clearFlags(ShortcutInfo.FLAG_PINNED);
         } else {
+            // If the shortcut has no default activity, try to set the main activity.
+            // But in the request-pin case, it's optional, so it's okay even if the caller
+            // has no default activity.
+            if (inShortcut.getActivity() == null) {
+                inShortcut.setActivity(mService.injectGetDefaultMainActivity(
+                        inShortcut.getPackage(), inShortcut.getUserId()));
+            }
+
             // It doesn't exist, so it must have all mandatory fields.
             mService.validateShortcutForPinRequest(inShortcut);
 
@@ -244,12 +251,15 @@
             inShortcut.resolveResourceStrings(mService.injectGetResourcesForApplicationAsUser(
                     inShortcut.getPackage(), inShortcut.getUserId()));
             if (DEBUG) {
-                Slog.d(TAG, "resolved shortcut=" + inShortcut.toInsecureString());
+                Slog.d(TAG, "Resolved shortcut=" + inShortcut.toInsecureString());
             }
             // We should strip out the intent, but should preserve the icon.
             shortcutForLauncher = inShortcut.clone(
                     ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER_APPROVAL);
         }
+        if (DEBUG) {
+            Slog.d(TAG, "Sending to launcher=" + shortcutForLauncher.toInsecureString());
+        }
 
         // Create a request object.
         final PinShortcutRequestInner inner =
@@ -360,7 +370,9 @@
                 if (DEBUG) {
                     Slog.d(TAG, "Temporarily adding " + shortcutId + " as dynamic");
                 }
-                // Add as a dynamic shortcut.
+                // Add as a dynamic shortcut.  In order for a shortcut to be dynamic, it must
+                // have a target activity, so we set a dummy here.  It's later removed
+                // in deleteDynamicWithId().
                 if (original.getActivity() == null) {
                     original.setActivity(mService.getDummyMainActivity(appPackageName));
                 }
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index c02ce6e..a890526 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1604,7 +1604,7 @@
     private void fixUpIncomingShortcutInfo(@NonNull ShortcutInfo shortcut, boolean forUpdate,
             boolean forPinRequest) {
         Preconditions.checkNotNull(shortcut, "Null shortcut detected");
-        if (!forPinRequest && shortcut.getActivity() != null) {
+        if (shortcut.getActivity() != null) {
             Preconditions.checkState(
                     shortcut.getPackage().equals(shortcut.getActivity().getPackageName()),
                     "Cannot publish shortcut: activity " + shortcut.getActivity() + " does not"
@@ -1618,10 +1618,8 @@
         if (!forUpdate) {
             shortcut.enforceMandatoryFields(/* forPinned= */ forPinRequest);
             if (!forPinRequest) {
-                Preconditions.checkArgument(
-                        injectIsMainActivity(shortcut.getActivity(), shortcut.getUserId()),
-                        "Cannot publish shortcut: " + shortcut.getActivity()
-                                + " is not main activity");
+                Preconditions.checkState(shortcut.getActivity() != null,
+                        "Cannot publish shortcut: target activity is not set");
             }
         }
         if (shortcut.getIcon() != null) {
@@ -1870,9 +1868,7 @@
             throwIfUserLockedL(userId);
 
             Preconditions.checkState(isUidForegroundLocked(injectBinderCallingUid()),
-                "Calling application must have a foreground activity or a foreground service");
-
-            // TODO Cancel all pending requests from the caller.
+                    "Calling application must have a foreground activity or a foreground service");
 
             // Send request to the launcher, if supported.
             ret = mShortcutRequestPinProcessor.requestPinItemLocked(shortcut, appWidget, userId,
@@ -3193,6 +3189,10 @@
         return new ComponentName(packageName, DUMMY_MAIN_ACTIVITY);
     }
 
+    boolean isDummyMainActivity(@Nullable ComponentName name) {
+        return name != null && DUMMY_MAIN_ACTIVITY.equals(name.getClassName());
+    }
+
     /**
      * Return all the enabled, exported and main activities from a package.
      */
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index fa1d991..0a312f0 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -251,9 +251,9 @@
     static final boolean DEBUG_INPUT = false;
     static final boolean DEBUG_KEYGUARD = false;
     static final boolean DEBUG_LAYOUT = false;
-    static final boolean DEBUG_STARTING_WINDOW = false;
+    static final boolean DEBUG_SPLASH_SCREEN = false;
     static final boolean DEBUG_WAKEUP = false;
-    static final boolean SHOW_STARTING_ANIMATIONS = true;
+    static final boolean SHOW_SPLASH_SCREENS = true;
 
     // Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key.
     // No longer recommended for desk docks;
@@ -2794,10 +2794,10 @@
 
     /** {@inheritDoc} */
     @Override
-    public View addStartingWindow(IBinder appToken, String packageName, int theme,
-            CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
-            int icon, int logo, int windowFlags, Configuration overrideConfig) {
-        if (!SHOW_STARTING_ANIMATIONS) {
+    public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme,
+            CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon,
+            int logo, int windowFlags, Configuration overrideConfig) {
+        if (!SHOW_SPLASH_SCREENS) {
             return null;
         }
         if (packageName == null) {
@@ -2809,7 +2809,7 @@
 
         try {
             Context context = mContext;
-            if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "addStartingWindow " + packageName
+            if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "addSplashScreen " + packageName
                     + ": nonLocalizedLabel=" + nonLocalizedLabel + " theme="
                     + Integer.toHexString(theme));
             if (theme != context.getThemeResId() || labelRes != 0) {
@@ -2822,8 +2822,8 @@
             }
 
             if (overrideConfig != null && !overrideConfig.equals(EMPTY)) {
-                if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "addStartingWindow: creating context based"
-                        + " on overrideConfig" + overrideConfig + " for starting window");
+                if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "addSplashScreen: creating context based"
+                        + " on overrideConfig" + overrideConfig + " for splash screen");
                 final Context overrideContext = context.createConfigurationContext(overrideConfig);
                 overrideContext.setTheme(theme);
                 final TypedArray typedArray = overrideContext.obtainStyledAttributes(
@@ -2833,7 +2833,7 @@
                     // We want to use the windowBackground for the override context if it is
                     // available, otherwise we use the default one to make sure a themed starting
                     // window is displayed for the app.
-                    if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "addStartingWindow: apply overrideConfig"
+                    if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "addSplashScreen: apply overrideConfig"
                             + overrideConfig + " to starting window resId=" + resId);
                     context = overrideContext;
                 }
@@ -2895,19 +2895,19 @@
                 params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
             }
 
-            params.setTitle("Starting " + packageName);
+            params.setTitle("Splash Screen " + packageName);
 
             wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
             view = win.getDecorView();
 
-            if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "Adding starting window for "
+            if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "Adding splash screen window for "
                 + packageName + " / " + appToken + ": " + (view.getParent() != null ? view : null));
 
             wm.addView(view, params);
 
             // Only return the view if it was successfully added to the
             // window manager... which we can tell by it having a parent.
-            return view.getParent() != null ? view : null;
+            return view.getParent() != null ? new SplashScreenSurface(view) : null;
         } catch (WindowManager.BadTokenException e) {
             // ignore
             Log.w(TAG, appToken + " already running, starting window not displayed. " +
@@ -2929,13 +2929,13 @@
 
     /** {@inheritDoc} */
     @Override
-    public void removeStartingWindow(IBinder appToken, View window) {
-        if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Removing starting window for " + appToken + ": "
-                + window + " Callers=" + Debug.getCallers(4));
+    public void removeSplashScreen(IBinder appToken, StartingSurface surface) {
+        if (DEBUG_SPLASH_SCREEN) Slog.v(TAG, "Removing splash screen window for " + appToken + ": "
+                + surface + " Callers=" + Debug.getCallers(4));
 
-        if (window != null) {
+        if (surface != null) {
             WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
-            wm.removeView(window);
+            wm.removeView(((SplashScreenSurface) surface).view);
         }
     }
 
diff --git a/services/core/java/com/android/server/policy/SplashScreenSurface.java b/services/core/java/com/android/server/policy/SplashScreenSurface.java
new file mode 100644
index 0000000..d421291
--- /dev/null
+++ b/services/core/java/com/android/server/policy/SplashScreenSurface.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 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.server.policy;
+
+import android.view.View;
+import android.view.WindowManagerPolicy;
+import android.view.WindowManagerPolicy.StartingSurface;
+
+import com.android.internal.policy.DecorView;
+import com.android.internal.policy.PhoneWindow;
+
+/**
+ * Holds the contents of a splash screen starting window, i.e. the {@link DecorView} of a
+ * {@link PhoneWindow}. This is just a wrapper such that we can return it from
+ * {@link WindowManagerPolicy#addSplashScreen}.
+ */
+class SplashScreenSurface implements StartingSurface {
+
+    final View view;
+
+    SplashScreenSurface(View view) {
+        this.view = view;
+    }
+}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index f2ccac5..8aefebc 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -136,6 +136,8 @@
     private static final int DIRTY_SCREEN_BRIGHTNESS_BOOST = 1 << 11;
     // Dirty bit: sQuiescent changed
     private static final int DIRTY_QUIESCENT = 1 << 12;
+    // Dirty bit: VR Mode enabled changed
+    private static final int DIRTY_VR_MODE_CHANGED = 1 << 13;
 
     // Summarizes the state of all active wakelocks.
     private static final int WAKE_LOCK_CPU = 1 << 0;
@@ -413,11 +415,15 @@
     private int mScreenBrightnessSettingMinimum;
     private int mScreenBrightnessSettingMaximum;
     private int mScreenBrightnessSettingDefault;
+    private int mScreenBrightnessForVrSettingDefault;
 
     // The screen brightness setting, from 0 to 255.
     // Use -1 if no value has been set.
     private int mScreenBrightnessSetting;
 
+    // The screen brightness setting, from 0 to 255, to be used while in VR Mode.
+    private int mScreenBrightnessForVrSetting;
+
     // The screen auto-brightness adjustment setting, from -1 to 1.
     // Use 0 if there is no adjustment.
     private float mScreenAutoBrightnessAdjustmentSetting;
@@ -511,6 +517,9 @@
     // True if brightness should be affected by twilight.
     private boolean mBrightnessUseTwilight;
 
+    // True if we are currently in VR Mode.
+    private boolean mIsVrModeEnabled;
+
     private native void nativeInit();
 
     private static native void nativeAcquireSuspendBlocker(String name);
@@ -594,6 +603,7 @@
             mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();
             mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
             mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
+            mScreenBrightnessForVrSettingDefault = pm.getDefaultScreenBrightnessForVrSetting();
 
             SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());
 
@@ -640,6 +650,9 @@
                     Settings.System.SCREEN_BRIGHTNESS),
                     false, mSettingsObserver, UserHandle.USER_ALL);
             resolver.registerContentObserver(Settings.System.getUriFor(
+                    Settings.System.SCREEN_BRIGHTNESS_FOR_VR),
+                    false, mSettingsObserver, UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.System.getUriFor(
                     Settings.System.SCREEN_BRIGHTNESS_MODE),
                     false, mSettingsObserver, UserHandle.USER_ALL);
             resolver.registerContentObserver(Settings.System.getUriFor(
@@ -773,11 +786,17 @@
             }
         }
 
-        final int oldScreenBrightnessSetting = mScreenBrightnessSetting;
+        final int oldScreenBrightnessSetting = getCurrentBrightnessSettingLocked();
+
+        mScreenBrightnessForVrSetting = Settings.System.getIntForUser(resolver,
+                Settings.System.SCREEN_BRIGHTNESS_FOR_VR, mScreenBrightnessForVrSettingDefault,
+                UserHandle.USER_CURRENT);
+
         mScreenBrightnessSetting = Settings.System.getIntForUser(resolver,
                 Settings.System.SCREEN_BRIGHTNESS, mScreenBrightnessSettingDefault,
                 UserHandle.USER_CURRENT);
-        if (oldScreenBrightnessSetting != mScreenBrightnessSetting) {
+
+        if (oldScreenBrightnessSetting != getCurrentBrightnessSettingLocked()) {
             mTemporaryScreenBrightnessSettingOverride = -1;
         }
 
@@ -811,6 +830,10 @@
         mDirty |= DIRTY_SETTINGS;
     }
 
+    private int getCurrentBrightnessSettingLocked() {
+        return mIsVrModeEnabled ? mScreenBrightnessForVrSetting : mScreenBrightnessSetting;
+    }
+
     private void postAfterBootCompleted(Runnable r) {
         if (mBootCompleted) {
             BackgroundThread.getHandler().post(r);
@@ -2069,6 +2092,7 @@
                 || !mDreamsSupportedConfig
                 || !mDreamsEnabledSetting
                 || !mDisplayPowerRequest.isBrightOrDim()
+                || mDisplayPowerRequest.isVr()
                 || (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT
                         | USER_ACTIVITY_SCREEN_DIM | USER_ACTIVITY_SCREEN_DREAM)) == 0
                 || !mBootCompleted) {
@@ -2113,7 +2137,8 @@
         final boolean oldDisplayReady = mDisplayReady;
         if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
                 | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
-                | DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST | DIRTY_QUIESCENT)) != 0) {
+                | DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST | DIRTY_VR_MODE_CHANGED |
+                DIRTY_QUIESCENT)) != 0) {
             mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked();
 
             // Determine appropriate screen brightness and auto-brightness adjustments.
@@ -2127,6 +2152,9 @@
                 // bootloader brightness and the default brightness to be identical.
                 autoBrightness = false;
                 brightnessSetByUser = false;
+            } else if (mIsVrModeEnabled) {
+                screenBrightness = mScreenBrightnessForVrSetting;
+                autoBrightness = false;
             } else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
                 screenBrightness = mScreenBrightnessOverrideFromWindowManager;
                 autoBrightness = false;
@@ -2160,7 +2188,7 @@
             mDisplayPowerRequest.useAutoBrightness = autoBrightness;
             mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
             mDisplayPowerRequest.lowPowerMode = mLowPowerModeEnabled;
-            mDisplayPowerRequest.boostScreenBrightness = mScreenBrightnessBoostInProgress;
+            mDisplayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness();
             mDisplayPowerRequest.useTwilight = mBrightnessUseTwilight;
 
             if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
@@ -2191,6 +2219,7 @@
                         + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
                         + ", mBootCompleted=" + mBootCompleted
                         + ", mScreenBrightnessBoostInProgress=" + mScreenBrightnessBoostInProgress
+                        + ", mIsVrModeEnabled= " + mIsVrModeEnabled
                         + ", sQuiescent=" + sQuiescent);
             }
         }
@@ -2220,6 +2249,10 @@
         }
     }
 
+    private boolean shouldBoostScreenBrightness() {
+        return !mIsVrModeEnabled && mScreenBrightnessBoostInProgress;
+    }
+
     private static boolean isValidBrightness(int value) {
         return value >= 0 && value <= 255;
     }
@@ -2230,6 +2263,10 @@
     }
 
     private int getDesiredScreenPolicyLocked() {
+        if (mIsVrModeEnabled) {
+            return DisplayPowerRequest.POLICY_VR;
+        }
+
         if (mWakefulness == WAKEFULNESS_ASLEEP || sQuiescent) {
             return DisplayPowerRequest.POLICY_OFF;
         }
@@ -2333,7 +2370,7 @@
     };
 
     private boolean shouldUseProximitySensorLocked() {
-        return (mWakeLockSummary & WAKE_LOCK_PROXIMITY_SCREEN_OFF) != 0;
+        return !mIsVrModeEnabled && (mWakeLockSummary & WAKE_LOCK_PROXIMITY_SCREEN_OFF) != 0;
     }
 
     /**
@@ -3085,7 +3122,11 @@
             pw.println("  mScreenBrightnessSettingMinimum=" + mScreenBrightnessSettingMinimum);
             pw.println("  mScreenBrightnessSettingMaximum=" + mScreenBrightnessSettingMaximum);
             pw.println("  mScreenBrightnessSettingDefault=" + mScreenBrightnessSettingDefault);
+            pw.println("  mScreenBrightnessForVrSettingDefault="
+                    + mScreenBrightnessForVrSettingDefault);
+            pw.println("  mScreenBrightnessForVrSetting=" + mScreenBrightnessForVrSetting);
             pw.println("  mDoubleTapWakeEnabled=" + mDoubleTapWakeEnabled);
+            pw.println("  mIsVrModeEnabled=" + mIsVrModeEnabled);
 
             final int sleepTimeout = getSleepTimeoutLocked();
             final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
@@ -3223,6 +3264,14 @@
         @Override
         public void onVrStateChanged(boolean enabled) {
             powerHintInternal(PowerHint.VR_MODE, enabled ? 1 : 0);
+
+            synchronized (mLock) {
+                if (mIsVrModeEnabled != enabled) {
+                    mIsVrModeEnabled = enabled;
+                    mDirty |= DIRTY_VR_MODE_CHANGED;
+                    updatePowerStateLocked();
+                }
+            }
         }
     };
 
@@ -3975,6 +4024,7 @@
                 case Display.STATE_DOZE:
                 case Display.STATE_DOZE_SUSPEND:
                 case Display.STATE_ON:
+                case Display.STATE_VR:
                     break;
                 default:
                     screenState = Display.STATE_UNKNOWN;
diff --git a/services/core/java/com/android/server/updates/TzDataInstallReceiver.java b/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
index b260e4e..b704eb1 100644
--- a/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
@@ -20,7 +20,7 @@
 
 import java.io.File;
 import java.io.IOException;
-import libcore.tzdata.update.TzDataBundleInstaller;
+import libcore.tzdata.update2.TimeZoneBundleInstaller;
 
 /**
  * An install receiver responsible for installing timezone data updates.
@@ -29,18 +29,19 @@
 
     private static final String TAG = "TZDataInstallReceiver";
 
+    private static final File SYSTEM_TZ_DATA_FILE = new File("/system/usr/share/zoneinfo/tzdata");
     private static final File TZ_DATA_DIR = new File("/data/misc/zoneinfo");
     private static final String UPDATE_DIR_NAME = TZ_DATA_DIR.getPath() + "/updates/";
     private static final String UPDATE_METADATA_DIR_NAME = "metadata/";
     private static final String UPDATE_VERSION_FILE_NAME = "version";
     private static final String UPDATE_CONTENT_FILE_NAME = "tzdata_bundle.zip";
 
-    private final TzDataBundleInstaller installer;
+    private final TimeZoneBundleInstaller installer;
 
     public TzDataInstallReceiver() {
         super(UPDATE_DIR_NAME, UPDATE_CONTENT_FILE_NAME, UPDATE_METADATA_DIR_NAME,
                 UPDATE_VERSION_FILE_NAME);
-        installer = new TzDataBundleInstaller(TAG, TZ_DATA_DIR);
+        installer = new TimeZoneBundleInstaller(TAG, SYSTEM_TZ_DATA_FILE, TZ_DATA_DIR);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index 35004c2..7630984 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -27,21 +27,20 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerService.H.ADD_STARTING;
-
-import android.graphics.Bitmap;
-import android.os.Trace;
-import com.android.server.AttributeCache;
 
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
-import android.os.Binder;
+import android.graphics.Bitmap;
 import android.os.Debug;
+import android.os.Handler;
 import android.os.IBinder;
-import android.os.Message;
+import android.os.Looper;
+import android.os.Trace;
 import android.util.Slog;
 import android.view.IApplicationToken;
+import android.view.WindowManagerPolicy.StartingSurface;
 
+import com.android.server.AttributeCache;
 /**
  * Controller for the app window token container. This is created by activity manager to link
  * activity records to the app window token container they use in window manager.
@@ -52,6 +51,7 @@
         extends WindowContainerController<AppWindowToken, AppWindowContainerListener> {
 
     private final IApplicationToken mToken;
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
 
     private final Runnable mOnWindowsDrawn = () -> {
         if (mListener == null) {
@@ -80,20 +80,109 @@
         mListener.onWindowsGone();
     };
 
-    public AppWindowContainerController(IApplicationToken token,
-            AppWindowContainerListener listener, int taskId, int index, int requestedOrientation,
-            boolean fullscreen, boolean showForAllUsers, int configChanges,
+    private final Runnable mAddStartingWindow = () -> {
+        final StartingData startingData;
+        final Configuration mergedOverrideConfiguration;
+
+        synchronized (mWindowMap) {
+            startingData = mContainer.startingData;
+            mergedOverrideConfiguration = mContainer.getMergedOverrideConfiguration();
+        }
+
+        if (startingData == null) {
+            // Animation has been canceled... do nothing.
+            return;
+        }
+
+        if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting "
+                + this + ": pkg=" + mContainer.startingData.pkg);
+
+        StartingSurface contents = null;
+        try {
+            contents = mService.mPolicy.addSplashScreen(mContainer.token, startingData.pkg,
+                    startingData.theme, startingData.compatInfo, startingData.nonLocalizedLabel,
+                    startingData.labelRes, startingData.icon, startingData.logo,
+                    startingData.windowFlags, mergedOverrideConfiguration);
+        } catch (Exception e) {
+            Slog.w(TAG_WM, "Exception when adding starting window", e);
+        }
+        if (contents != null) {
+            boolean abort = false;
+
+            synchronized(mWindowMap) {
+                if (mContainer.removed || mContainer.startingData == null) {
+                    // If the window was successfully added, then
+                    // we need to remove it.
+                    if (mContainer.startingWindow != null) {
+                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
+                                "Aborted starting " + mContainer
+                                        + ": removed=" + mContainer.removed
+                                        + " startingData=" + mContainer.startingData);
+                        mContainer.startingWindow = null;
+                        mContainer.startingData = null;
+                        abort = true;
+                    }
+                } else {
+                    mContainer.startingSurface = contents;
+                }
+                if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM,
+                        "Added starting " + mContainer
+                                + ": startingWindow="
+                                + mContainer.startingWindow + " startingView="
+                                + mContainer.startingSurface);
+            }
+
+            if (abort) {
+                try {
+                    mService.mPolicy.removeSplashScreen(mContainer.token, contents);
+                } catch (Exception e) {
+                    Slog.w(TAG_WM, "Exception when removing starting window", e);
+                }
+            }
+        }
+    };
+
+    private final Runnable mRemoveStartingWindow = () -> {
+        IBinder token = null;
+        StartingSurface contents = null;
+        synchronized (mWindowMap) {
+            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Remove starting "
+                    + mContainer + ": startingWindow="
+                    + mContainer.startingWindow + " startingView="
+                    + mContainer.startingSurface);
+            if (mContainer.startingWindow != null) {
+                contents = mContainer.startingSurface;
+                token = mContainer.token;
+                mContainer.startingData = null;
+                mContainer.startingSurface = null;
+                mContainer.startingWindow = null;
+                mContainer.startingDisplayed = false;
+            }
+        }
+        if (contents != null) {
+            try {
+                mService.mPolicy.removeSplashScreen(token, contents);
+            } catch (Exception e) {
+                Slog.w(TAG_WM, "Exception when removing starting window", e);
+            }
+        }
+    };
+
+    public AppWindowContainerController(TaskWindowContainerController taskController,
+            IApplicationToken token, AppWindowContainerListener listener, int index,
+            int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
             boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
             int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos) {
-        this(token, listener, taskId, index, requestedOrientation, fullscreen, showForAllUsers,
+        this(taskController, token, listener, index, requestedOrientation, fullscreen,
+                showForAllUsers,
                 configChanges, voiceInteraction, launchTaskBehind, alwaysFocusable,
                 targetSdkVersion, rotationAnimationHint, inputDispatchingTimeoutNanos,
                 WindowManagerService.getInstance());
     }
 
-    public AppWindowContainerController(IApplicationToken token,
-            AppWindowContainerListener listener, int taskId, int index, int requestedOrientation,
-            boolean fullscreen, boolean showForAllUsers, int configChanges,
+    public AppWindowContainerController(TaskWindowContainerController taskController,
+            IApplicationToken token, AppWindowContainerListener listener, int index,
+            int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
             boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
             int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
             WindowManagerService service) {
@@ -107,11 +196,10 @@
                 return;
             }
 
-            // TODO: Have the controller for the task passed in when task are changed to use
-            // controller.
-            final Task task = mService.mTaskIdToTask.get(taskId);
+            final Task task = taskController.mContainer;
             if (task == null) {
-                throw new IllegalArgumentException("addAppToken: invalid taskId=" + taskId);
+                throw new IllegalArgumentException("AppWindowContainerController: invalid "
+                        + " controller=" + taskController);
             }
 
             atoken = new AppWindowToken(mService, token, voiceInteraction, task.getDisplayContent(),
@@ -119,47 +207,27 @@
                     requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
                     alwaysFocusable, this);
             if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
-                    + " task=" + taskId + " at " + index);
+                    + " controller=" + taskController + " at " + index);
             task.addChild(atoken, index);
         }
     }
 
     public void removeContainer(int displayId) {
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            synchronized(mWindowMap) {
-                final DisplayContent dc = mRoot.getDisplayContent(displayId);
-                if (dc == null) {
-                    Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: "
-                            + mToken + " from non-existing displayId=" + displayId);
-                    return;
-                }
-                dc.removeAppToken(mToken.asBinder());
-                super.removeContainer();
+        synchronized(mWindowMap) {
+            final DisplayContent dc = mRoot.getDisplayContent(displayId);
+            if (dc == null) {
+                Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: "
+                        + mToken + " from non-existing displayId=" + displayId);
+                return;
             }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
+            dc.removeAppToken(mToken.asBinder());
+            super.removeContainer();
         }
     }
 
-    // TODO: Move to task window controller when that is created and rename to positionChildAt()
-    public void positionAt(int taskId, int index) {
-        synchronized(mService.mWindowMap) {
-            if (mContainer == null) {
-                Slog.w(TAG_WM,
-                        "Attempted to position of non-existing app token: " + mToken);
-                return;
-            }
-
-            // TODO: Should get the window container from this owner when the task owner stuff is
-            // hooked-up.
-            final Task task = mService.mTaskIdToTask.get(taskId);
-            if (task == null) {
-                throw new IllegalArgumentException("positionChildAt: invalid taskId=" + taskId);
-            }
-            task.addChild(mContainer, index);
-        }
-
+    @Override
+    public void removeContainer() {
+        throw new UnsupportedOperationException("Use removeContainer(displayId) instead.");
     }
 
     public Configuration setOrientation(int requestedOrientation, int displayId,
@@ -393,19 +461,42 @@
             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData");
             mContainer.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
                     labelRes, icon, logo, windowFlags);
-            final Message m = mService.mH.obtainMessage(ADD_STARTING, mContainer);
-            // Note: we really want to do sendMessageAtFrontOfQueue() because we
-            // want to process the message ASAP, before any other queued
-            // messages.
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
-            mService.mH.sendMessageAtFrontOfQueue(m);
+            scheduleAddStartingWindow();
         }
         return true;
     }
 
+    void scheduleAddStartingWindow() {
+
+        // Note: we really want to do sendMessageAtFrontOfQueue() because we
+        // want to process the message ASAP, before any other queued
+        // messages.
+        if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
+        mHandler.postAtFrontOfQueue(mAddStartingWindow);
+    }
+
     public void removeStartingWindow() {
         synchronized (mWindowMap) {
-            mService.scheduleRemoveStartingWindowLocked(mContainer);
+            if (mHandler.hasCallbacks(mRemoveStartingWindow)) {
+                // Already scheduled.
+                return;
+            }
+
+            if (mContainer.startingWindow == null) {
+                if (mContainer.startingData != null) {
+                    // Starting window has not been added yet, but it is scheduled to be added.
+                    // Go ahead and cancel the request.
+                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
+                            "Clearing startingData for token=" + mContainer);
+                    mContainer.startingData = null;
+                }
+                return;
+            }
+
+            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, Debug.getCallers(1)
+                    + ": Schedule remove starting " + mContainer
+                    + " startingWindow=" + mContainer.startingWindow);
+            mHandler.post(mRemoveStartingWindow);
         }
     }
 
@@ -458,9 +549,7 @@
                         "Attempted to freeze screen with non-existing app token: " + mContainer);
                 return;
             }
-            final long origId = Binder.clearCallingIdentity();
             mContainer.startFreezingScreen();
-            Binder.restoreCallingIdentity(origId);
         }
     }
 
@@ -469,11 +558,9 @@
             if (mContainer == null) {
                 return;
             }
-            final long origId = Binder.clearCallingIdentity();
             if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="
                     + mContainer.hidden + " freezing=" + mContainer.mAppAnimator.freezingScreen);
             mContainer.stopFreezingScreen(true, force);
-            Binder.restoreCallingIdentity(origId);
         }
     }
 
@@ -508,19 +595,24 @@
 
 
     void reportWindowsDrawn() {
-        mService.mH.post(mOnWindowsDrawn);
+        mHandler.post(mOnWindowsDrawn);
     }
 
     void reportWindowsVisible() {
-        mService.mH.post(mOnWindowsVisible);
+        mHandler.post(mOnWindowsVisible);
     }
 
     void reportWindowsGone() {
-        mService.mH.post(mOnWindowsGone);
+        mHandler.post(mOnWindowsGone);
     }
 
     /** Calls directly into activity manager so window manager lock shouldn't held. */
     boolean keyDispatchingTimedOut(String reason) {
         return mListener != null && mListener.keyDispatchingTimedOut(reason);
     }
+
+    @Override
+    public String toString() {
+        return "{AppWindowContainerController token=" + mToken + "}";
+    }
 }
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 0a48758..f4fa220 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -29,9 +29,9 @@
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
@@ -47,22 +47,21 @@
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
 import static com.android.server.wm.WindowManagerService.logWithStack;
 
-import android.os.Debug;
-import com.android.internal.util.ToBooleanFunction;
-import com.android.server.input.InputApplicationHandle;
-import com.android.server.wm.WindowManagerService.H;
-
 import android.annotation.NonNull;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Binder;
+import android.os.Debug;
 import android.os.IBinder;
-import android.os.Message;
 import android.os.SystemClock;
 import android.util.Slog;
 import android.view.IApplicationToken;
-import android.view.View;
 import android.view.WindowManager;
+import android.view.WindowManagerPolicy.StartingSurface;
+
+import com.android.internal.util.ToBooleanFunction;
+import com.android.server.input.InputApplicationHandle;
+import com.android.server.wm.WindowManagerService.H;
 
 import java.io.PrintWriter;
 import java.util.ArrayDeque;
@@ -138,7 +137,7 @@
     // Information about an application starting window if displayed.
     StartingData startingData;
     WindowState startingWindow;
-    View startingView;
+    StartingSurface startingSurface;
     boolean startingDisplayed;
     boolean startingMoved;
     boolean firstWindowDrawn;
@@ -213,8 +212,9 @@
             // it from behind the starting window, so there is no need for it to also be doing its
             // own stuff.
             winAnimator.clearAnimation();
-            winAnimator.mService.mFinishedStarting.add(this);
-            winAnimator.mService.mH.sendEmptyMessage(H.FINISHED_STARTING);
+            if (getController() != null) {
+                getController().removeStartingWindow();
+            }
         }
         updateReportedVisibilityLocked();
     }
@@ -439,8 +439,6 @@
     }
 
     void onRemovedFromDisplay() {
-        AppWindowToken startingToken = null;
-
         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app token: " + this);
 
         boolean delayed = setVisibility(null, false, TRANSIT_UNSET, true, mVoiceInteraction);
@@ -461,6 +459,10 @@
         if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, "removeAppToken: "
                 + this + " delayed=" + delayed + " Callers=" + Debug.getCallers(4));
 
+        if (startingData != null && getController() != null) {
+            getController().removeStartingWindow();
+        }
+
         final TaskStack stack = mTask.mStack;
         if (delayed && !isEmpty()) {
             // set the token aside because it has an active animation to be finished
@@ -477,9 +479,6 @@
         }
 
         removed = true;
-        if (startingData != null) {
-            startingToken = this;
-        }
         stopFreezingScreen(true, true);
         if (mService.mFocusedApp == this) {
             if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Removing focused app token:" + this);
@@ -491,9 +490,6 @@
         if (!delayed) {
             updateReportedVisibilityLocked();
         }
-
-        // Will only remove if startingToken non null.
-        mService.scheduleRemoveStartingWindowLocked(startingToken);
     }
 
     void clearAnimatingFlags() {
@@ -557,7 +553,9 @@
         mAppStopped = true;
         destroySurfaces();
         // Remove any starting window that was added for this app if they are still around.
-        mTask.mService.scheduleRemoveStartingWindowLocked(this);
+        if (getController() != null) {
+            getController().removeStartingWindow();
+        }
     }
 
     /**
@@ -667,16 +665,20 @@
         // TODO: Something smells about the code below...Is there a better way?
         if (startingWindow == win) {
             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Notify removed startingWindow " + win);
-            mService.scheduleRemoveStartingWindowLocked(this);
+            if (getController() != null) {
+                getController().removeStartingWindow();
+            }
         } else if (mChildren.size() == 0 && startingData != null) {
             // If this is the last window and we had requested a starting transition window,
             // well there is no point now.
             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Nulling last startingWindow");
             startingData = null;
-        } else if (mChildren.size() == 1 && startingView != null) {
+        } else if (mChildren.size() == 1 && startingSurface != null) {
             // If this is the last window except for a starting transition window,
             // we need to get rid of the starting transition.
-            mService.scheduleRemoveStartingWindowLocked(this);
+            if (getController() != null) {
+                getController().removeStartingWindow();
+            }
         }
     }
 
@@ -1015,7 +1017,7 @@
         }
 
         final WindowState tStartingWindow = fromToken.startingWindow;
-        if (tStartingWindow != null && fromToken.startingView != null) {
+        if (tStartingWindow != null && fromToken.startingSurface != null) {
             // In this case, the starting icon has already been displayed, so start
             // letting windows get shown immediately without any more transitions.
             mService.mSkipAppTransitionAnimation = true;
@@ -1027,13 +1029,13 @@
 
             // Transfer the starting window over to the new token.
             startingData = fromToken.startingData;
-            startingView = fromToken.startingView;
+            startingSurface = fromToken.startingSurface;
             startingDisplayed = fromToken.startingDisplayed;
             fromToken.startingDisplayed = false;
             startingWindow = tStartingWindow;
             reportedVisible = fromToken.reportedVisible;
             fromToken.startingData = null;
-            fromToken.startingView = null;
+            fromToken.startingSurface = null;
             fromToken.startingWindow = null;
             fromToken.startingMoved = true;
             tStartingWindow.mToken = this;
@@ -1080,10 +1082,9 @@
             startingData = fromToken.startingData;
             fromToken.startingData = null;
             fromToken.startingMoved = true;
-            final Message m = mService.mH.obtainMessage(H.ADD_STARTING, this);
-            // Note: we really want to do sendMessageAtFrontOfQueue() because we want to process the
-            // message ASAP, before any other queued messages.
-            mService.mH.sendMessageAtFrontOfQueue(m);
+            if (getController() != null) {
+                getController().scheduleAddStartingWindow();
+            }
             return true;
         }
 
@@ -1421,10 +1422,10 @@
                     pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn);
                     pw.print(" mIsExiting="); pw.println(mIsExiting);
         }
-        if (startingWindow != null || startingView != null
+        if (startingWindow != null || startingSurface != null
                 || startingDisplayed || startingMoved) {
             pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow);
-                    pw.print(" startingView="); pw.print(startingView);
+                    pw.print(" startingSurface="); pw.print(startingSurface);
                     pw.print(" startingDisplayed="); pw.print(startingDisplayed);
                     pw.print(" startingMoved="); pw.println(startingMoved);
         }
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index dc06d12..6ac172b 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -322,7 +322,7 @@
         if (!configChanged) {
             return null;
         }
-        displayContent.onOverrideConfigurationChanged(currentConfig);
+        displayContent.onOverrideConfigurationChanged(newConfiguration);
 
         if (displayId == DEFAULT_DISPLAY) {
             // Override configuration of the default display duplicates global config. In this case
@@ -498,7 +498,10 @@
                     if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
                             "RECOVER DESTROY", false);
                     winAnimator.destroySurface();
-                    mService.scheduleRemoveStartingWindowLocked(winAnimator.mWin.mAppToken);
+                    if (winAnimator.mWin.mAppToken != null
+                            && winAnimator.mWin.mAppToken.getController() != null) {
+                        winAnimator.mWin.mAppToken.getController().removeStartingWindow();
+                    }
                 }
 
                 try {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index a468598..b1b7542 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -22,6 +22,7 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
+import static com.android.server.EventLogTags.WM_TASK_REMOVED;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -89,8 +90,8 @@
     private boolean mIsOnTopLauncher;
 
     Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
-            Configuration overrideConfig, boolean isOnTopLauncher, int resizeMode,
-            boolean homeTask) {
+            Configuration overrideConfig, boolean isOnTopLauncher, int resizeMode, boolean homeTask,
+            TaskWindowContainerController controller) {
         mTaskId = taskId;
         mStack = stack;
         mUserId = userId;
@@ -98,6 +99,7 @@
         mIsOnTopLauncher = isOnTopLauncher;
         mResizeMode = resizeMode;
         mHomeTask = homeTask;
+        setController(controller);
         setBounds(bounds, overrideConfig);
     }
 
@@ -150,7 +152,7 @@
     @Override
     void removeImmediately() {
         if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
-        EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeTask");
+        EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeTask");
         mDeferRemoval = false;
 
         // Make sure to remove dim layer user first before removing task its from parent.
@@ -160,19 +162,17 @@
         }
 
         super.removeImmediately();
-        mService.mTaskIdToTask.delete(mTaskId);
     }
 
-    // TODO: Change to use re-parenting in WC.
-    void moveTaskToStack(TaskStack stack, boolean toTop) {
+    void reparent(TaskStack stack, int position) {
         if (stack == mStack) {
             return;
         }
-        if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: removing taskId=" + mTaskId
+        if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
                 + " from stack=" + mStack);
-        EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
+        EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "reParentTask");
         getParent().removeChild(this);
-        stack.addTask(this, toTop);
+        stack.addTask(this, position, showForAllUsers(), false /* moveParents */);
     }
 
     /** @see com.android.server.am.ActivityManagerService#positionTaskInStack(int, int, int). */
@@ -188,12 +188,13 @@
             // and add to top of the target stack. We will move it proper position afterwards.
             if (DEBUG_STACK) Slog.i(TAG, "positionTaskInStack: removing taskId=" + mTaskId
                     + " from stack=" + mStack);
-            EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
+            EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "positionTaskInStack");
             mStack.removeChild(this);
-            stack.addTask(this, true /* toTop */);
+            stack.addTask(this, position);
+        } else {
+            stack.positionChildAt(position, this, true /* includingParents */);
         }
 
-        stack.positionChildAt(position, this, true /* includingParents */);
         resizeLocked(bounds, overrideConfig, false /* force */);
 
         for (int activityNdx = mChildren.size() - 1; activityNdx >= 0; --activityNdx) {
@@ -225,7 +226,7 @@
         super.removeChild(token);
 
         if (mChildren.isEmpty()) {
-            EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeAppToken: last token");
+            EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeAppToken: last token");
             if (mDeferRemoval) {
                 removeIfPossible();
             }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index d7c7cfa..eeea532 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -507,8 +507,8 @@
     }
 
     // TODO: Checkout the call points of this method and the ones below to see how they can fit in WC.
-    void addTask(Task task, boolean toTop) {
-        addTask(task, toTop, task.showForAllUsers());
+    void addTask(Task task, int position) {
+        addTask(task, position, task.showForAllUsers(), true /* moveParents */);
     }
 
     /**
@@ -516,10 +516,10 @@
      * When task is added to top of the stack, the entire branch of the hierarchy (including stack
      * and display) will be brought to top.
      * @param task The task to add.
-     * @param toTop Whether to add it to the top or bottom.
+     * @param position Target position to add the task to.
      * @param showForAllUsers Whether to show the task regardless of the current user.
      */
-    void addTask(Task task, boolean toTop, boolean showForAllUsers) {
+    void addTask(Task task, int position, boolean showForAllUsers, boolean moveParents) {
         final TaskStack currentStack = task.mStack;
         // TODO: We pass stack to task's constructor, but we still need to call this method.
         // This doesn't make sense, mStack will already be set equal to "this" at this point.
@@ -529,14 +529,12 @@
                     + ", but it is already attached to stackId=" + task.mStack.mStackId);
         }
 
-        final int targetPosition = toTop ? mChildren.size() : 0;
-
         // Add child task.
         task.mStack = this;
-        addChild(task, targetPosition);
+        addChild(task, null);
 
         // Move child to a proper position, as some restriction for position might apply.
-        positionChildAt(targetPosition, task, true /* includingParents */, showForAllUsers);
+        positionChildAt(position, task, moveParents /* includingParents */, showForAllUsers);
     }
 
     @Override
@@ -546,7 +544,7 @@
 
     /**
      * Overridden version of {@link TaskStack#positionChildAt(int, Task, boolean)}. Used in
-     * {@link TaskStack#addTask(Task, boolean, boolean showForAllUsers)}, as it can receive
+     * {@link TaskStack#addTask(Task, int, boolean showForAllUsers, boolean)}, as it can receive
      * showForAllUsers param from {@link AppWindowToken} instead of {@link Task#showForAllUsers()}.
      */
     private void positionChildAt(int position, Task child, boolean includingParents,
diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerController.java b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
new file mode 100644
index 0000000..9c303f8
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2016 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.server.wm;
+
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.util.EventLog;
+import android.util.Slog;
+
+import static com.android.server.EventLogTags.WM_TASK_CREATED;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
+import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+/**
+ * Controller for the task container. This is created by activity manager to link task records to
+ * the task container they use in window manager.
+ *
+ * Test class: {@link TaskWindowContainerControllerTests}
+ */
+public class TaskWindowContainerController
+        extends WindowContainerController<Task, WindowContainerListener> {
+
+    private final int mTaskId;
+
+    public TaskWindowContainerController(int taskId, int stackId, int userId, Rect bounds,
+            Configuration overrideConfig, int resizeMode, boolean homeTask, boolean isOnTopLauncher,
+            boolean toTop, boolean showForAllUsers) {
+        super(null, WindowManagerService.getInstance());
+        mTaskId = taskId;
+
+        synchronized(mWindowMap) {
+            if (DEBUG_STACK) Slog.i(TAG_WM, "TaskWindowContainerController: taskId=" + taskId
+                    + " stackId=" + stackId + " bounds=" + bounds);
+
+            // TODO: Pass controller for the stack to get the container object when stack is
+            // switched to use controller.
+            final TaskStack stack = mService.mStackIdToStack.get(stackId);
+            if (stack == null) {
+                throw new IllegalArgumentException("TaskWindowContainerController: invalid stackId="
+                        + stackId);
+            }
+            EventLog.writeEvent(WM_TASK_CREATED, taskId, stackId);
+            final Task task = new Task(taskId, stack, userId, mService, bounds, overrideConfig,
+                    isOnTopLauncher, resizeMode, homeTask, this);
+            final int position = toTop ? POSITION_TOP : POSITION_BOTTOM;
+            stack.addTask(task, position, showForAllUsers, true /* moveParents */);
+        }
+    }
+
+    @Override
+    public void removeContainer() {
+        synchronized(mWindowMap) {
+            if (mContainer == null) {
+                if (DEBUG_STACK) Slog.i(TAG_WM, "removeTask: could not find taskId=" + mTaskId);
+                return;
+            }
+            mContainer.removeIfPossible();
+            super.removeContainer();
+        }
+    }
+
+    public void positionChildAt(AppWindowContainerController childController, int index) {
+        synchronized(mService.mWindowMap) {
+            final AppWindowToken aToken = childController.mContainer;
+            if (aToken == null) {
+                Slog.w(TAG_WM,
+                        "Attempted to position of non-existing app : " + childController);
+                return;
+            }
+
+            final Task task = mContainer;
+            if (task == null) {
+                throw new IllegalArgumentException("positionChildAt: invalid task=" + this);
+            }
+            task.addChild(aToken, index);
+        }
+    }
+
+    public void reparent(int stackId, int position) {
+        synchronized (mWindowMap) {
+            if (DEBUG_STACK) Slog.i(TAG_WM, "reparent: moving taskId=" + mTaskId
+                    + " to stackId=" + stackId + " at " + position);
+            if (mContainer == null) {
+                if (DEBUG_STACK) Slog.i(TAG_WM,
+                        "reparent: could not find taskId=" + mTaskId);
+                return;
+            }
+            final TaskStack stack = mService.mStackIdToStack.get(stackId);
+            if (stack == null) {
+                if (DEBUG_STACK) Slog.i(TAG_WM,
+                        "reparent: could not find stackId=" + stackId);
+                return;
+            }
+            mContainer.reparent(stack, position);
+            final DisplayContent displayContent = stack.getDisplayContent();
+            displayContent.setLayoutNeeded();
+            mService.mWindowPlacerLocked.performSurfacePlacement();
+        }
+    }
+
+    public void setResizeable(int resizeMode) {
+        synchronized (mWindowMap) {
+            if (mContainer != null) {
+                mContainer.setResizeable(resizeMode);
+            }
+        }
+    }
+
+    public void resize(Rect bounds, Configuration overrideConfig, boolean relayout,
+            boolean forced) {
+        synchronized (mWindowMap) {
+            if (mContainer == null) {
+                throw new IllegalArgumentException("resizeTask: taskId " + mTaskId + " not found.");
+            }
+
+            if (mContainer.resizeLocked(bounds, overrideConfig, forced) && relayout) {
+                mContainer.getDisplayContent().setLayoutNeeded();
+                mService.mWindowPlacerLocked.performSurfacePlacement();
+            }
+        }
+    }
+
+    // TODO: Move to positionChildAt() in stack controller once we have a stack controller.
+    public void positionAt(int stackId, int index, Rect bounds, Configuration overrideConfig) {
+        synchronized (mWindowMap) {
+            if (DEBUG_STACK) Slog.i(TAG_WM, "positionChildAt: positioning taskId=" + mTaskId
+                    + " in stackId=" + stackId + " at " + index);
+            if (mContainer == null) {
+                if (DEBUG_STACK) Slog.i(TAG_WM,
+                        "positionTaskInStack: could not find taskId=" + mTaskId);
+                return;
+            }
+            final TaskStack stack = mService.mStackIdToStack.get(stackId);
+            if (stack == null) {
+                if (DEBUG_STACK) Slog.i(TAG_WM,
+                        "positionTaskInStack: could not find stackId=" + stackId);
+                return;
+            }
+            mContainer.positionTaskInStack(stack, index, bounds, overrideConfig);
+            final DisplayContent displayContent = stack.getDisplayContent();
+            displayContent.setLayoutNeeded();
+            mService.mWindowPlacerLocked.performSurfacePlacement();
+        }
+    }
+
+    // TODO: Replace with moveChildToTop in stack controller?
+    public void moveToTop(boolean includingParents) {
+        synchronized(mWindowMap) {
+            if (mContainer == null) {
+                Slog.e(TAG_WM, "moveToTop: taskId=" + mTaskId + " not found");
+                return;
+            }
+            final TaskStack stack = mContainer.mStack;
+            stack.positionChildAt(POSITION_TOP, mContainer, includingParents);
+
+            if (mService.mAppTransition.isTransitionSet()) {
+                mContainer.setSendingToBottom(false);
+            }
+            stack.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+        }
+    }
+
+    // TODO: Replace with moveChildToBottom in stack controller?
+    public void moveToBottom() {
+        synchronized(mWindowMap) {
+            if (mContainer == null) {
+                Slog.e(TAG_WM, "moveTaskToBottom: taskId=" + mTaskId + " not found");
+                return;
+            }
+            final TaskStack stack = mContainer.mStack;
+            stack.positionChildAt(POSITION_BOTTOM, mContainer, false /* includingParents */);
+            if (mService.mAppTransition.isTransitionSet()) {
+                mContainer.setSendingToBottom(true);
+            }
+            stack.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+        }
+    }
+
+    public void getBounds(Rect bounds) {
+        synchronized (mWindowMap) {
+            if (mContainer != null) {
+                mContainer.getBounds(bounds);
+                return;
+            }
+            bounds.setEmpty();
+        }
+    }
+
+    /**
+     * Puts this task into docked drag resizing mode. See {@link DragResizeMode}.
+     *
+     * @param resizing Whether to put the task into drag resize mode.
+     */
+    public void setTaskDockedResizing(boolean resizing) {
+        synchronized (mWindowMap) {
+            if (mContainer == null) {
+                Slog.w(TAG_WM, "setTaskDockedResizing: taskId " + mTaskId + " not found.");
+                return;
+            }
+            mContainer.setDragResizing(resizing, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
+        }
+    }
+
+    public void cancelWindowTransition() {
+        synchronized (mWindowMap) {
+            if (mContainer == null) {
+                Slog.w(TAG_WM, "cancelWindowTransition: taskId " + mTaskId + " not found.");
+                return;
+            }
+            mContainer.cancelTaskWindowTransition();
+        }
+    }
+
+    public void cancelThumbnailTransition() {
+        synchronized (mWindowMap) {
+            if (mContainer == null) {
+                Slog.w(TAG_WM, "cancelThumbnailTransition: taskId " + mTaskId + " not found.");
+                return;
+            }
+            mContainer.cancelTaskThumbnailTransition();
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "{TaskWindowContainerController taskId=" + mTaskId + "}";
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 0e6ecde..fd7ea6d 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -235,7 +235,7 @@
     @CallSuper
     void positionChildAt(int position, E child, boolean includingParents) {
         if ((position < 0 && position != POSITION_BOTTOM)
-                || (position >= mChildren.size() && position != POSITION_TOP)) {
+                || (position > mChildren.size() && position != POSITION_TOP)) {
             throw new IllegalArgumentException("positionAt: invalid position=" + position
                     + ", children number=" + mChildren.size());
         }
@@ -248,7 +248,7 @@
 
         switch (position) {
             case POSITION_TOP:
-                if (mChildren.getLast() != child) {
+                if (mChildren.peekLast() != child) {
                     mChildren.remove(child);
                     mChildren.addLast(child);
                 }
@@ -258,7 +258,7 @@
                 }
                 break;
             case POSITION_BOTTOM:
-                if (mChildren.getFirst() != child) {
+                if (mChildren.peekFirst() != child) {
                     mChildren.remove(child);
                     mChildren.addFirst(child);
                 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 38cb543..048affb 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -707,8 +707,6 @@
 
     private final BoundsAnimationController mBoundsAnimationController;
 
-    SparseArray<Task> mTaskIdToTask = new SparseArray<>();
-
     /** All of the TaskStacks in the window manager, unordered. For an ordered list call
      * DisplayContent.getStacks(). */
     // TODO: Don't believe this is needed with the WindowContainer model.
@@ -912,7 +910,6 @@
     }
 
     private static WindowManagerService sInstance;
-
     static WindowManagerService getInstance() {
         return sInstance;
     }
@@ -2441,35 +2438,6 @@
         }
     }
 
-    public void addTask(int taskId, int stackId, int userId, Rect bounds,
-            Configuration overrideConfig, int resizeMode, boolean homeTask, boolean isOnTopLauncher,
-            boolean toTop, boolean showForAllUsers) {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "addTask()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        synchronized(mWindowMap) {
-            Task task = mTaskIdToTask.get(taskId);
-            if (task != null) {
-                throw new IllegalArgumentException(
-                        "addTask: Attempt to add already existing task=" + task);
-            }
-
-            if (DEBUG_STACK) Slog.i(TAG_WM, "createTaskLocked: taskId=" + taskId
-                    + " stackId=" + stackId + " bounds=" + bounds);
-
-            final TaskStack stack = mStackIdToStack.get(stackId);
-            if (stack == null) {
-                throw new IllegalArgumentException("addTask: invalid stackId=" + stackId);
-            }
-            EventLog.writeEvent(WM_TASK_CREATED, taskId, stackId);
-            task = new Task(taskId, stack, userId, this, bounds, overrideConfig, isOnTopLauncher,
-                    resizeMode, homeTask);
-            mTaskIdToTask.put(taskId, task);
-            stack.addTask(task, toTop, showForAllUsers);
-        }
-    }
-
     @Override
     public Configuration updateOrientationFromAppTokens(Configuration currentConfig,
             IBinder freezeThisOneIfNeeded, int displayId) {
@@ -2851,77 +2819,6 @@
         }
     }
 
-    void scheduleRemoveStartingWindowLocked(AppWindowToken wtoken) {
-        if (wtoken == null) {
-            return;
-        }
-        if (mH.hasMessages(H.REMOVE_STARTING, wtoken)) {
-            // Already scheduled.
-            return;
-        }
-
-        if (wtoken.startingWindow == null) {
-            if (wtoken.startingData != null) {
-                // Starting window has not been added yet, but it is scheduled to be added.
-                // Go ahead and cancel the request.
-                if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
-                        "Clearing startingData for token=" + wtoken);
-                wtoken.startingData = null;
-            }
-            return;
-        }
-
-        if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, Debug.getCallers(1) +
-                ": Schedule remove starting " + wtoken + (wtoken != null ?
-                " startingWindow=" + wtoken.startingWindow : ""));
-        Message m = mH.obtainMessage(H.REMOVE_STARTING, wtoken);
-        mH.sendMessage(m);
-    }
-
-    public void moveTaskToTop(int taskId) {
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            synchronized(mWindowMap) {
-                final Task task = mTaskIdToTask.get(taskId);
-                if (task == null) {
-                    // Normal behavior, addAppToken will be called next and task will be created.
-                    return;
-                }
-                task.mStack.positionChildAt(POSITION_TOP, task, true /* includingParents */);
-
-                if (mAppTransition.isTransitionSet()) {
-                    task.setSendingToBottom(false);
-                }
-                final DisplayContent displayContent = task.getDisplayContent();
-                displayContent.layoutAndAssignWindowLayersIfNeeded();
-            }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
-    public void moveTaskToBottom(int taskId) {
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            synchronized(mWindowMap) {
-                final Task task = mTaskIdToTask.get(taskId);
-                if (task == null) {
-                    Slog.e(TAG_WM, "moveTaskToBottom: taskId=" + taskId
-                            + " not found in mTaskIdToTask");
-                    return;
-                }
-                final TaskStack stack = task.mStack;
-                stack.positionChildAt(POSITION_BOTTOM, task, false /* includingParents */);
-                if (mAppTransition.isTransitionSet()) {
-                    task.setSendingToBottom(true);
-                }
-                stack.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
-            }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
     boolean isStackVisibleLocked(int stackId) {
         final TaskStack stack = mStackIdToStack.get(stackId);
         return (stack != null && stack.isVisible());
@@ -3091,58 +2988,6 @@
         }
     }
 
-    public void removeTask(int taskId) {
-        synchronized (mWindowMap) {
-            Task task = mTaskIdToTask.get(taskId);
-            if (task == null) {
-                if (DEBUG_STACK) Slog.i(TAG_WM, "removeTask: could not find taskId=" + taskId);
-                return;
-            }
-            task.removeIfPossible();
-        }
-    }
-
-    @Override
-    public void cancelTaskWindowTransition(int taskId) {
-        synchronized (mWindowMap) {
-            Task task = mTaskIdToTask.get(taskId);
-            if (task != null) {
-                task.cancelTaskWindowTransition();
-            }
-        }
-    }
-
-    @Override
-    public void cancelTaskThumbnailTransition(int taskId) {
-        synchronized (mWindowMap) {
-            Task task = mTaskIdToTask.get(taskId);
-            if (task != null) {
-                task.cancelTaskThumbnailTransition();
-            }
-        }
-    }
-
-    public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
-        synchronized (mWindowMap) {
-            if (DEBUG_STACK) Slog.i(TAG_WM, "moveTaskToStack: moving taskId=" + taskId
-                    + " to stackId=" + stackId + " at " + (toTop ? "top" : "bottom"));
-            Task task = mTaskIdToTask.get(taskId);
-            if (task == null) {
-                if (DEBUG_STACK) Slog.i(TAG_WM, "moveTaskToStack: could not find taskId=" + taskId);
-                return;
-            }
-            TaskStack stack = mStackIdToStack.get(stackId);
-            if (stack == null) {
-                if (DEBUG_STACK) Slog.i(TAG_WM, "moveTaskToStack: could not find stackId=" + stackId);
-                return;
-            }
-            task.moveTaskToStack(stack, toTop);
-            final DisplayContent displayContent = stack.getDisplayContent();
-            displayContent.setLayoutNeeded();
-            mWindowPlacerLocked.performSurfacePlacement();
-        }
-    }
-
     public void getStackDockedModeBounds(int stackId, Rect bounds, boolean ignoreVisibility) {
         synchronized (mWindowMap) {
             final TaskStack stack = mStackIdToStack.get(stackId);
@@ -3218,69 +3063,6 @@
         }
     }
 
-    /** @see com.android.server.am.ActivityManagerService#positionTaskInStack(int, int, int). */
-    public void positionTaskInStack(int taskId, int stackId, int position, Rect bounds,
-            Configuration overrideConfig) {
-        synchronized (mWindowMap) {
-            if (DEBUG_STACK) Slog.i(TAG_WM, "positionTaskInStack: positioning taskId=" + taskId
-                    + " in stackId=" + stackId + " at " + position);
-            Task task = mTaskIdToTask.get(taskId);
-            if (task == null) {
-                if (DEBUG_STACK) Slog.i(TAG_WM,
-                        "positionTaskInStack: could not find taskId=" + taskId);
-                return;
-            }
-            TaskStack stack = mStackIdToStack.get(stackId);
-            if (stack == null) {
-                if (DEBUG_STACK) Slog.i(TAG_WM,
-                        "positionTaskInStack: could not find stackId=" + stackId);
-                return;
-            }
-            task.positionTaskInStack(stack, position, bounds, overrideConfig);
-            final DisplayContent displayContent = stack.getDisplayContent();
-            displayContent.setLayoutNeeded();
-            mWindowPlacerLocked.performSurfacePlacement();
-        }
-    }
-
-    /**
-     * Re-sizes the specified task and its containing windows.
-     * Returns a {@link Configuration} object that contains configurations settings
-     * that should be overridden due to the operation.
-     */
-    public void resizeTask(int taskId, Rect bounds, Configuration overrideConfig,
-            boolean relayout, boolean forced) {
-        synchronized (mWindowMap) {
-            Task task = mTaskIdToTask.get(taskId);
-            if (task == null) {
-                throw new IllegalArgumentException("resizeTask: taskId " + taskId
-                        + " not found.");
-            }
-
-            if (task.resizeLocked(bounds, overrideConfig, forced) && relayout) {
-                task.getDisplayContent().setLayoutNeeded();
-                mWindowPlacerLocked.performSurfacePlacement();
-            }
-        }
-    }
-
-    /**
-     * Puts a specific task into docked drag resizing mode. See {@link DragResizeMode}.
-     *
-     * @param taskId The id of the task to put into drag resize mode.
-     * @param resizing Whether to put the task into drag resize mode.
-     */
-    public void setTaskDockedResizing(int taskId, boolean resizing) {
-        synchronized (mWindowMap) {
-            Task task = mTaskIdToTask.get(taskId);
-            if (task == null) {
-                Slog.w(TAG, "setTaskDockedResizing: taskId " + taskId + " not found.");
-                return;
-            }
-            task.setDragResizing(resizing, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
-        }
-    }
-
     /**
      * Starts deferring layout passes. Useful when doing multiple changes but to optimize
      * performance, only one layout pass should be done. This can be called multiple times, and
@@ -3301,24 +3083,6 @@
         }
     }
 
-    public void getTaskBounds(int taskId, Rect bounds) {
-        synchronized (mWindowMap) {
-            Task task = mTaskIdToTask.get(taskId);
-            if (task != null) {
-                task.getBounds(bounds);
-                return;
-            }
-            bounds.setEmpty();
-        }
-    }
-
-    /** Return true if the input task id represents a valid window manager task. */
-    public boolean isValidTaskId(int taskId) {
-        synchronized (mWindowMap) {
-            return mTaskIdToTask.get(taskId) != null;
-        }
-    }
-
     /**
      * @return true if the activity contains windows that have
      *         {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set
@@ -5578,9 +5342,6 @@
         public static final int REPORT_FOCUS_CHANGE = 2;
         public static final int REPORT_LOSING_FOCUS = 3;
         public static final int DO_TRAVERSAL = 4;
-        public static final int ADD_STARTING = 5;
-        public static final int REMOVE_STARTING = 6;
-        public static final int FINISHED_STARTING = 7;
         public static final int WINDOW_FREEZE_TIMEOUT = 11;
 
         public static final int APP_TRANSITION_TIMEOUT = 13;
@@ -5722,126 +5483,6 @@
                     }
                 } break;
 
-                case ADD_STARTING: {
-                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
-                    final StartingData sd = wtoken.startingData;
-
-                    if (sd == null) {
-                        // Animation has been canceled... do nothing.
-                        return;
-                    }
-
-                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting "
-                            + wtoken + ": pkg=" + sd.pkg);
-
-                    View view = null;
-                    try {
-                        view = mPolicy.addStartingWindow(wtoken.token, sd.pkg, sd.theme,
-                            sd.compatInfo, sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.logo,
-                            sd.windowFlags, wtoken.getMergedOverrideConfiguration());
-                    } catch (Exception e) {
-                        Slog.w(TAG_WM, "Exception when adding starting window", e);
-                    }
-
-                    if (view != null) {
-                        boolean abort = false;
-
-                        synchronized(mWindowMap) {
-                            if (wtoken.removed || wtoken.startingData == null) {
-                                // If the window was successfully added, then
-                                // we need to remove it.
-                                if (wtoken.startingWindow != null) {
-                                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
-                                            "Aborted starting " + wtoken
-                                            + ": removed=" + wtoken.removed
-                                            + " startingData=" + wtoken.startingData);
-                                    wtoken.startingWindow = null;
-                                    wtoken.startingData = null;
-                                    abort = true;
-                                }
-                            } else {
-                                wtoken.startingView = view;
-                            }
-                            if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM,
-                                    "Added starting " + wtoken
-                                    + ": startingWindow="
-                                    + wtoken.startingWindow + " startingView="
-                                    + wtoken.startingView);
-                        }
-
-                        if (abort) {
-                            try {
-                                mPolicy.removeStartingWindow(wtoken.token, view);
-                            } catch (Exception e) {
-                                Slog.w(TAG_WM, "Exception when removing starting window", e);
-                            }
-                        }
-                    }
-                } break;
-
-                case REMOVE_STARTING: {
-                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
-                    IBinder token = null;
-                    View view = null;
-                    synchronized (mWindowMap) {
-                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Remove starting "
-                                + wtoken + ": startingWindow="
-                                + wtoken.startingWindow + " startingView="
-                                + wtoken.startingView);
-                        if (wtoken.startingWindow != null) {
-                            view = wtoken.startingView;
-                            token = wtoken.token;
-                            wtoken.startingData = null;
-                            wtoken.startingView = null;
-                            wtoken.startingWindow = null;
-                            wtoken.startingDisplayed = false;
-                        }
-                    }
-                    if (view != null) {
-                        try {
-                            mPolicy.removeStartingWindow(token, view);
-                        } catch (Exception e) {
-                            Slog.w(TAG_WM, "Exception when removing starting window", e);
-                        }
-                    }
-                } break;
-
-                case FINISHED_STARTING: {
-                    IBinder token = null;
-                    View view = null;
-                    while (true) {
-                        synchronized (mWindowMap) {
-                            final int N = mFinishedStarting.size();
-                            if (N <= 0) {
-                                break;
-                            }
-                            AppWindowToken wtoken = mFinishedStarting.remove(N-1);
-
-                            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
-                                    "Finished starting " + wtoken
-                                    + ": startingWindow=" + wtoken.startingWindow
-                                    + " startingView=" + wtoken.startingView);
-
-                            if (wtoken.startingWindow == null) {
-                                continue;
-                            }
-
-                            view = wtoken.startingView;
-                            token = wtoken.token;
-                            wtoken.startingData = null;
-                            wtoken.startingView = null;
-                            wtoken.startingWindow = null;
-                            wtoken.startingDisplayed = false;
-                        }
-
-                        try {
-                            mPolicy.removeStartingWindow(token, view);
-                        } catch (Exception e) {
-                            Slog.w(TAG_WM, "Exception when removing starting window", e);
-                        }
-                    }
-                } break;
-
                 case WINDOW_FREEZE_TIMEOUT: {
                     // TODO(multidisplay): Can non-default displays rotate?
                     synchronized (mWindowMap) {
@@ -7348,21 +6989,6 @@
     private void dumpTokensLocked(PrintWriter pw, boolean dumpAll) {
         pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
         mRoot.dumpTokens(pw, dumpAll);
-        if (!mFinishedStarting.isEmpty()) {
-            pw.println();
-            pw.println("  Finishing start of application tokens:");
-            for (int i=mFinishedStarting.size()-1; i>=0; i--) {
-                WindowToken token = mFinishedStarting.get(i);
-                pw.print("  Finished Starting #"); pw.print(i);
-                        pw.print(' '); pw.print(token);
-                if (dumpAll) {
-                    pw.println(':');
-                    token.dump(pw, "    ");
-                } else {
-                    pw.println();
-                }
-            }
-        }
         if (!mOpeningApps.isEmpty() || !mClosingApps.isEmpty()) {
             pw.println();
             if (mOpeningApps.size() > 0) {
@@ -7992,15 +7618,6 @@
         }
     }
 
-    public void setTaskResizeable(int taskId, int resizeMode) {
-        synchronized (mWindowMap) {
-            final Task task = mTaskIdToTask.get(taskId);
-            if (task != null) {
-                task.setResizeable(resizeMode);
-            }
-        }
-    }
-
     public void setForceResizableTasks(boolean forceResizableTasks) {
         synchronized (mWindowMap) {
             mForceResizableTasks = forceResizableTasks;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index e5ed18d..19ef44c 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -461,16 +461,7 @@
         mStackClip = STACK_CLIP_BEFORE_ANIM;
         mWin.checkPolicyVisibilityChange();
         mTransformation.clear();
-        if (mDrawState == HAS_DRAWN
-                && mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
-                && mWin.mAppToken != null
-                && mWin.mAppToken.firstWindowDrawn
-                && mWin.mAppToken.startingData != null) {
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Finish starting "
-                    + mWin.mToken + ": first real window done animating");
-            mService.mFinishedStarting.add(mWin.mAppToken);
-            mService.mH.sendEmptyMessage(H.FINISHED_STARTING);
-        } else if (mAttrType == LayoutParams.TYPE_STATUS_BAR && mWin.mPolicyVisibility) {
+        if (mAttrType == LayoutParams.TYPE_STATUS_BAR && mWin.mPolicyVisibility) {
             // Upon completion of a not-visible to visible status bar animation a relayout is
             // required.
             if (displayContent != null) {
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 1aabd5e..4df1001 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -441,8 +441,9 @@
             wtoken.deferClearAllDrawn = false;
             // Ensure that apps that are mid-starting are also scheduled to have their
             // starting windows removed after the animation is complete
-            if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit) {
-                mService.scheduleRemoveStartingWindowLocked(wtoken);
+            if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit
+                    && wtoken.getController() != null) {
+                wtoken.getController().removeStartingWindow();
             }
             mService.mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
 
diff --git a/services/core/jni/com_android_server_connectivity_Vpn.cpp b/services/core/jni/com_android_server_connectivity_Vpn.cpp
index c54d732..4d85d9a 100644
--- a/services/core/jni/com_android_server_connectivity_Vpn.cpp
+++ b/services/core/jni/com_android_server_connectivity_Vpn.cpp
@@ -17,24 +17,25 @@
 #define LOG_NDEBUG 0
 
 #define LOG_TAG "VpnJni"
-#include <cutils/log.h>
-#include "netutils/ifc.h"
 
-#include <stdio.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
 #include <arpa/inet.h>
 #include <errno.h>
 #include <fcntl.h>
-
 #include <linux/if.h>
 #include <linux/if_tun.h>
 #include <linux/route.h>
 #include <linux/ipv6_route.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <log/log.h>
+
+#include "netutils/ifc.h"
 
 #include "jni.h"
 #include "JNIHelp.h"
diff --git a/services/core/jni/com_android_server_lights_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp
index cf7f1cb..2fd0603 100644
--- a/services/core/jni/com_android_server_lights_LightsService.cpp
+++ b/services/core/jni/com_android_server_lights_LightsService.cpp
@@ -103,16 +103,15 @@
         state.flashMode = Flash::NONE;
     } else {
         // Only set non-brightness settings when not in low-persistence mode
-        state.color = colorARGB;
         state.flashMode = flash;
         state.flashOnMs = onMS;
         state.flashOffMs = offMS;
     }
 
+    state.color = colorARGB;
     state.brightnessMode = brightness;
 
     Status status;
-
     {
         ALOGD_IF_SLOW(50, "Excessive delay setting light");
         Return<Status> ret = gLight->setLight(type, state);
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 09886db..fa6405a 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -59,6 +59,12 @@
 static jmethodID method_reportMeasurementData;
 static jmethodID method_reportNavigationMessages;
 
+/*
+ * Save a pointer to JavaVm to attach/detach threads executing
+ * callback methods that need to make JNI calls.
+ */
+static JavaVM* sJvm;
+
 using android::OK;
 using android::sp;
 using android::status_t;
@@ -216,6 +222,62 @@
     }
 }
 
+class ScopedJniThreadAttach {
+public:
+    ScopedJniThreadAttach() {
+        /*
+         * attachResult will also be JNI_OK if the thead was already attached to
+         * JNI before the call to AttachCurrentThread().
+         */
+        jint attachResult = sJvm->AttachCurrentThread(&mEnv, nullptr);
+        LOG_ALWAYS_FATAL_IF(attachResult != JNI_OK, "Unable to attach thread. Error %d",
+                            attachResult);
+    }
+
+    ~ScopedJniThreadAttach() {
+        jint detachResult = sJvm->DetachCurrentThread();
+        /*
+         * Return if the thread was already detached. Log error for any other
+         * failure.
+         */
+        if (detachResult == JNI_EDETACHED) {
+            return;
+        }
+
+        LOG_ALWAYS_FATAL_IF(detachResult != JNI_OK, "Unable to detach thread. Error %d",
+                            detachResult);
+    }
+
+    JNIEnv* getEnv() {
+        /*
+         * Checking validity of mEnv in case the thread was detached elsewhere.
+         */
+        LOG_ALWAYS_FATAL_IF(AndroidRuntime::getJNIEnv() != mEnv);
+        return mEnv;
+    }
+
+private:
+    JNIEnv* mEnv = nullptr;
+};
+
+thread_local std::unique_ptr<ScopedJniThreadAttach> tJniThreadAttacher;
+
+static JNIEnv* getJniEnv() {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+    /*
+     * If env is nullptr, the thread is not already attached to
+     * JNI. It is attached below and the destructor for ScopedJniThreadAttach
+     * will detach it on thread exit.
+     */
+    if (env == nullptr) {
+        tJniThreadAttacher.reset(new ScopedJniThreadAttach());
+        env = tJniThreadAttacher->getEnv();
+    }
+
+    return env;
+}
+
 /*
  * GnssCallback class implements the callback methods for IGnss interface.
  */
@@ -247,7 +309,7 @@
 
 Return<void> GnssCallback::gnssLocationCb(
         const ::android::hardware::gnss::V1_0::GnssLocation& location) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getJniEnv();
     env->CallVoidMethod(mCallbacksObj,
                         method_reportLocation,
                         location.gnssLocationFlags,
@@ -263,14 +325,14 @@
 }
 
 Return<void> GnssCallback::gnssStatusCb(const IGnssCallback::GnssStatusValue status) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getJniEnv();
     env->CallVoidMethod(mCallbacksObj, method_reportStatus, status);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
     return Void();
 }
 
 Return<void> GnssCallback::gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getJniEnv();
 
     sGnssSvListSize = svStatus.numSvs;
     if (sGnssSvListSize > static_cast<uint32_t>(
@@ -292,7 +354,7 @@
 
 Return<void> GnssCallback::gnssNmeaCb(
     int64_t timestamp, const ::android::hardware::hidl_string& nmea) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getJniEnv();
     /*
      * The Java code will call back to read these values.
      * We do this to avoid creating unnecessary String objects.
@@ -308,7 +370,7 @@
 Return<void> GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) {
     ALOGD("%s: %du\n", __func__, capabilities);
 
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getJniEnv();
     env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
     return Void();
@@ -325,7 +387,7 @@
 }
 
 Return<void> GnssCallback::gnssRequestTimeCb() {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getJniEnv();
     env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
     return Void();
@@ -334,7 +396,7 @@
 Return<void> GnssCallback::gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) {
     ALOGD("%s: yearOfHw=%d\n", __func__, info.yearOfHw);
 
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getJniEnv();
     env->CallVoidMethod(mCallbacksObj, method_setGnssYearOfHardware,
                         info.yearOfHw);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
@@ -350,7 +412,7 @@
  * interface.
  */
 Return<void> GnssXtraCallback::downloadRequestCb() {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getJniEnv();
     env->CallVoidMethod(mCallbacksObj, method_xtraDownloadRequest);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
     return Void();
@@ -385,7 +447,7 @@
         const android::hardware::gnss::V1_0::GnssLocation& location,
         GeofenceTransition transition,
         hardware::gnss::V1_0::GnssUtcTime timestamp) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getJniEnv();
 
     env->CallVoidMethod(mCallbacksObj,
                         method_reportGeofenceTransition,
@@ -408,7 +470,7 @@
 Return<void> GnssGeofenceCallback::gnssGeofenceStatusCb(
         GeofenceAvailability status,
         const android::hardware::gnss::V1_0::GnssLocation& location) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getJniEnv();
     env->CallVoidMethod(mCallbacksObj,
                         method_reportGeofenceStatus,
                         status,
@@ -426,7 +488,7 @@
 
 Return<void> GnssGeofenceCallback::gnssGeofenceAddCb(int32_t geofenceId,
                                                     GeofenceStatus status) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getJniEnv();
     if (status != IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS) {
         ALOGE("%s: Error in adding a Geofence: %d\n", __func__, status);
     }
@@ -441,7 +503,7 @@
 
 Return<void> GnssGeofenceCallback::gnssGeofenceRemoveCb(int32_t geofenceId,
                                                        GeofenceStatus status) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getJniEnv();
     if (status != IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS) {
         ALOGE("%s: Error in removing a Geofence: %d\n", __func__, status);
     }
@@ -455,7 +517,7 @@
 
 Return<void> GnssGeofenceCallback::gnssGeofencePauseCb(int32_t geofenceId,
                                                       GeofenceStatus status) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getJniEnv();
     if (status != IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS) {
         ALOGE("%s: Error in pausing Geofence: %d\n", __func__, status);
     }
@@ -469,7 +531,7 @@
 
 Return<void> GnssGeofenceCallback::gnssGeofenceResumeCb(int32_t geofenceId,
                                                        GeofenceStatus status) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getJniEnv();
     if (status != IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS) {
         ALOGE("%s: Error in resuming Geofence: %d\n", __func__, status);
     }
@@ -496,7 +558,7 @@
 
 Return<void> GnssNavigationMessageCallback::gnssNavigationMessageCb(
         const IGnssNavigationMessageCallback::GnssNavigationMessage& message) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getJniEnv();
 
     size_t dataLength = message.data.size();
 
@@ -545,7 +607,7 @@
 
 Return<void> GnssMeasurementCallback::GnssMeasurementCb(
         const IGnssMeasurementCallback::GnssData& data) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getJniEnv();
 
     jobject clock;
     jobjectArray measurementArray;
@@ -700,7 +762,7 @@
 
 Return<void> GnssNiCallback::niNotifyCb(
         const IGnssNiCallback::GnssNiNotification& notification) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getJniEnv();
     jstring requestorId = env->NewStringUTF(notification.requestorId.c_str());
     jstring text = env->NewStringUTF(notification.notificationMessage.c_str());
 
@@ -742,7 +804,7 @@
 
 Return<void> AGnssCallback::agnssStatusIpV6Cb(
         const IAGnssCallback::AGnssStatusIpV6& agps_status) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getJniEnv();
     jbyteArray byteArray = NULL;
     bool isSupported = false;
 
@@ -778,7 +840,7 @@
 
 Return<void> AGnssCallback::agnssStatusIpV4Cb(
         const IAGnssCallback::AGnssStatusIpV4& agps_status) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getJniEnv();
     jbyteArray byteArray = NULL;
 
     uint32_t ipAddr = agps_status.ipV4Addr;
@@ -813,7 +875,7 @@
         return NULL;
     }
 
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getJniEnv();
     jbyteArray byteArray = env->NewByteArray(4);
     if (byteArray == NULL) {
         ALOGE("Unable to allocate byte array for IPv4 address");
@@ -832,19 +894,19 @@
  * interface.
  */
 struct AGnssRilCallback : IAGnssRilCallback {
-    Return<void> requestSetIdCb(IAGnssRilCallback::ID setIdFlag) override;
+    Return<void> requestSetIdCb(uint32_t setIdFlag) override;
     Return<void> requestRefLocCb() override;
 };
 
-Return<void> AGnssRilCallback::requestSetIdCb(IAGnssRilCallback::ID setIdFlag) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+Return<void> AGnssRilCallback::requestSetIdCb(uint32_t setIdFlag) {
+    JNIEnv* env = getJniEnv();
     env->CallVoidMethod(mCallbacksObj, method_requestSetID, setIdFlag);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
     return Void();
 }
 
 Return<void> AGnssRilCallback::requestRefLocCb() {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getJniEnv();
     env->CallVoidMethod(mCallbacksObj, method_requestRefLocation);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
     return Void();
@@ -885,6 +947,14 @@
             "reportNavigationMessage",
             "(Landroid/location/GnssNavigationMessage;)V");
 
+    /*
+     * Save a pointer to JVM.
+     */
+    jint jvmStatus = env->GetJavaVM(&sJvm);
+    if (jvmStatus != JNI_OK) {
+        LOG_ALWAYS_FATAL("Unable to get Java VM. Error: %d", jvmStatus);
+    }
+
     // TODO(b/31632518)
     gnssHal = IGnss::getService("gnss");
     if (gnssHal != nullptr) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 9f66062..2e5b687 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -10097,6 +10097,7 @@
                 .setSmallIcon(R.drawable.ic_qs_network_logging)
                 .setContentTitle(mContext.getString(R.string.network_logging_notification_title))
                 .setContentText(mContext.getString(R.string.network_logging_notification_text))
+                .setTicker(mContext.getString(R.string.network_logging_notification_title))
                 .setShowWhen(true)
                 .setContentIntent(pendingIntent)
                 .build();
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index af570b0..1189dae 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -23,6 +23,7 @@
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.Assert.fail;
 
@@ -61,6 +62,7 @@
 import android.net.ScoredNetwork;
 import android.net.WifiKey;
 import android.net.wifi.WifiConfiguration;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
@@ -261,7 +263,7 @@
 
     @Test
     public void testUpdateScores_notActiveScorer() {
-        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
+        bindToScorer(false /*callerIsScorer*/);
 
         try {
             mNetworkScoreService.updateScores(new ScoredNetwork[0]);
@@ -273,7 +275,7 @@
 
     @Test
     public void testUpdateScores_oneRegisteredCache() throws RemoteException {
-        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
+        bindToScorer(true /*callerIsScorer*/);
 
         mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI,
                 mNetworkScoreCache, CACHE_FILTER_NONE);
@@ -288,7 +290,7 @@
 
     @Test
     public void testUpdateScores_twoRegisteredCaches() throws RemoteException {
-        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
+        bindToScorer(true /*callerIsScorer*/);
 
         mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI,
                 mNetworkScoreCache, CACHE_FILTER_NONE);
@@ -323,7 +325,7 @@
 
     @Test
     public void testClearScores_notActiveScorer_noRequestNetworkScoresPermission() {
-        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
+        bindToScorer(false /*callerIsScorer*/);
         when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
             .thenReturn(PackageManager.PERMISSION_DENIED);
         try {
@@ -336,7 +338,7 @@
 
     @Test
     public void testClearScores_activeScorer_noRequestNetworkScoresPermission() {
-        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
+        bindToScorer(true /*callerIsScorer*/);
         when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
             .thenReturn(PackageManager.PERMISSION_DENIED);
 
@@ -345,7 +347,7 @@
 
     @Test
     public void testClearScores_activeScorer() throws RemoteException {
-        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
+        bindToScorer(true /*callerIsScorer*/);
 
         mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache,
                 CACHE_FILTER_NONE);
@@ -357,7 +359,7 @@
     @Test
     public void testClearScores_notActiveScorer_hasRequestNetworkScoresPermission()
             throws RemoteException {
-        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
+        bindToScorer(false /*callerIsScorer*/);
         when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
                 .thenReturn(PackageManager.PERMISSION_GRANTED);
 
@@ -383,7 +385,7 @@
 
     @Test
     public void testDisableScoring_notActiveScorer_noRequestNetworkScoresPermission() {
-        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
+        bindToScorer(false /*callerIsScorer*/);
         when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
                 .thenReturn(PackageManager.PERMISSION_DENIED);
 
@@ -448,6 +450,42 @@
         assertFalse(stringWriter.toString().isEmpty());
     }
 
+    @Test
+    public void testIsCallerActiveScorer_noBoundService() throws Exception {
+        mNetworkScoreService.systemRunning();
+
+        assertFalse(mNetworkScoreService.isCallerActiveScorer(Binder.getCallingUid()));
+    }
+
+    @Test
+    public void testIsCallerActiveScorer_boundServiceIsNotCaller() throws Exception {
+        bindToScorer(false /*callerIsScorer*/);
+
+        assertFalse(mNetworkScoreService.isCallerActiveScorer(Binder.getCallingUid()));
+    }
+
+    @Test
+    public void testIsCallerActiveScorer_boundServiceIsCaller() throws Exception {
+        bindToScorer(true /*callerIsScorer*/);
+
+        assertTrue(mNetworkScoreService.isCallerActiveScorer(Binder.getCallingUid()));
+    }
+
+    @Test
+    public void testGetActiveScorerPackage_notActive() throws Exception {
+        mNetworkScoreService.systemRunning();
+
+        assertNull(mNetworkScoreService.getActiveScorerPackage());
+    }
+
+    @Test
+    public void testGetActiveScorerPackage_active() throws Exception {
+        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
+        mNetworkScoreService.systemRunning();
+
+        assertEquals(NEW_SCORER.packageName, mNetworkScoreService.getActiveScorerPackage());
+    }
+
     // "injects" the mock INetworkRecommendationProvider into the NetworkScoreService.
     private void injectProvider() {
         final ComponentName componentName = new ComponentName(NEW_SCORER.packageName,
@@ -467,4 +505,14 @@
         });
         mNetworkScoreService.systemRunning();
     }
+
+    private void bindToScorer(boolean callerIsScorer) {
+        final int callingUid = callerIsScorer ? Binder.getCallingUid() : 0;
+        NetworkScorerAppData appData = new NetworkScorerAppData(NEW_SCORER.packageName,
+                callingUid, NEW_SCORER.recommendationServiceClassName);
+        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(appData);
+        when(mContext.bindServiceAsUser(isA(Intent.class), isA(ServiceConnection.class), anyInt(),
+                isA(UserHandle.class))).thenReturn(true);
+        mNetworkScoreService.systemRunning();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 10ca902..228b8e0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -1403,7 +1403,7 @@
     protected ShortcutInfo makeShortcut(String id, String title, ComponentName activity,
             Icon icon, Intent intent, int rank) {
         final ShortcutInfo.Builder  b = new ShortcutInfo.Builder(mClientContext, id)
-                .setActivity(new ComponentName(mClientContext.getPackageName(), "dummy"))
+                .setActivity(new ComponentName(mClientContext.getPackageName(), "main"))
                 .setShortLabel(title)
                 .setRank(rank)
                 .setIntent(intent);
@@ -1432,7 +1432,7 @@
     protected ShortcutInfo makeShortcut(String id, String title, ComponentName activity,
             Icon icon, Intent[] intents, int rank) {
         final ShortcutInfo.Builder  b = new ShortcutInfo.Builder(mClientContext, id)
-                .setActivity(new ComponentName(mClientContext.getPackageName(), "dummy"))
+                .setActivity(new ComponentName(mClientContext.getPackageName(), "main"))
                 .setShortLabel(title)
                 .setRank(rank)
                 .setIntents(intents);
@@ -1455,7 +1455,7 @@
     protected ShortcutInfo makeShortcutWithExtras(String id, Intent intent,
             PersistableBundle extras) {
         final ShortcutInfo.Builder  b = new ShortcutInfo.Builder(mClientContext, id)
-                .setActivity(new ComponentName(mClientContext.getPackageName(), "dummy"))
+                .setActivity(new ComponentName(mClientContext.getPackageName(), "main"))
                 .setShortLabel("title-" + id)
                 .setExtras(extras)
                 .setIntent(intent);
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
index fbf0ed2..bcd72fc 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
@@ -38,6 +38,7 @@
 import android.os.UserHandle;
 import android.test.MoreAsserts;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
 import android.util.Pair;
 
 import com.android.frameworks.servicestests.R;
@@ -227,8 +228,9 @@
 
     private void assertPinItemRequest(PinItemRequest actualRequest) {
         assertNotNull(actualRequest);
-
         assertEquals(PinItemRequest.REQUEST_TYPE_SHORTCUT, actualRequest.getRequestType());
+
+        Log.i(TAG, "Requested shortcut: " + actualRequest.getShortcutInfo().toInsecureString());
     }
 
     /**
@@ -243,9 +245,16 @@
         final Icon res32x32 = Icon.createWithResource(getTestContext(), R.drawable.black_32x32);
 
         runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
-            ShortcutInfo s1 = makeShortcutWithIcon("s1", res32x32);
+            /// Create a shortcut with no target activity.
+            final ShortcutInfo.Builder  b = new ShortcutInfo.Builder(mClientContext, "s1")
+                    .setShortLabel("Title-" + "s1")
+                    .setIcon(res32x32)
+                    .setIntent(makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class));
+            final ShortcutInfo s = b.build();
 
-            assertTrue(mManager.requestPinShortcut(s1,
+            assertNull(s.getActivity());
+
+            assertTrue(mManager.requestPinShortcut(s,
                     resultIntent == null ? null : resultIntent.getIntentSender()));
 
             verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
@@ -271,6 +280,7 @@
             assertWith(request.getShortcutInfo())
                     .haveIds("s1")
                     .areAllOrphan()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, MAIN_ACTIVITY_CLASS))
                     .areAllWithNoIntent();
 
             assertAllHaveIcon(list(request.getShortcutInfo()));
@@ -295,6 +305,7 @@
                     .areAllNotDynamic()
                     .areAllEnabled()
                     .areAllPinned()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, MAIN_ACTIVITY_CLASS))
                     .areAllWithIntent();
         });
     }
@@ -310,6 +321,145 @@
         checkRequestPinShortcut(resultIntent);
     }
 
+    public void testRequestPinShortcut_explicitTargetActivity() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+        setDefaultLauncher(USER_10, mMainActivityFetcher.apply(LAUNCHER_2, USER_10));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            ShortcutInfo s1 = makeShortcutWithActivity("s1",
+                    new ComponentName(CALLING_PACKAGE_1, "different_activity"));
+
+            assertTrue(mManager.requestPinShortcut(s1, null));
+
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+
+            // Shortcut shouldn't be registered yet.
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Check the intent passed to startActivityAsUser().
+            final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+
+            verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
+
+            assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage);
+
+            // Check the request object.
+            final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
+
+            assertPinItemRequest(request);
+
+            assertWith(request.getShortcutInfo())
+                    .haveIds("s1")
+                    .areAllOrphan()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "different_activity"))
+                    .areAllWithNoIntent();
+
+            // Accept the request.
+            assertForLauncherCallbackNoThrow(mLauncherApps,
+                    () -> assertTrue(request.accept()))
+                    .assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_P0)
+                    .haveIds("s1");
+        });
+
+        verify(mServiceContext, times(1)).sendIntentSender(eq(null));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1")
+                    .areAllNotDynamic()
+                    .areAllEnabled()
+                    .areAllPinned()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "different_activity"))
+                    .areAllWithIntent();
+        });
+    }
+
+    public void testRequestPinShortcut_wrongTargetActivity() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            // Create dynamic shortcut
+            ShortcutInfo s1 = makeShortcutWithActivity("s1",
+                    new ComponentName("wrong_package", "different_activity"));
+
+            assertExpectException(IllegalStateException.class, "not belong to package", () -> {
+                assertTrue(mManager.requestPinShortcut(s1, /* resultIntent=*/ null));
+            });
+
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+            verify(mServiceContext, times(0)).startActivityAsUser(
+                    any(Intent.class), any(UserHandle.class));
+        });
+    }
+
+    public void testRequestPinShortcut_noTargetActivity_noMainActivity() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+        setDefaultLauncher(USER_10, mMainActivityFetcher.apply(LAUNCHER_2, USER_10));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            /// Create a shortcut with no target activity.
+            final ShortcutInfo.Builder  b = new ShortcutInfo.Builder(mClientContext, "s1")
+                    .setShortLabel("Title-" + "s1")
+                    .setIntent(makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class));
+            final ShortcutInfo s = b.build();
+
+            assertNull(s.getActivity());
+
+            // Caller has no main activity.
+            mMainActivityFetcher = (packageName, userId) -> null;
+
+            assertTrue(mManager.requestPinShortcut(s, null));
+
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+
+            // Shortcut shouldn't be registered yet.
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Check the intent passed to startActivityAsUser().
+            final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+
+            verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
+
+            assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage);
+
+            // Check the request object.
+            final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
+
+            assertPinItemRequest(request);
+
+            assertWith(request.getShortcutInfo())
+                    .haveIds("s1")
+                    .areAllOrphan()
+                    .areAllWithNoActivity() // Activity is not set; expected.
+                    .areAllWithNoIntent();
+
+            // Accept the request.
+            assertForLauncherCallbackNoThrow(mLauncherApps,
+                    () -> assertTrue(request.accept()))
+                    .assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_P0)
+                    .haveIds("s1");
+        });
+
+        verify(mServiceContext, times(1)).sendIntentSender(eq(null));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1")
+                    .areAllNotDynamic()
+                    .areAllEnabled()
+                    .areAllPinned()
+                    .areAllWithNoActivity() // Activity is not set; expected.
+                    .areAllWithIntent();
+        });
+
+    }
+
     public void testRequestPinShortcut_dynamicExists() {
         setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
 
@@ -328,6 +478,7 @@
             assertWith(getCallerShortcuts())
                     .haveIds("s1")
                     .areAllDynamic()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
                     .areAllNotPinned();
         });
 
@@ -348,6 +499,7 @@
                     .haveIds("s1")
                     .areAllDynamic()
                     .areAllNotPinned()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
                     .areAllWithNoIntent();
 
             assertAllHaveIcon(list(request.getShortcutInfo()));
@@ -361,6 +513,7 @@
                     .haveIds("s1")
                     .areAllDynamic()
                     .areAllEnabled()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
                     .areAllPinned();
         });
     }
@@ -379,6 +532,8 @@
             assertWith(getCallerShortcuts())
                     .haveIds("ms1")
                     .areAllManifest()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1,
+                            ShortcutActivity.class.getName()))
                     .areAllNotPinned();
         });
 
@@ -399,6 +554,8 @@
                     .haveIds("ms1")
                     .areAllManifest()
                     .areAllNotPinned()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1,
+                            ShortcutActivity.class.getName()))
                     .areAllWithNoIntent();
 
             assertAllHaveIcon(list(request.getShortcutInfo()));
@@ -412,6 +569,8 @@
                     .haveIds("ms1")
                     .areAllManifest()
                     .areAllEnabled()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1,
+                            ShortcutActivity.class.getName()))
                     .areAllPinned();
         });
     }
@@ -431,6 +590,7 @@
             assertWith(getCallerShortcuts())
                     .haveIds("s1")
                     .areAllDynamic()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
                     .areAllPinned();
 
             assertTrue(mManager.requestPinShortcut(makeShortcutIdOnly("s1"),
@@ -456,6 +616,8 @@
             assertWith(getCallerShortcuts())
                     .haveIds("ms1")
                     .areAllManifest()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1,
+                            ShortcutActivity.class.getName()))
                     .areAllPinned();
 
             assertTrue(mManager.requestPinShortcut(makeShortcutIdOnly("ms1"),
@@ -483,6 +645,7 @@
                     .haveIds("s1")
                     .areAllNotDynamic()
                     .areAllEnabled()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
                     .areAllPinned();
 
             assertTrue(mManager.requestPinShortcut(makeShortcutIdOnly("s1"),
@@ -511,6 +674,7 @@
                     .haveIds("s1")
                     .areAllNotDynamic()
                     .areAllDisabled()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
                     .areAllPinned();
 
             assertExpectException(IllegalArgumentException.class, "exists but disabled", () -> {
@@ -541,6 +705,8 @@
                     .haveIds("ms1")
                     .areAllNotManifest()
                     .areAllDisabled()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1,
+                            ShortcutActivity.class.getName()))
                     .areAllPinned();
 
             assertExpectException(IllegalArgumentException.class, "exists but disabled", () -> {
@@ -570,6 +736,7 @@
             assertWith(getCallerShortcuts())
                     .haveIds("s1")
                     .areAllDynamic()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
                     .areAllPinned();
 
             // The shortcut is already pinned, but not by the current launcher, so it'll still
@@ -597,6 +764,7 @@
                     .haveIds("s1")
                     .areAllDynamic()
                     .areAllNotPinned() // Note it's not pinned by this launcher.
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
                     .areAllWithNoIntent();
 
             // Accept the request.
@@ -608,6 +776,7 @@
                     .haveIds("s1")
                     .areAllDynamic()
                     .areAllEnabled()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
                     .areAllPinned();
         });
     }
@@ -629,6 +798,8 @@
             assertWith(getCallerShortcuts())
                     .haveIds("ms1")
                     .areAllManifest()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1,
+                            ShortcutActivity.class.getName()))
                     .areAllPinned();
 
             // The shortcut is already pinned, but not by the current launcher, so it'll still
@@ -656,6 +827,8 @@
                     .haveIds("ms1")
                     .areAllManifest()
                     .areAllNotPinned() // Note it's not pinned by this launcher.
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1,
+                            ShortcutActivity.class.getName()))
                     .areAllWithNoIntent();
 
             // Accept the request.
@@ -667,6 +840,8 @@
                     .haveIds("ms1")
                     .areAllManifest()
                     .areAllEnabled()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1,
+                            ShortcutActivity.class.getName()))
                     .areAllPinned();
         });
     }
@@ -710,6 +885,7 @@
                     .haveIds("s1")
                     .areAllDynamic()
                     .areAllNotPinned()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
                     .areAllWithNoIntent();
 
             // Accept the request.
@@ -719,6 +895,7 @@
                     .haveIds("s1", "s2")
                     .areAllDynamic()
                     .areAllEnabled()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
                     .areAllPinned();
         });
 
@@ -727,6 +904,7 @@
                     .haveIds("s1", "s2")
                     .areAllDynamic()
                     .areAllEnabled()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
                     .areAllPinned();
         });
     }
@@ -752,6 +930,7 @@
             assertWith(getCallerShortcuts())
                     .haveIds("s1")
                     .areAllDynamic()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
                     .areAllNotPinned();
         });
 
@@ -772,6 +951,7 @@
                     .haveIds("s1")
                     .areAllDynamic()
                     .areAllNotPinned()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
                     .areAllWithNoIntent();
 
             assertAllHaveIcon(list(request.getShortcutInfo()));
@@ -786,6 +966,7 @@
                     .areAllDynamic()
                     .areAllEnabled()
                     .areAllPinned()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
                     .forShortcutWithId("s1", (si) -> {
                         // Still the original title.
                         assertEquals("Title-s1", si.getShortLabel());
@@ -810,6 +991,8 @@
             assertWith(getCallerShortcuts())
                     .haveIds("ms1")
                     .areAllManifest()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1,
+                            ShortcutActivity.class.getName()))
                     .areAllNotPinned();
         });
 
@@ -830,6 +1013,8 @@
                     .haveIds("ms1")
                     .areAllManifest()
                     .areAllNotPinned()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1,
+                            ShortcutActivity.class.getName()))
                     .areAllWithNoIntent();
 
             assertAllHaveIcon(list(request.getShortcutInfo()));
@@ -844,6 +1029,8 @@
                     .areAllManifest()
                     .areAllEnabled()
                     .areAllPinned()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1,
+                            ShortcutActivity.class.getName()))
                     .forShortcutWithId("ms1", (si) -> {
                         // Still the original title.
                         // Title should be something like:
@@ -893,6 +1080,7 @@
                     .haveIds("s1")
                     .areAllDynamic()
                     .areAllNotPinned()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
                     .areAllWithNoIntent();
 
             // Accept the request -> should fail.
@@ -950,9 +1138,9 @@
                     .haveIds("s1")
                     .areAllDynamic()
                     .areAllNotPinned()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
                     .areAllWithNoIntent();
 
-            // Accept the request -> should fail.
             assertTrue(request.accept());
         });
 
@@ -1004,6 +1192,8 @@
                     .haveIds("ms1")
                     .areAllManifest()
                     .areAllNotPinned()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1,
+                            ShortcutActivity.class.getName()))
                     .areAllWithNoIntent();
 
             // Accept the request -> should fail.
@@ -1059,10 +1249,11 @@
                     .haveIds("ms1")
                     .areAllManifest()
                     .areAllNotPinned()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1,
+                            ShortcutActivity.class.getName()))
                     .areAllWithNoIntent();
 
 
-            // Accept the request -> should fail.
             assertTrue(request.accept());
         });
 
@@ -1071,6 +1262,9 @@
                     .haveIds("ms1")
                     .areAllMutable() // Note it's no longer immutable.
                     .areAllFloating()
+
+                    // Note it's the activity from makeShortcutWithShortLabel().
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
                     .forShortcutWithId("ms1", si -> {
                         assertEquals("new", si.getShortLabel());
                     });
@@ -1104,6 +1298,7 @@
             mManager.disableShortcuts(list("s1"));
             assertWith(getCallerShortcuts())
                     .haveIds("s1")
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
                     .areAllDisabled();
         });
 
@@ -1125,6 +1320,7 @@
                     .haveIds("s1")
                     .areAllDynamic()
                     .areAllNotPinned()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
                     .areAllWithNoIntent();
 
             // Accept the request -> should fail.
@@ -1144,6 +1340,7 @@
         runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
             assertWith(getCallerShortcuts())
                     .haveIds("s1")
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
                     .areAllDisabled();
         });
     }
@@ -1174,6 +1371,8 @@
             publishManifestShortcutsAsCaller(R.xml.shortcut_0);
             assertWith(getCallerShortcuts())
                     .haveIds("ms1")
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1,
+                            ShortcutActivity.class.getName()))
                     .areAllDisabled();
         });
 
@@ -1195,6 +1394,8 @@
                     .haveIds("ms1")
                     .areAllManifest()
                     .areAllNotPinned()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1,
+                            ShortcutActivity.class.getName()))
                     .areAllWithNoIntent();
 
             // Accept the request -> should fail.
@@ -1214,6 +1415,8 @@
         runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
             assertWith(getCallerShortcuts())
                     .haveIds("ms1")
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1,
+                            ShortcutActivity.class.getName()))
                     .areAllDisabled();
         });
     }
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
index 8a962e7..7f1c273 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
@@ -18,16 +18,22 @@
 
 import org.junit.Test;
 
+import android.os.Binder;
+import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.view.IApplicationToken;
 
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.res.Configuration.EMPTY;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
 
 /**
- * Test class for {@link WindowContainerController}.
+ * Test class for {@link AppWindowContainerController}.
  *
  * Build/Install/Run:
  *  bit FrameworksServicesTests:com.android.server.wm.AppWindowContainerControllerTests
@@ -36,7 +42,70 @@
 @Presubmit
 @org.junit.runner.RunWith(AndroidJUnit4.class)
 public class AppWindowContainerControllerTests extends WindowTestsBase {
-// TODO Add tests once TaskWindowContainerController is created.
+
     @Test
-    public void dummyTest() throws Exception {}
+    public void testRemoveContainer() throws Exception {
+        final TestAppWindowContainerController controller = createAppWindowController();
+
+        // Assert token was added to display.
+        assertNotNull(sDisplayContent.getWindowToken(controller.mToken.asBinder()));
+        // Assert that the container was created and linked.
+        assertNotNull(controller.mContainer);
+
+        controller.removeContainer(sDisplayContent.getDisplayId());
+
+        // Assert token was remove from display.
+        assertNull(sDisplayContent.getWindowToken(controller.mToken.asBinder()));
+        // Assert that the container was removed.
+        assertNull(controller.mContainer);
+    }
+
+    @Test
+    public void testSetOrientation() throws Exception {
+        final TestAppWindowContainerController controller = createAppWindowController();
+
+        // Assert orientation is unspecified to start.
+        assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, controller.getOrientation());
+
+        controller.setOrientation(SCREEN_ORIENTATION_LANDSCAPE, sDisplayContent.getDisplayId(),
+                EMPTY /* displayConfig */, false /* freezeScreenIfNeeded */);
+        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, controller.getOrientation());
+
+        controller.removeContainer(sDisplayContent.getDisplayId());
+        // Assert orientation is unspecified to after container is removed.
+        assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, controller.getOrientation());
+    }
+
+    private TestAppWindowContainerController createAppWindowController() {
+        final TaskStack stack = createTaskStackOnDisplay(sDisplayContent);
+        final TestTaskWindowContainerController taskController =
+                new TestTaskWindowContainerController(stack.mStackId);
+        final IApplicationToken token = new TestIApplicationToken();
+        return new TestAppWindowContainerController(taskController, token);
+    }
+
+    private class TestAppWindowContainerController extends AppWindowContainerController {
+
+        final IApplicationToken mToken;
+
+        TestAppWindowContainerController(TestTaskWindowContainerController taskController,
+                IApplicationToken token) {
+            super(taskController, token, null /* listener */, 0 /* index */,
+                    SCREEN_ORIENTATION_UNSPECIFIED, true /* fullscreen */,
+                    true /* showForAllUsers */, 0 /* configChanges */, false /* voiceInteraction */,
+                    false /* launchTaskBehind */, false /* alwaysFocusable */,
+                    0 /* targetSdkVersion */, 0 /* rotationAnimationHint */,
+                    0 /* inputDispatchingTimeoutNanos */, sWm);
+            mToken = token;
+        }
+    }
+
+    private class TestIApplicationToken implements IApplicationToken {
+
+        private final Binder mBinder = new Binder();
+        @Override
+        public IBinder asBinder() {
+            return mBinder;
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 786c2bb..85931e8 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -19,6 +19,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import android.content.res.Configuration;
 import android.hardware.display.DisplayManagerGlobal;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
@@ -208,6 +209,10 @@
         voiceInteractionWindow.removeImmediately();
     }
 
+    /**
+     * This tests stack movement between displays and proper stack's, task's and app token's display
+     * container references updates.
+     */
     @Test
     public void testMoveStackBetweenDisplays() throws Exception {
         // Create second display.
@@ -238,4 +243,28 @@
         assertEquals(sDisplayContent, task.getDisplayContent());
         assertEquals(sDisplayContent, token.getDisplayContent());
     }
+
+    /**
+     * This tests override configuration updates for display content.
+     */
+    @Test
+    public void testDisplayOverrideConfigUpdate() throws Exception {
+        final int displayId = sDisplayContent.getDisplayId();
+        final Configuration currentOverrideConfig = sDisplayContent.getOverrideConfiguration();
+
+        // Create new, slightly changed override configuration and apply it to the display.
+        final Configuration newOverrideConfig = new Configuration(currentOverrideConfig);
+        newOverrideConfig.densityDpi += 120;
+        newOverrideConfig.fontScale += 0.3;
+
+        sWm.setNewDisplayOverrideConfiguration(newOverrideConfig, displayId);
+
+        // Check that override config is applied.
+        assertEquals(newOverrideConfig, sDisplayContent.getOverrideConfiguration());
+
+        // Check that global configuration is updated, as we've updated default display's config.
+        final Configuration globalConfig = sWm.mRoot.getConfiguration();
+        assertEquals(newOverrideConfig.densityDpi, globalConfig.densityDpi);
+        assertEquals(newOverrideConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
new file mode 100644
index 0000000..0dd31c3
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 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.server.wm;
+
+import org.junit.Test;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+/**
+ * Test class for {@link TaskWindowContainerController}.
+ *
+ * Build/Install/Run:
+ *  bit FrameworksServicesTests:com.android.server.wm.TaskWindowContainerControllerTests
+ */
+@SmallTest
+@Presubmit
+@org.junit.runner.RunWith(AndroidJUnit4.class)
+public class TaskWindowContainerControllerTests extends WindowTestsBase {
+// TODO Add tests once StackWindowContainerController is created.
+    @Test
+    public void dummyTest() throws Exception {}
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 1853a65..c4fd722 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -16,29 +16,6 @@
 
 package com.android.server.wm;
 
-import com.android.internal.policy.IKeyguardDismissCallback;
-import com.android.internal.policy.IShortcutService;
-import com.android.server.input.InputManagerService;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.res.CompatibilityInfo;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.Display;
-import android.view.IWindowManager;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.WindowManagerPolicy;
-import android.view.animation.Animation;
-
-import java.io.PrintWriter;
-
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
@@ -62,8 +39,8 @@
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_PHONE;
 import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
-import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
 import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION;
+import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
 import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
 import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
@@ -81,9 +58,30 @@
 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-
 import static org.mockito.Mockito.mock;
 
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Display;
+import android.view.IWindowManager;
+import android.view.KeyEvent;
+import android.view.WindowManager;
+import android.view.WindowManagerPolicy;
+import android.view.animation.Animation;
+
+import com.android.internal.policy.IKeyguardDismissCallback;
+import com.android.internal.policy.IShortcutService;
+import com.android.server.input.InputManagerService;
+
+import java.io.PrintWriter;
+
 class TestWindowManagerPolicy implements WindowManagerPolicy {
     private static final String TAG = "TestWindowManagerPolicy";
 
@@ -308,14 +306,14 @@
     }
 
     @Override
-    public View addStartingWindow(IBinder appToken, String packageName, int theme,
+    public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme,
             CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon,
             int logo, int windowFlags, Configuration overrideConfig) {
         return null;
     }
 
     @Override
-    public void removeStartingWindow(IBinder appToken, View window) {
+    public void removeSplashScreen(IBinder appToken, StartingSurface surface) {
 
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
index ef6ee32..466da94 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
@@ -76,7 +76,7 @@
         final Rect mInsetBounds = new Rect();
         boolean mFullscreenForTest = true;
         TaskWithBounds(Rect bounds) {
-            super(0, mStubStack, 0, sWm, null, null, false, 0, false);
+            super(0, mStubStack, 0, sWm, null, null, false, 0, false, null);
             mBounds = bounds;
         }
         @Override
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index fb3beb3..be080f5 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -27,6 +27,7 @@
 
 import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
 import static android.app.AppOpsManager.OP_NONE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
 import static android.content.res.Configuration.EMPTY;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
@@ -39,6 +40,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
 import static org.mockito.Mockito.mock;
 
 /**
@@ -144,8 +146,8 @@
     /**Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
     Task createTaskInStack(TaskStack stack, int userId) {
         final Task newTask = new Task(sNextTaskId++, stack, userId, sWm, null, EMPTY, false, 0,
-                false);
-        stack.addTask(newTask, true);
+                false, null);
+        stack.addTask(newTask, POSITION_TOP);
         return newTask;
     }
 
@@ -192,4 +194,17 @@
             return mChildren.getLast();
         }
     }
+
+    /**
+     * Used so we can gain access to some protected members of {@link TaskWindowContainerController}
+     * class.
+     */
+    class TestTaskWindowContainerController extends TaskWindowContainerController {
+
+        TestTaskWindowContainerController(int stackId) {
+            super(sNextTaskId++, stackId, 0 /* userId */, null /* bounds */,
+                    EMPTY /* overrideConfig*/, RESIZE_MODE_UNRESIZEABLE, false /* homeTask*/,
+                    false /* isOnTopLauncher */, true /* toTop*/, true /* showForAllUsers */);
+        }
+    }
 }
diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
index a664f21..ea45bd1 100644
--- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
+++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
@@ -925,7 +925,7 @@
         }
 
         public ShortcutListAsserter areAllWithActivity(ComponentName activity) {
-            forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.getActivity().equals(activity)));
+            forAllShortcuts(s -> assertEquals("id=" + s.getId(), activity, s.getActivity()));
             return this;
         }
 
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index c69b7c2..b20384d 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -115,6 +115,13 @@
      */
     public static final String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts";
 
+    /**
+     * Extra key used to indicate the time (in millis) when the last outgoing emergency call was
+     * made.  This is used to identify potential emergency callbacks.
+     */
+    public static final String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS =
+            "android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS";
+
     public static class Details {
 
         /** Call can currently be put on hold or unheld. */
diff --git a/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java b/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
index 85584d3..4445a22 100644
--- a/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
+++ b/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
@@ -51,4 +51,8 @@
             view.dispatchDetachedFromWindow();
         }
     }
+
+    public static ViewRootImpl getRootView(View view) {
+        return view.mAttachInfo != null ? view.mAttachInfo.mViewRootImpl : null;
+    }
 }
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 71c1117..5e5ebd7 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -480,14 +480,6 @@
     }
 
     @Override
-    public void cancelTaskWindowTransition(int taskId) {
-    }
-
-    @Override
-    public void cancelTaskThumbnailTransition(int taskId) {
-    }
-
-    @Override
     public void endProlongedAnimations() {
     }
 
diff --git a/core/java/android/service/autofill/IAutoFillCallback.aidl b/tools/layoutlib/bridge/src/android/view/ViewRootImpl_Accessor.java
similarity index 68%
copy from core/java/android/service/autofill/IAutoFillCallback.aidl
copy to tools/layoutlib/bridge/src/android/view/ViewRootImpl_Accessor.java
index d6d4f39..0e15b97 100644
--- a/core/java/android/service/autofill/IAutoFillCallback.aidl
+++ b/tools/layoutlib/bridge/src/android/view/ViewRootImpl_Accessor.java
@@ -14,14 +14,13 @@
  * limitations under the License.
  */
 
-package android.service.autofill;
-
-import java.util.List;
+package android.view;
 
 /**
- * @hide
+ * Accessor to allow layoutlib to call {@link ViewRootImpl#dispatchApplyInsets} directly.
  */
-oneway interface IAutoFillCallback {
-    void autofill(in List values);
-    void showError(String message);
+public class ViewRootImpl_Accessor {
+    public static void dispatchApplyInsets(ViewRootImpl viewRoot, View host) {
+        viewRoot.dispatchApplyInsets(host);
+    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java
index 726ff22..2fe3ed5 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java
@@ -38,7 +38,10 @@
 import android.graphics.drawable.Drawable;
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
+import android.view.AttachInfo_Accessor;
 import android.view.View;
+import android.view.ViewRootImpl;
+import android.view.ViewRootImpl_Accessor;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.widget.RelativeLayout;
@@ -302,6 +305,17 @@
         return Bridge.getResourceId(ResourceType.ID, ID_PREFIX + name);
     }
 
+    @Override
+    public void requestFitSystemWindows() {
+        // The framework call would usually bubble up to ViewRootImpl but, in layoutlib, Layout will
+        // act as view root for most purposes. That way, we can also save going through the Handler
+        // to dispatch the new applied insets.
+        ViewRootImpl root = AttachInfo_Accessor.getRootView(this);
+        if (root != null) {
+            ViewRootImpl_Accessor.dispatchApplyInsets(root, this);
+        }
+    }
+
     /**
      * A helper class to help initialize the Layout.
      */
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/InsetsWidget.java b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/InsetsWidget.java
new file mode 100644
index 0000000..36e5c26
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/InsetsWidget.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 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.layoutlib.test.myapplication.widgets;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.WindowInsets;
+import android.widget.TextView;
+
+public class InsetsWidget extends TextView {
+    public static boolean sApplyInsetsCalled = false;
+
+    public InsetsWidget(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        requestApplyInsets();
+    }
+
+    @Override
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+        sApplyInsetsCalled = true;
+        return super.onApplyWindowInsets(insets);
+    }
+}
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/insets.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/insets.xml
new file mode 100644
index 0000000..ff06d79
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/insets.xml
@@ -0,0 +1,12 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:padding="16dp"
+              android:orientation="horizontal"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content">
+
+    <com.android.layoutlib.test.myapplication.widgets.InsetsWidget
+        android:text="Hello world"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/text1"/>
+</LinearLayout>
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index c813a12..cdcae89 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -53,7 +53,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.pm.PackageInstaller.Session;
 import android.content.res.AssetManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -61,32 +60,17 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.io.InputStream;
 import java.lang.ref.WeakReference;
-import java.net.MalformedURLException;
+import java.lang.reflect.Field;
 import java.net.URL;
-import java.net.URLClassLoader;
-import java.nio.file.CopyOption;
-import java.nio.file.FileVisitOption;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
-import java.nio.file.attribute.BasicFileAttributes;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Enumeration;
-import java.util.List;
 import java.util.concurrent.TimeUnit;
-import java.util.function.BiPredicate;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
 
 import com.google.android.collect.Lists;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -434,6 +418,30 @@
         renderAndVerify(params, "simple_activity.png");
     }
 
+    @Test
+    public void testOnApplyInsetsCall()
+            throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
+        // We get the widget via reflection to avoid IntelliJ complaining about the class being
+        // located in the wrong package. (From the Bridge tests point of view, it is)
+        Class insetsWidgetClass = Class.forName("com.android.layoutlib.test.myapplication.widgets" +
+                ".InsetsWidget");
+        Field field = insetsWidgetClass.getDeclaredField("sApplyInsetsCalled");
+        assertFalse((Boolean)field.get(null));
+
+        LayoutPullParser parser = createLayoutPullParser("insets.xml");
+        LayoutLibTestCallback layoutLibCallback =
+                new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
+        layoutLibCallback.initResources();
+        SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5,
+                layoutLibCallback, "Theme.Material.Light.NoActionBar", false,
+                RenderingMode.NORMAL, 22);
+
+        render(params, -1);
+
+        assertTrue((Boolean)field.get(null));
+        field.set(null, false);
+    }
+
     @AfterClass
     public static void tearDown() {
         sLayoutLibLog = null;
@@ -621,6 +629,37 @@
         return new LayoutPullParser(APP_TEST_RES + "/layout/" + layoutPath);
     }
 
+    @NonNull
+    private static RenderResult render(SessionParams params, long frameTimeNanos) {
+        // TODO: Set up action bar handler properly to test menu rendering.
+        // Create session params.
+        System_Delegate.setBootTimeNanos(TimeUnit.MILLISECONDS.toNanos(871732800000L));
+        System_Delegate.setNanosTime(TimeUnit.MILLISECONDS.toNanos(871732800000L));
+        RenderSession session = sBridge.createSession(params);
+
+        try {
+
+            if (frameTimeNanos != -1) {
+                session.setElapsedFrameTimeNanos(frameTimeNanos);
+            }
+
+            if (!session.getResult().isSuccess()) {
+                getLogger().error(session.getResult().getException(),
+                        session.getResult().getErrorMessage());
+            }
+            // Render the session with a timeout of 50s.
+            Result renderResult = session.render(50000);
+            if (!renderResult.isSuccess()) {
+                getLogger().error(session.getResult().getException(),
+                        session.getResult().getErrorMessage());
+            }
+
+            return RenderResult.getFromSession(session);
+        } finally {
+            session.dispose();
+        }
+    }
+
     /**
      * Create a new rendering session and test that rendering the given layout doesn't throw any
      * exceptions and matches the provided image.
@@ -629,40 +668,19 @@
      * how far in the future is.
      */
     @Nullable
-    private RenderResult renderAndVerify(SessionParams params, String goldenFileName, long frameTimeNanos)
+    private static RenderResult renderAndVerify(SessionParams params, String goldenFileName, long
+            frameTimeNanos)
             throws ClassNotFoundException {
-        // TODO: Set up action bar handler properly to test menu rendering.
-        // Create session params.
-        System_Delegate.setBootTimeNanos(TimeUnit.MILLISECONDS.toNanos(871732800000L));
-        System_Delegate.setNanosTime(TimeUnit.MILLISECONDS.toNanos(871732800000L));
-        RenderSession session = sBridge.createSession(params);
-
-        if (frameTimeNanos != -1) {
-            session.setElapsedFrameTimeNanos(frameTimeNanos);
-        }
-
-        if (!session.getResult().isSuccess()) {
-            getLogger().error(session.getResult().getException(),
-                    session.getResult().getErrorMessage());
-        }
-        // Render the session with a timeout of 50s.
-        Result renderResult = session.render(50000);
-        if (!renderResult.isSuccess()) {
-            getLogger().error(session.getResult().getException(),
-                    session.getResult().getErrorMessage());
-        }
+        RenderResult result = Main.render(params, frameTimeNanos);
         try {
             String goldenImagePath = APP_TEST_DIR + "/golden/" + goldenFileName;
-            ImageUtils.requireSimilar(goldenImagePath, session.getImage());
-
-            return RenderResult.getFromSession(session);
+            assertNotNull(result.getImage());
+            ImageUtils.requireSimilar(goldenImagePath, result.getImage());
         } catch (IOException e) {
             getLogger().error(e, e.getMessage());
-        } finally {
-            session.dispose();
         }
 
-        return null;
+        return result;
     }
 
     /**
@@ -670,9 +688,9 @@
      * exceptions and matches the provided image.
      */
     @Nullable
-    private RenderResult renderAndVerify(SessionParams params, String goldenFileName)
+    private static RenderResult renderAndVerify(SessionParams params, String goldenFileName)
             throws ClassNotFoundException {
-        return renderAndVerify(params, goldenFileName, -1);
+        return Main.renderAndVerify(params, goldenFileName, -1);
     }
 
     /**
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderResult.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderResult.java
index 17b20f7..087478f 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderResult.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderResult.java
@@ -23,6 +23,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 
+import java.awt.image.BufferedImage;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -31,19 +32,22 @@
     private final List<ViewInfo> mRootViews;
     private final List<ViewInfo> mSystemViews;
     private final Result mRenderResult;
+    private BufferedImage mImage;
 
     private RenderResult(@Nullable Result result, @Nullable List<ViewInfo> systemViewInfoList,
-            @Nullable List<ViewInfo> rootViewInfoList) {
+            @Nullable List<ViewInfo> rootViewInfoList, @Nullable BufferedImage image) {
         mSystemViews = systemViewInfoList == null ? Collections.emptyList() : systemViewInfoList;
         mRootViews = rootViewInfoList == null ? Collections.emptyList() : rootViewInfoList;
         mRenderResult = result;
+        mImage = image;
     }
 
     @NonNull
     static RenderResult getFromSession(@NonNull RenderSession session) {
         return new RenderResult(session.getResult(),
                 new ArrayList<>(session.getSystemRootViews()),
-                new ArrayList<>(session.getRootViews()));
+                new ArrayList<>(session.getRootViews()),
+                session.getImage());
     }
 
     @Nullable
@@ -60,4 +64,9 @@
     public List<ViewInfo> getSystemViews() {
         return mSystemViews;
     }
+
+    @Nullable
+    public BufferedImage getImage() {
+        return mImage;
+    }
 }