Merge "TIF: Fix comments for program start/end times" into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index d380e70..e9d5c3d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6417,22 +6417,6 @@
     field public static final android.os.Parcelable.Creator<android.app.usage.ConfigurationStats> CREATOR;
   }
 
-  public class DataUsagePolicy {
-    field public final int networkType;
-    field public final java.lang.String[] subscriberIds;
-    field public final long thresholdInBytes;
-    field public final int[] uids;
-  }
-
-  public static class DataUsagePolicy.Builder {
-    ctor public DataUsagePolicy.Builder();
-    method public android.app.usage.DataUsagePolicy.Builder addSubscriberId(java.lang.String);
-    method public android.app.usage.DataUsagePolicy.Builder addUid(int);
-    method public android.app.usage.DataUsagePolicy build();
-    method public android.app.usage.DataUsagePolicy.Builder setNetworkType(int);
-    method public android.app.usage.DataUsagePolicy.Builder setThreshold(long);
-  }
-
   public final class NetworkStats implements java.lang.AutoCloseable {
     method public void close();
     method public boolean getNextBucket(android.app.usage.NetworkStats.Bucket);
@@ -6457,8 +6441,7 @@
     field public static final int STATE_ALL = -1; // 0xffffffff
     field public static final int STATE_DEFAULT = 1; // 0x1
     field public static final int STATE_FOREGROUND = 2; // 0x2
-    field public static final int TAG_ALL = 0; // 0x0
-    field public static final int TAG_ANY = -1; // 0xffffffff
+    field public static final int TAG_NONE = 0; // 0x0
     field public static final int UID_ALL = -1; // 0xffffffff
     field public static final int UID_REMOVED = -4; // 0xfffffffc
     field public static final int UID_TETHERING = -5; // 0xfffffffb
@@ -6467,20 +6450,18 @@
   public class NetworkStatsManager {
     method public android.app.usage.NetworkStats queryDetails(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats queryDetailsForUid(int, java.lang.String, long, long, int) throws android.os.RemoteException, java.lang.SecurityException;
-    method public android.app.usage.NetworkStats queryDetailsForUidTag(int, java.lang.String, long, long, int, int) throws android.os.RemoteException, java.lang.SecurityException;
+    method public android.app.usage.NetworkStats queryDetailsForUidTag(int, java.lang.String, long, long, int, int);
     method public android.app.usage.NetworkStats querySummary(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
-    method public android.app.usage.NetworkStats querySummary(int, java.lang.String, long, long, boolean) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats.Bucket querySummaryForDevice(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
-    method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, java.lang.String, long, long, boolean) throws android.os.RemoteException, java.lang.SecurityException;
-    method public void registerDataUsageCallback(android.app.usage.DataUsagePolicy, android.app.usage.NetworkStatsManager.DataUsageCallback);
-    method public void registerDataUsageCallback(android.app.usage.DataUsagePolicy, android.app.usage.NetworkStatsManager.DataUsageCallback, android.os.Handler);
-    method public void unregisterDataUsageCallback(android.app.usage.NetworkStatsManager.DataUsageCallback);
+    method public void registerUsageCallback(int, java.lang.String, long, android.app.usage.NetworkStatsManager.UsageCallback);
+    method public void registerUsageCallback(int, java.lang.String, long, android.app.usage.NetworkStatsManager.UsageCallback, android.os.Handler);
+    method public void unregisterUsageCallback(android.app.usage.NetworkStatsManager.UsageCallback);
   }
 
-  public static class NetworkStatsManager.DataUsageCallback {
-    ctor public NetworkStatsManager.DataUsageCallback();
-    method public void onLimitReached();
+  public static abstract class NetworkStatsManager.UsageCallback {
+    ctor public NetworkStatsManager.UsageCallback();
+    method public abstract void onThresholdReached(int, java.lang.String);
   }
 
   public final class UsageEvents implements android.os.Parcelable {
@@ -23538,12 +23519,6 @@
     method public int getUid();
   }
 
-  public final class DataUsageRequest 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.net.DataUsageRequest> CREATOR;
-  }
-
   public class DhcpInfo implements android.os.Parcelable {
     ctor public DhcpInfo();
     method public int describeContents();
diff --git a/api/removed.txt b/api/removed.txt
index f9fce40..2673a82 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -17,6 +17,37 @@
 
 }
 
+package android.app.usage {
+
+  public class DataUsagePolicy {
+    field public final int networkType;
+    field public final java.lang.String[] subscriberIds;
+    field public final long thresholdInBytes;
+    field public final int[] uids;
+  }
+
+  public static class DataUsagePolicy.Builder {
+    ctor public DataUsagePolicy.Builder();
+    method public android.app.usage.DataUsagePolicy.Builder addSubscriberId(java.lang.String);
+    method public android.app.usage.DataUsagePolicy.Builder addUid(int);
+    method public android.app.usage.DataUsagePolicy build();
+    method public android.app.usage.DataUsagePolicy.Builder setNetworkType(int);
+    method public android.app.usage.DataUsagePolicy.Builder setThreshold(long);
+  }
+
+  public class NetworkStatsManager {
+    method public void registerDataUsageCallback(android.app.usage.DataUsagePolicy, android.app.usage.NetworkStatsManager.DataUsageCallback, android.os.Handler);
+    method public void registerDataUsageCallback(android.app.usage.DataUsagePolicy, android.app.usage.NetworkStatsManager.UsageCallback, android.os.Handler);
+    method public void unregisterDataUsageCallback(android.app.usage.NetworkStatsManager.DataUsageCallback);
+  }
+
+  public static abstract class NetworkStatsManager.DataUsageCallback {
+    ctor public NetworkStatsManager.DataUsageCallback();
+    method public deprecated void onLimitReached();
+  }
+
+}
+
 package android.content {
 
   public abstract class Context {
diff --git a/api/system-current.txt b/api/system-current.txt
index dbbefbf..e5c88cc 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6698,22 +6698,6 @@
     field public static final android.os.Parcelable.Creator<android.app.usage.ConfigurationStats> CREATOR;
   }
 
-  public class DataUsagePolicy {
-    field public final int networkType;
-    field public final java.lang.String[] subscriberIds;
-    field public final long thresholdInBytes;
-    field public final int[] uids;
-  }
-
-  public static class DataUsagePolicy.Builder {
-    ctor public DataUsagePolicy.Builder();
-    method public android.app.usage.DataUsagePolicy.Builder addSubscriberId(java.lang.String);
-    method public android.app.usage.DataUsagePolicy.Builder addUid(int);
-    method public android.app.usage.DataUsagePolicy build();
-    method public android.app.usage.DataUsagePolicy.Builder setNetworkType(int);
-    method public android.app.usage.DataUsagePolicy.Builder setThreshold(long);
-  }
-
   public final class NetworkStats implements java.lang.AutoCloseable {
     method public void close();
     method public boolean getNextBucket(android.app.usage.NetworkStats.Bucket);
@@ -6738,8 +6722,7 @@
     field public static final int STATE_ALL = -1; // 0xffffffff
     field public static final int STATE_DEFAULT = 1; // 0x1
     field public static final int STATE_FOREGROUND = 2; // 0x2
-    field public static final int TAG_ALL = 0; // 0x0
-    field public static final int TAG_ANY = -1; // 0xffffffff
+    field public static final int TAG_NONE = 0; // 0x0
     field public static final int UID_ALL = -1; // 0xffffffff
     field public static final int UID_REMOVED = -4; // 0xfffffffc
     field public static final int UID_TETHERING = -5; // 0xfffffffb
@@ -6748,20 +6731,18 @@
   public class NetworkStatsManager {
     method public android.app.usage.NetworkStats queryDetails(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats queryDetailsForUid(int, java.lang.String, long, long, int) throws android.os.RemoteException, java.lang.SecurityException;
-    method public android.app.usage.NetworkStats queryDetailsForUidTag(int, java.lang.String, long, long, int, int) throws android.os.RemoteException, java.lang.SecurityException;
+    method public android.app.usage.NetworkStats queryDetailsForUidTag(int, java.lang.String, long, long, int, int);
     method public android.app.usage.NetworkStats querySummary(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
-    method public android.app.usage.NetworkStats querySummary(int, java.lang.String, long, long, boolean) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats.Bucket querySummaryForDevice(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
-    method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, java.lang.String, long, long, boolean) throws android.os.RemoteException, java.lang.SecurityException;
-    method public void registerDataUsageCallback(android.app.usage.DataUsagePolicy, android.app.usage.NetworkStatsManager.DataUsageCallback);
-    method public void registerDataUsageCallback(android.app.usage.DataUsagePolicy, android.app.usage.NetworkStatsManager.DataUsageCallback, android.os.Handler);
-    method public void unregisterDataUsageCallback(android.app.usage.NetworkStatsManager.DataUsageCallback);
+    method public void registerUsageCallback(int, java.lang.String, long, android.app.usage.NetworkStatsManager.UsageCallback);
+    method public void registerUsageCallback(int, java.lang.String, long, android.app.usage.NetworkStatsManager.UsageCallback, android.os.Handler);
+    method public void unregisterUsageCallback(android.app.usage.NetworkStatsManager.UsageCallback);
   }
 
-  public static class NetworkStatsManager.DataUsageCallback {
-    ctor public NetworkStatsManager.DataUsageCallback();
-    method public void onLimitReached();
+  public static abstract class NetworkStatsManager.UsageCallback {
+    ctor public NetworkStatsManager.UsageCallback();
+    method public abstract void onThresholdReached(int, java.lang.String);
   }
 
   public final class UsageEvents implements android.os.Parcelable {
@@ -25364,12 +25345,6 @@
     method public int getUid();
   }
 
-  public final class DataUsageRequest 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.net.DataUsageRequest> CREATOR;
-  }
-
   public class DhcpInfo implements android.os.Parcelable {
     ctor public DhcpInfo();
     method public int describeContents();
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 6897ce0..7f2c2d6 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -15,6 +15,37 @@
 
 }
 
+package android.app.usage {
+
+  public class DataUsagePolicy {
+    field public final int networkType;
+    field public final java.lang.String[] subscriberIds;
+    field public final long thresholdInBytes;
+    field public final int[] uids;
+  }
+
+  public static class DataUsagePolicy.Builder {
+    ctor public DataUsagePolicy.Builder();
+    method public android.app.usage.DataUsagePolicy.Builder addSubscriberId(java.lang.String);
+    method public android.app.usage.DataUsagePolicy.Builder addUid(int);
+    method public android.app.usage.DataUsagePolicy build();
+    method public android.app.usage.DataUsagePolicy.Builder setNetworkType(int);
+    method public android.app.usage.DataUsagePolicy.Builder setThreshold(long);
+  }
+
+  public class NetworkStatsManager {
+    method public void registerDataUsageCallback(android.app.usage.DataUsagePolicy, android.app.usage.NetworkStatsManager.DataUsageCallback, android.os.Handler);
+    method public void registerDataUsageCallback(android.app.usage.DataUsagePolicy, android.app.usage.NetworkStatsManager.UsageCallback, android.os.Handler);
+    method public void unregisterDataUsageCallback(android.app.usage.NetworkStatsManager.DataUsageCallback);
+  }
+
+  public static abstract class NetworkStatsManager.DataUsageCallback {
+    ctor public NetworkStatsManager.DataUsageCallback();
+    method public deprecated void onLimitReached();
+  }
+
+}
+
 package android.content {
 
   public abstract class Context {
diff --git a/api/test-current.txt b/api/test-current.txt
index acd7299..ff2a41c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -6422,22 +6422,6 @@
     field public static final android.os.Parcelable.Creator<android.app.usage.ConfigurationStats> CREATOR;
   }
 
-  public class DataUsagePolicy {
-    field public final int networkType;
-    field public final java.lang.String[] subscriberIds;
-    field public final long thresholdInBytes;
-    field public final int[] uids;
-  }
-
-  public static class DataUsagePolicy.Builder {
-    ctor public DataUsagePolicy.Builder();
-    method public android.app.usage.DataUsagePolicy.Builder addSubscriberId(java.lang.String);
-    method public android.app.usage.DataUsagePolicy.Builder addUid(int);
-    method public android.app.usage.DataUsagePolicy build();
-    method public android.app.usage.DataUsagePolicy.Builder setNetworkType(int);
-    method public android.app.usage.DataUsagePolicy.Builder setThreshold(long);
-  }
-
   public final class NetworkStats implements java.lang.AutoCloseable {
     method public void close();
     method public boolean getNextBucket(android.app.usage.NetworkStats.Bucket);
@@ -6462,8 +6446,7 @@
     field public static final int STATE_ALL = -1; // 0xffffffff
     field public static final int STATE_DEFAULT = 1; // 0x1
     field public static final int STATE_FOREGROUND = 2; // 0x2
-    field public static final int TAG_ALL = 0; // 0x0
-    field public static final int TAG_ANY = -1; // 0xffffffff
+    field public static final int TAG_NONE = 0; // 0x0
     field public static final int UID_ALL = -1; // 0xffffffff
     field public static final int UID_REMOVED = -4; // 0xfffffffc
     field public static final int UID_TETHERING = -5; // 0xfffffffb
@@ -6472,20 +6455,18 @@
   public class NetworkStatsManager {
     method public android.app.usage.NetworkStats queryDetails(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats queryDetailsForUid(int, java.lang.String, long, long, int) throws android.os.RemoteException, java.lang.SecurityException;
-    method public android.app.usage.NetworkStats queryDetailsForUidTag(int, java.lang.String, long, long, int, int) throws android.os.RemoteException, java.lang.SecurityException;
+    method public android.app.usage.NetworkStats queryDetailsForUidTag(int, java.lang.String, long, long, int, int);
     method public android.app.usage.NetworkStats querySummary(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
-    method public android.app.usage.NetworkStats querySummary(int, java.lang.String, long, long, boolean) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats.Bucket querySummaryForDevice(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
-    method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, java.lang.String, long, long, boolean) throws android.os.RemoteException, java.lang.SecurityException;
-    method public void registerDataUsageCallback(android.app.usage.DataUsagePolicy, android.app.usage.NetworkStatsManager.DataUsageCallback);
-    method public void registerDataUsageCallback(android.app.usage.DataUsagePolicy, android.app.usage.NetworkStatsManager.DataUsageCallback, android.os.Handler);
-    method public void unregisterDataUsageCallback(android.app.usage.NetworkStatsManager.DataUsageCallback);
+    method public void registerUsageCallback(int, java.lang.String, long, android.app.usage.NetworkStatsManager.UsageCallback);
+    method public void registerUsageCallback(int, java.lang.String, long, android.app.usage.NetworkStatsManager.UsageCallback, android.os.Handler);
+    method public void unregisterUsageCallback(android.app.usage.NetworkStatsManager.UsageCallback);
   }
 
-  public static class NetworkStatsManager.DataUsageCallback {
-    ctor public NetworkStatsManager.DataUsageCallback();
-    method public void onLimitReached();
+  public static abstract class NetworkStatsManager.UsageCallback {
+    ctor public NetworkStatsManager.UsageCallback();
+    method public abstract void onThresholdReached(int, java.lang.String);
   }
 
   public final class UsageEvents implements android.os.Parcelable {
@@ -23607,12 +23588,6 @@
     method public int getUid();
   }
 
-  public final class DataUsageRequest 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.net.DataUsageRequest> CREATOR;
-  }
-
   public class DhcpInfo implements android.os.Parcelable {
     ctor public DhcpInfo();
     method public int describeContents();
diff --git a/api/test-removed.txt b/api/test-removed.txt
index f9fce40..2673a82 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -17,6 +17,37 @@
 
 }
 
+package android.app.usage {
+
+  public class DataUsagePolicy {
+    field public final int networkType;
+    field public final java.lang.String[] subscriberIds;
+    field public final long thresholdInBytes;
+    field public final int[] uids;
+  }
+
+  public static class DataUsagePolicy.Builder {
+    ctor public DataUsagePolicy.Builder();
+    method public android.app.usage.DataUsagePolicy.Builder addSubscriberId(java.lang.String);
+    method public android.app.usage.DataUsagePolicy.Builder addUid(int);
+    method public android.app.usage.DataUsagePolicy build();
+    method public android.app.usage.DataUsagePolicy.Builder setNetworkType(int);
+    method public android.app.usage.DataUsagePolicy.Builder setThreshold(long);
+  }
+
+  public class NetworkStatsManager {
+    method public void registerDataUsageCallback(android.app.usage.DataUsagePolicy, android.app.usage.NetworkStatsManager.DataUsageCallback, android.os.Handler);
+    method public void registerDataUsageCallback(android.app.usage.DataUsagePolicy, android.app.usage.NetworkStatsManager.UsageCallback, android.os.Handler);
+    method public void unregisterDataUsageCallback(android.app.usage.NetworkStatsManager.DataUsageCallback);
+  }
+
+  public static abstract class NetworkStatsManager.DataUsageCallback {
+    ctor public NetworkStatsManager.DataUsageCallback();
+    method public deprecated void onLimitReached();
+  }
+
+}
+
 package android.content {
 
   public abstract class Context {
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 8b277b2..ae78e218 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -949,7 +949,7 @@
                             mService.mConnectionId);
             if (connection != null) {
                 try {
-                    return connection.getMagnifiedRegion();
+                    return connection.getMagnificationRegion();
                 } catch (RemoteException re) {
                     Log.w(LOG_TAG, "Failed to obtain magnified region", re);
                     re.rethrowFromSystemServer();
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 3783fca..7a55079 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -75,7 +75,7 @@
 
     float getMagnificationCenterY();
 
-    Region getMagnifiedRegion();
+    Region getMagnificationRegion();
 
     boolean resetMagnification(boolean animate);
 
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 9b4c8bd..07d3b8a 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1879,14 +1879,9 @@
      *
      * @param isInMultiWindowMode True if the activity is in multi-window mode.
      */
-    @CallSuper
     public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
-        if (DEBUG_LIFECYCLE) Slog.v(TAG,
-                "onMultiWindowModeChanged " + this + ": " + isInMultiWindowMode);
-        mFragments.dispatchMultiWindowModeChanged(isInMultiWindowMode);
-        if (mWindow != null) {
-            mWindow.onMultiWindowModeChanged();
-        }
+        // Left deliberately empty. There should be no side effects if a direct
+        // subclass of Activity does not call super.
     }
 
     /**
@@ -1909,11 +1904,9 @@
      *
      * @param isInPictureInPictureMode True if the activity is in picture-in-picture mode.
      */
-    @CallSuper
     public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
-        if (DEBUG_LIFECYCLE) Slog.v(TAG,
-                "onPictureInPictureModeChanged " + this + ": " + isInPictureInPictureMode);
-        mFragments.dispatchPictureInPictureModeChanged(isInPictureInPictureMode);
+        // Left deliberately empty. There should be no side effects if a direct
+        // subclass of Activity does not call super.
     }
 
     /**
@@ -6875,6 +6868,23 @@
         }
     }
 
+    final void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode) {
+        if (DEBUG_LIFECYCLE) Slog.v(TAG,
+                "dispatchMultiWindowModeChanged " + this + ": " + isInMultiWindowMode);
+        mFragments.dispatchMultiWindowModeChanged(isInMultiWindowMode);
+        if (mWindow != null) {
+            mWindow.onMultiWindowModeChanged();
+        }
+        onMultiWindowModeChanged(isInMultiWindowMode);
+    }
+
+    final void dispatchPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
+        if (DEBUG_LIFECYCLE) Slog.v(TAG,
+                "dispatchPictureInPictureModeChanged " + this + ": " + isInPictureInPictureMode);
+        mFragments.dispatchPictureInPictureModeChanged(isInPictureInPictureMode);
+        onPictureInPictureModeChanged(isInPictureInPictureMode);
+    }
+
     /**
      * @hide
      */
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index ff8cf66..8a92b54 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -901,7 +901,7 @@
      */
     static public int getMaxRecentTasksStatic() {
         if (gMaxRecentTasks < 0) {
-            return gMaxRecentTasks = isLowRamDeviceStatic() ? 50 : 100;
+            return gMaxRecentTasks = isLowRamDeviceStatic() ? 36 : 48;
         }
         return gMaxRecentTasks;
     }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 6b62837..a4f404f 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2418,8 +2418,9 @@
             Bundle receiverExtras = data.readBundle();
             IBinder activityToken = data.readStrongBinder();
             boolean focused = data.readInt() == 1;
+            boolean newSessionId = data.readInt() == 1;
             boolean res = requestAssistContextExtras(requestType, receiver, receiverExtras,
-                    activityToken, focused);
+                    activityToken, focused, newSessionId);
             reply.writeNoException();
             reply.writeInt(res ? 1 : 0);
             return true;
@@ -6104,7 +6105,7 @@
 
     public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver,
             Bundle receiverExtras,
-            IBinder activityToken, boolean focused) throws RemoteException {
+            IBinder activityToken, boolean focused, boolean newSessionId) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
@@ -6113,6 +6114,7 @@
         data.writeBundle(receiverExtras);
         data.writeStrongBinder(activityToken);
         data.writeInt(focused ? 1 : 0);
+        data.writeInt(newSessionId ? 1 : 0);
         mRemote.transact(REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, reply, 0);
         reply.readException();
         boolean res = reply.readInt() != 0;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 9383394..061d924 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -206,7 +206,8 @@
     ActivityClientRecord mNewActivities = null;
     // Number of activities that are currently visible on-screen.
     int mNumVisibleActivities = 0;
-    WeakReference<AssistStructure> mLastAssistStructure;
+    ArrayList<WeakReference<AssistStructure>> mLastAssistStructures = new ArrayList<>();
+    private int mLastSessionId;
     final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();
     AppBindData mBoundApplication;
     Profiler mProfiler;
@@ -557,7 +558,7 @@
                 return;
             }
             try {
-                int bufferSize = SystemProperties.getInt("debug.traceview-buffer-size-in-mb", 8);
+                int bufferSize = SystemProperties.getInt("debug.traceview-buffer-size-mb", 8);
                 VMDebug.startMethodTracing(profileFile, profileFd.getFileDescriptor(),
                         bufferSize * 1024 * 1024, 0, samplingInterval != 0, samplingInterval);
                 profiling = true;
@@ -622,6 +623,7 @@
         IBinder activityToken;
         IBinder requestToken;
         int requestType;
+        int sessionId;
     }
 
     static final class ActivityConfigChangeData {
@@ -1183,11 +1185,12 @@
 
         @Override
         public void requestAssistContextExtras(IBinder activityToken, IBinder requestToken,
-                int requestType) {
+                int requestType, int sessionId) {
             RequestAssistContextExtras cmd = new RequestAssistContextExtras();
             cmd.activityToken = activityToken;
             cmd.requestToken = requestToken;
             cmd.requestType = requestType;
+            cmd.sessionId = sessionId;
             sendMessage(H.REQUEST_ASSIST_CONTEXT_EXTRAS, cmd);
         }
 
@@ -1804,6 +1807,7 @@
     }
 
     private Configuration mMainThreadConfig = new Configuration();
+
     Configuration applyConfigCompatMainThread(int displayDensity, Configuration config,
             CompatibilityInfo compat) {
         if (config == null) {
@@ -2785,10 +2789,15 @@
     }
 
     public void handleRequestAssistContextExtras(RequestAssistContextExtras cmd) {
-        if (mLastAssistStructure != null) {
-            AssistStructure structure = mLastAssistStructure.get();
-            if (structure != null) {
-                structure.clearSendChannel();
+        if (mLastSessionId != cmd.sessionId) {
+            // Clear the existing structures
+            mLastSessionId = cmd.sessionId;
+            for (int i = mLastAssistStructures.size() - 1; i >= 0; i--) {
+                AssistStructure structure = mLastAssistStructures.get(i).get();
+                if (structure != null) {
+                    structure.clearSendChannel();
+                }
+                mLastAssistStructures.remove(i);
             }
         }
         Bundle data = new Bundle();
@@ -2820,7 +2829,7 @@
         if (structure == null) {
             structure = new AssistStructure();
         }
-        mLastAssistStructure = new WeakReference<>(structure);
+        mLastAssistStructures.add(new WeakReference<>(structure));
         IActivityManager mgr = ActivityManagerNative.getDefault();
         try {
             mgr.reportAssistContextExtras(cmd.requestToken, data, structure, content, referrer);
@@ -2906,14 +2915,14 @@
     private void handleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode) {
         final ActivityClientRecord r = mActivities.get(token);
         if (r != null) {
-            r.activity.onMultiWindowModeChanged(isInMultiWindowMode);
+            r.activity.dispatchMultiWindowModeChanged(isInMultiWindowMode);
         }
     }
 
     private void handlePictureInPictureModeChanged(IBinder token, boolean isInPipMode) {
         final ActivityClientRecord r = mActivities.get(token);
         if (r != null) {
-            r.activity.onPictureInPictureModeChanged(isInPipMode);
+            r.activity.dispatchPictureInPictureModeChanged(isInPipMode);
         }
     }
 
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index ea86dd0..d6da3f4 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -621,7 +621,8 @@
             IBinder activityToken = data.readStrongBinder();
             IBinder requestToken = data.readStrongBinder();
             int requestType = data.readInt();
-            requestAssistContextExtras(activityToken, requestToken, requestType);
+            int sessionId = data.readInt();
+            requestAssistContextExtras(activityToken, requestToken, requestType, sessionId);
             reply.writeNoException();
             return true;
         }
@@ -1377,12 +1378,13 @@
 
     @Override
     public void requestAssistContextExtras(IBinder activityToken, IBinder requestToken,
-            int requestType) throws RemoteException {
+            int requestType, int sessionId) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeStrongBinder(activityToken);
         data.writeStrongBinder(requestToken);
         data.writeInt(requestType);
+        data.writeInt(sessionId);
         mRemote.transact(REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
         data.recycle();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 849fcec..2fcad0d 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -524,7 +524,7 @@
 
     public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver,
             Bundle receiverExtras,
-            IBinder activityToken, boolean focused) throws RemoteException;
+            IBinder activityToken, boolean focused, boolean newSessionId) throws RemoteException;
 
     public void reportAssistContextExtras(IBinder token, Bundle extras,
             AssistStructure structure, AssistContent content, Uri referrer) throws RemoteException;
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index a3b2638..559f69f 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -143,8 +143,8 @@
     void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException;
     void dumpDbInfo(FileDescriptor fd, String[] args) throws RemoteException;
     void unstableProviderDied(IBinder provider) throws RemoteException;
-    void requestAssistContextExtras(IBinder activityToken, IBinder requestToken, int requestType)
-            throws RemoteException;
+    void requestAssistContextExtras(IBinder activityToken, IBinder requestToken, int requestType,
+            int sessionId) throws RemoteException;
     void scheduleTranslucentConversionComplete(IBinder token, boolean timeout)
             throws RemoteException;
     void scheduleOnNewActivityOptions(IBinder token, ActivityOptions options)
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index e60712a..752dc1e 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -466,11 +466,7 @@
         final boolean isBundledApp = mApplicationInfo.isSystemApp()
                 && !mApplicationInfo.isUpdatedSystemApp();
 
-        // Apps are allowed to open any native library under /data
-        // TODO (dimitry):This is something which could be limited to apps own directory
-        // later on but currently there are number of apps relying on this.
-        // (see http://b/27588281 and http://b/26954419 for examples)
-        String libraryPermittedPath = "/data";
+        String libraryPermittedPath = mDataDir;
         if (isBundledApp) {
             // This is necessary to grant bundled apps access to
             // libraries located in subdirectories of /system/lib
diff --git a/core/java/android/app/usage/DataUsagePolicy.java b/core/java/android/app/usage/DataUsagePolicy.java
index 5a5dcbc..ee6b60c 100644
--- a/core/java/android/app/usage/DataUsagePolicy.java
+++ b/core/java/android/app/usage/DataUsagePolicy.java
@@ -29,6 +29,7 @@
 /**
  * Defines a policy for data usage callbacks, made through {@link DataUsagePolicy.Builder} and used
  * to be notified on data usage via {@link NetworkStatsManager#registerDataUsageCallback}.
+ * @removed
  */
 public class DataUsagePolicy {
 
diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java
index 9963eab..226aa8f 100644
--- a/core/java/android/app/usage/NetworkStats.java
+++ b/core/java/android/app/usage/NetworkStats.java
@@ -193,14 +193,9 @@
         public static final int ROAMING_YES = 0x2;
 
         /**
-         * Special TAG value matching any tag.
-         */
-        public static final int TAG_ANY = android.net.NetworkStats.TAG_ALL;
-
-        /**
          * Special TAG value for total data across all tags
          */
-        public static final int TAG_ALL = android.net.NetworkStats.TAG_NONE;
+        public static final int TAG_NONE = android.net.NetworkStats.TAG_NONE;
 
         private int mUid;
         private int mTag;
@@ -232,8 +227,7 @@
 
         private static int convertTag(int tag) {
             switch (tag) {
-                case android.net.NetworkStats.TAG_ALL: return TAG_ANY;
-                case android.net.NetworkStats.TAG_NONE: return TAG_ALL;
+                case android.net.NetworkStats.TAG_NONE: return TAG_NONE;
             }
             return tag;
         }
@@ -417,9 +411,9 @@
      * Collects summary results and sets summary enumeration mode.
      * @throws RemoteException
      */
-    void startSummaryEnumeration(boolean includeTags) throws RemoteException {
+    void startSummaryEnumeration() throws RemoteException {
         mSummary = mSession.getSummaryForAllUid(mTemplate, mStartTimeStamp, mEndTimeStamp,
-                includeTags);
+                false /* includeTags */);
         mEnumerationIndex = 0;
     }
 
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 2e3aca4..4a28117 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -106,7 +106,7 @@
      * device. Result is a single Bucket aggregated over time, state, uid, tag and roaming. This
      * means the bucket's start and end timestamp are going to be the same as the 'startTime' and
      * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid
-     * {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_ALL}
+     * {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}
      * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}.
      *
      * @param networkType As defined in {@link ConnectivityManager}, e.g.
@@ -122,8 +122,11 @@
      */
     public Bucket querySummaryForDevice(int networkType, String subscriberId,
             long startTime, long endTime) throws SecurityException, RemoteException {
-        NetworkTemplate template = createTemplate(networkType, subscriberId);
-        if (template == null) {
+        NetworkTemplate template;
+        try {
+            template = createTemplate(networkType, subscriberId);
+        } catch (IllegalArgumentException e) {
+            if (DBG) Log.e(TAG, "Cannot create template", e);
             return null;
         }
 
@@ -136,21 +139,10 @@
     }
 
     /**
-     * Query network usage statistics summaries aggregated across tags.
-     *
-     * #see querySummaryForUser(int, String, long, long, boolean)
-     */
-    public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime,
-            long endTime) throws SecurityException, RemoteException {
-        return querySummaryForUser(networkType, subscriberId, startTime, endTime,
-            false /* includeTags */);
-    }
-
-    /**
      * Query network usage statistics summaries. Result is summarised data usage for all uids
      * belonging to calling user. Result is a single Bucket aggregated over time, state and uid.
      * This means the bucket's start and end timestamp are going to be the same as the 'startTime'
-     * and 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid
+     * and 'endTime' parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid
      * {@link NetworkStats.Bucket#UID_ALL}.
      *
      * @param networkType As defined in {@link ConnectivityManager}, e.g.
@@ -161,42 +153,33 @@
      *            {@link java.lang.System#currentTimeMillis}.
      * @param endTime End of period. Defined in terms of "Unix time", see
      *            {@link java.lang.System#currentTimeMillis}.
-     * @param includeTags whether to include network tags. If {@code true}, tags will be returned
-     *            and history retention may be shorter.
      * @return Bucket object or null if permissions are insufficient or error happened during
      *         statistics collection.
      */
     public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime,
-            long endTime, boolean includeTags) throws SecurityException, RemoteException {
-        NetworkTemplate template = createTemplate(networkType, subscriberId);
-        if (template == null) {
+            long endTime) throws SecurityException, RemoteException {
+        NetworkTemplate template;
+        try {
+            template = createTemplate(networkType, subscriberId);
+        } catch (IllegalArgumentException e) {
+            if (DBG) Log.e(TAG, "Cannot create template", e);
             return null;
         }
 
         NetworkStats stats;
         stats = new NetworkStats(mContext, template, startTime, endTime);
-        stats.startSummaryEnumeration(includeTags);
+        stats.startSummaryEnumeration();
 
         stats.close();
         return stats.getSummaryAggregate();
     }
 
     /**
-     * Query network usage statistics summaries aggregated across tags.
-     *
-     * #see querySummary(int, String, long, long, boolean)
-     */
-    public NetworkStats querySummary(int networkType, String subscriberId, long startTime,
-            long endTime) throws SecurityException, RemoteException {
-        return querySummary(networkType, subscriberId, startTime, endTime, false /* includeTags */);
-    }
-
-    /**
      * Query network usage statistics summaries. Result filtered to include only uids belonging to
      * calling user. Result is aggregated over time, hence all buckets will have the same start and
-     * end timestamps. Not aggregated over state or uid or tag. This means buckets' start and end
-     * timestamps are going to be the same as the 'startTime' and 'endTime' parameters. State,
-     * uid and tag are going to vary.
+     * end timestamps. Not aggregated over state or uid. This means buckets' start and end
+     * timestamps are going to be the same as the 'startTime' and 'endTime' parameters.
+     * State and uid are going to vary, and tag is going to be the same.
      *
      * @param networkType As defined in {@link ConnectivityManager}, e.g.
      *            {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
@@ -206,21 +189,22 @@
      *            {@link java.lang.System#currentTimeMillis}.
      * @param endTime End of period. Defined in terms of "Unix time", see
      *            {@link java.lang.System#currentTimeMillis}.
-     * @param includeTags whether to include network tags. If {@code true}, tags will be returned
-     *            and history retention may be shorter.
      * @return Statistics object or null if permissions are insufficient or error happened during
      *         statistics collection.
      */
     public NetworkStats querySummary(int networkType, String subscriberId, long startTime,
-            long endTime, boolean includeTags) throws SecurityException, RemoteException {
-        NetworkTemplate template = createTemplate(networkType, subscriberId);
-        if (template == null) {
+            long endTime) throws SecurityException, RemoteException {
+        NetworkTemplate template;
+        try {
+            template = createTemplate(networkType, subscriberId);
+        } catch (IllegalArgumentException e) {
+            if (DBG) Log.e(TAG, "Cannot create template", e);
             return null;
         }
 
         NetworkStats result;
         result = new NetworkStats(mContext, template, startTime, endTime);
-        result.startSummaryEnumeration(includeTags);
+        result.startSummaryEnumeration();
 
         return result;
     }
@@ -233,7 +217,7 @@
     public NetworkStats queryDetailsForUid(int networkType, String subscriberId,
             long startTime, long endTime, int uid) throws SecurityException, RemoteException {
         return queryDetailsForUidTag(networkType, subscriberId, startTime, endTime, uid,
-            NetworkStats.Bucket.TAG_ALL);
+            NetworkStats.Bucket.TAG_NONE);
     }
 
     /**
@@ -255,22 +239,28 @@
      * @param endTime End of period. Defined in terms of "Unix time", see
      *            {@link java.lang.System#currentTimeMillis}.
      * @param uid UID of app
-     * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_ANY} for any tags, use
-     *            {@link NetworkStats.Bucket#TAG_ALL} to aggregate over tags.
+     * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for no tags.
      * @return Statistics object or null if permissions are insufficient or error happened during
      *         statistics collection.
      */
     public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId,
-            long startTime, long endTime, int uid, int tag) throws SecurityException,
-            RemoteException {
-        NetworkTemplate template = createTemplate(networkType, subscriberId);
-        if (template == null) {
+            long startTime, long endTime, int uid, int tag) {
+        NetworkTemplate template;
+        try {
+            template = createTemplate(networkType, subscriberId);
+        } catch (IllegalArgumentException e) {
+            if (DBG) Log.e(TAG, "Cannot create template", e);
             return null;
         }
 
         NetworkStats result;
-        result = new NetworkStats(mContext, template, startTime, endTime);
-        result.startHistoryEnumeration(uid, tag);
+        try {
+            result = new NetworkStats(mContext, template, startTime, endTime);
+            result.startHistoryEnumeration(uid, tag);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag, e);
+            return null;
+        }
 
         return result;
     }
@@ -280,7 +270,7 @@
      * calling user. Result is aggregated over state but not aggregated over time or uid. This means
      * buckets' start and end timestamps are going to be between 'startTime' and 'endTime'
      * parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid will vary,
-     * tag {@link NetworkStats.Bucket#TAG_ALL} and roaming is going to be
+     * tag {@link NetworkStats.Bucket#TAG_NONE} and roaming is going to be
      * {@link NetworkStats.Bucket#ROAMING_ALL}.
      * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
      * interpolate across partial buckets. Since bucket length is in the order of hours, this
@@ -299,44 +289,59 @@
      */
     public NetworkStats queryDetails(int networkType, String subscriberId, long startTime,
             long endTime) throws SecurityException, RemoteException {
-        NetworkTemplate template = createTemplate(networkType, subscriberId);
-        if (template == null) {
+        NetworkTemplate template;
+        try {
+            template = createTemplate(networkType, subscriberId);
+        } catch (IllegalArgumentException e) {
+            if (DBG) Log.e(TAG, "Cannot create template", e);
             return null;
         }
+
         NetworkStats result;
         result = new NetworkStats(mContext, template, startTime, endTime);
         result.startUserUidEnumeration();
         return result;
     }
 
+    /** @removed */
+    public void registerDataUsageCallback(DataUsagePolicy policy, DataUsageCallback callback,
+                @Nullable Handler handler) {}
+
+    /** @removed */
+    public void registerDataUsageCallback(DataUsagePolicy policy, UsageCallback callback,
+                @Nullable Handler handler) {}
+
+    /** @removed */
+    public void unregisterDataUsageCallback(DataUsageCallback callback) {}
+
     /**
-     * Registers to receive notifications about data usage on specified networks and uids.
-     * The callbacks will continue to be called as long as the process is live or
-     * {@link #unregisterDataUsageCallback} is called.
+     * Registers to receive notifications about data usage on specified networks.
      *
-     * @param policy {@link DataUsagePolicy} describing this request.
-     * @param callback The {@link DataUsageCallback} that the system will call when data usage
-     *            has exceeded the specified threshold.
+     * #see registerUsageCallback(int, String[], long, UsageCallback, Handler)
      */
-    public void registerDataUsageCallback(DataUsagePolicy policy, DataUsageCallback callback) {
-        registerDataUsageCallback(policy, callback, null /* handler */);
+    public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes,
+            UsageCallback callback) {
+        registerUsageCallback(networkType, subscriberId, thresholdBytes, null /* handler */);
     }
 
     /**
-     * Registers to receive notifications about data usage on specified networks and uids.
-     * The callbacks will continue to be called as long as the process is live or
-     * {@link #unregisterDataUsageCallback} is called.
+     * Registers to receive notifications about data usage on specified networks.
      *
-     * @param policy {@link DataUsagePolicy} describing this request.
-     * @param callback The {@link DataUsageCallback} that the system will call when data usage
+     * <p>The callbacks will continue to be called as long as the process is live or
+     * {@link #unregisterUsageCallback} is called.
+     *
+     * @param networkType Type of network to monitor. Either
+                  {@link ConnectivityManager#TYPE_MOBILE} or {@link ConnectivityManager#TYPE_WIFI}.
+     * @param subscriberId If applicable, the subscriber id of the network interface.
+     * @param thresholdBytes Threshold in bytes to be notified on.
+     * @param callback The {@link UsageCallback} that the system will call when data usage
      *            has exceeded the specified threshold.
      * @param handler to dispatch callback events through, otherwise if {@code null} it uses
      *            the calling thread.
      */
-    public void registerDataUsageCallback(DataUsagePolicy policy, DataUsageCallback callback,
-                @Nullable Handler handler) {
-        checkNotNull(policy, "DataUsagePolicy cannot be null");
-        checkNotNull(callback, "DataUsageCallback cannot be null");
+    public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes,
+            UsageCallback callback, @Nullable Handler handler) {
+        checkNotNull(callback, "UsageCallback cannot be null");
 
         final Looper looper;
         if (handler == null) {
@@ -345,62 +350,72 @@
             looper = handler.getLooper();
         }
 
-        if (DBG) Log.d(TAG, "registerDataUsageCallback called with " + policy);
-
-        NetworkTemplate[] templates;
-        if (policy.subscriberIds == null || policy.subscriberIds.length == 0) {
-            templates = new NetworkTemplate[1];
-            templates[0] = createTemplate(policy.networkType, null /* subscriberId */);
-        } else {
-            templates = new NetworkTemplate[policy.subscriberIds.length];
-            for (int i = 0; i < policy.subscriberIds.length; i++) {
-                templates[i] = createTemplate(policy.networkType, policy.subscriberIds[i]);
-            }
+        if (DBG) {
+            Log.d(TAG, "registerUsageCallback called with: {"
+                + " networkType=" + networkType
+                + " subscriberId=" + subscriberId
+                + " thresholdBytes=" + thresholdBytes
+                + " }");
         }
+
+        NetworkTemplate template = createTemplate(networkType, subscriberId);
         DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET,
-                templates, policy.uids, policy.thresholdInBytes);
+                template, thresholdBytes);
         try {
-            CallbackHandler callbackHandler = new CallbackHandler(looper, callback);
-            callback.request = mService.registerDataUsageCallback(
+            CallbackHandler callbackHandler = new CallbackHandler(looper, networkType,
+                    subscriberId, callback);
+            callback.request = mService.registerUsageCallback(
                     mContext.getOpPackageName(), request, new Messenger(callbackHandler),
                     new Binder());
-            if (DBG) Log.d(TAG, "registerDataUsageCallback returned " + callback.request);
+            if (DBG) Log.d(TAG, "registerUsageCallback returned " + callback.request);
 
             if (callback.request == null) {
                 Log.e(TAG, "Request from callback is null; should not happen");
             }
         } catch (RemoteException e) {
             if (DBG) Log.d(TAG, "Remote exception when registering callback");
+            throw e.rethrowFromSystemServer();
         }
     }
 
     /**
      * Unregisters callbacks on data usage.
      *
-     * @param callback The {@link DataUsageCallback} used when registering.
+     * @param callback The {@link UsageCallback} used when registering.
      */
-    public void unregisterDataUsageCallback(DataUsageCallback callback) {
+    public void unregisterUsageCallback(UsageCallback callback) {
         if (callback == null || callback.request == null
                 || callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) {
-            throw new IllegalArgumentException("Invalid DataUsageCallback");
+            throw new IllegalArgumentException("Invalid UsageCallback");
         }
         try {
-            mService.unregisterDataUsageRequest(callback.request);
+            mService.unregisterUsageRequest(callback.request);
         } catch (RemoteException e) {
             if (DBG) Log.d(TAG, "Remote exception when unregistering callback");
+            throw e.rethrowFromSystemServer();
         }
     }
 
-    /**
-     * Base class for data usage callbacks. Should be extended by applications wanting
-     * notifications.
-     */
-    public static class DataUsageCallback {
-        /**
-         * Called when data usage has reached the given policy threshold.
-         */
+    /** @removed */
+    public static abstract class DataUsageCallback {
+        /** @removed */
+        @Deprecated
         public void onLimitReached() {}
+    }
 
+    /**
+     * Base class for usage callbacks. Should be extended by applications wanting notifications.
+     */
+    public static abstract class UsageCallback {
+
+        /**
+         * Called when data usage has reached the given threshold.
+         */
+        public abstract void onThresholdReached(int networkType, String subscriberId);
+
+        /**
+         * @hide used for internal bookkeeping
+         */
         private DataUsageRequest request;
     }
 
@@ -414,18 +429,24 @@
                 template = NetworkTemplate.buildTemplateWifiWildcard();
                 } break;
             default: {
-                Log.w(TAG, "Cannot create template for network type " + networkType
-                        + ", subscriberId '" + NetworkIdentity.scrubSubscriberId(subscriberId) +
-                        "'.");
+                throw new IllegalArgumentException("Cannot create template for network type "
+                        + networkType + ", subscriberId '"
+                        + NetworkIdentity.scrubSubscriberId(subscriberId) + "'.");
             }
         }
         return template;
     }
 
     private static class CallbackHandler extends Handler {
-        private DataUsageCallback mCallback;
-        CallbackHandler(Looper looper, DataUsageCallback callback) {
+        private final int mNetworkType;
+        private final String mSubscriberId;
+        private UsageCallback mCallback;
+
+        CallbackHandler(Looper looper, int networkType, String subscriberId,
+                UsageCallback callback) {
             super(looper);
+            mNetworkType = networkType;
+            mSubscriberId = subscriberId;
             mCallback = callback;
         }
 
@@ -437,7 +458,7 @@
             switch (message.what) {
                 case CALLBACK_LIMIT_REACHED: {
                     if (mCallback != null) {
-                        mCallback.onLimitReached();
+                        mCallback.onThresholdReached(mNetworkType, mSubscriberId);
                     } else {
                         Log.e(TAG, "limit reached with released callback for " + request);
                     }
diff --git a/core/java/android/net/DataUsageRequest.java b/core/java/android/net/DataUsageRequest.java
index 8526584..ac9a5a3 100644
--- a/core/java/android/net/DataUsageRequest.java
+++ b/core/java/android/net/DataUsageRequest.java
@@ -20,7 +20,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.util.Arrays;
 import java.util.Objects;
 
 /**
@@ -28,56 +27,33 @@
  * {@link android.app.usage.NetworkStatsManager#registerDataUsageCallback}.
  * If no {@code uid}s are set, callbacks are restricted to device-owners,
  * carrier-privileged apps, or system apps.
+ *
+ * @hide
  */
 public final class DataUsageRequest implements Parcelable {
 
-    /**
-     * @hide
-     */
     public static final String PARCELABLE_KEY = "DataUsageRequest";
-
-    /**
-     * @hide
-     */
     public static final int REQUEST_ID_UNSET = 0;
 
     /**
      * Identifies the request.  {@link DataUsageRequest}s should only be constructed by
      * the Framework and it is used internally to identify the request.
-     * @hide
      */
     public final int requestId;
 
     /**
-     * Set of {@link NetworkTemplate}s describing the networks to monitor.
-     * @hide
+     * {@link NetworkTemplate} describing the network to monitor.
      */
-    public final NetworkTemplate[] templates;
-
-    /**
-     * Set of UIDs of which to monitor data usage.
-     *
-     * <p>If not {@code null}, the caller will be notified when any of the uids exceed
-     * the given threshold. If {@code null} all uids for which the calling process has access
-     * to stats will be monitored.
-     * @hide
-     */
-    public final int[] uids;
+    public final NetworkTemplate template;
 
     /**
      * Threshold in bytes to be notified on.
-     * @hide
      */
     public final long thresholdInBytes;
 
-    /**
-     * @hide
-     */
-    public DataUsageRequest(int requestId, NetworkTemplate[] templates, int[] uids,
-                long thresholdInBytes) {
+    public DataUsageRequest(int requestId, NetworkTemplate template, long thresholdInBytes) {
         this.requestId = requestId;
-        this.templates = templates;
-        this.uids = uids;
+        this.template = template;
         this.thresholdInBytes = thresholdInBytes;
     }
 
@@ -89,8 +65,7 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(requestId);
-        dest.writeTypedArray(templates, flags);
-        dest.writeIntArray(uids);
+        dest.writeParcelable(template, flags);
         dest.writeLong(thresholdInBytes);
     }
 
@@ -99,11 +74,10 @@
                 @Override
                 public DataUsageRequest createFromParcel(Parcel in) {
                     int requestId = in.readInt();
-                    NetworkTemplate[] templates = in.createTypedArray(NetworkTemplate.CREATOR);
-                    int[] uids = in.createIntArray();
+                    NetworkTemplate template = in.readParcelable(null);
                     long thresholdInBytes = in.readLong();
-                    DataUsageRequest result = new DataUsageRequest(requestId,
-                            templates, uids, thresholdInBytes);
+                    DataUsageRequest result = new DataUsageRequest(requestId, template,
+                            thresholdInBytes);
                     return result;
                 }
 
@@ -116,8 +90,7 @@
     @Override
     public String toString() {
         return "DataUsageRequest [ requestId=" + requestId
-                + ", networkTemplates=" + Arrays.toString(templates)
-                + ", uids=" + Arrays.toString(uids)
+                + ", networkTemplate=" + template
                 + ", thresholdInBytes=" + thresholdInBytes + " ]";
     }
 
@@ -126,23 +99,13 @@
         if (obj instanceof DataUsageRequest == false) return false;
         DataUsageRequest that = (DataUsageRequest) obj;
         return that.requestId == this.requestId
-                && Arrays.deepEquals(that.templates, this.templates)
-                && Arrays.equals(that.uids, this.uids)
+                && Objects.equals(that.template, this.template)
                 && that.thresholdInBytes == this.thresholdInBytes;
     }
 
     @Override
     public int hashCode() {
-        // Start with a non-zero constant.
-        int result = 17;
-
-        // Include a hash for each field.
-        result = 31 * result + requestId;
-        result = 31 * result + Arrays.deepHashCode(templates);
-        result = 31 * result + Arrays.hashCode(uids);
-        result = 31 * result + (int) (thresholdInBytes ^ (thresholdInBytes >>> 32));
-
-        return result;
+        return Objects.hash(requestId, template, thresholdInBytes);
    }
 
 }
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 2eea940..e693009 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -61,10 +61,10 @@
     void advisePersistThreshold(long thresholdBytes);
 
     /** Registers a callback on data usage. */
-    DataUsageRequest registerDataUsageCallback(String callingPackage,
+    DataUsageRequest registerUsageCallback(String callingPackage,
             in DataUsageRequest request, in Messenger messenger, in IBinder binder);
 
     /** Unregisters a callback on data usage. */
-    void unregisterDataUsageRequest(in DataUsageRequest request);
+    void unregisterUsageRequest(in DataUsageRequest request);
 
 }
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index b9bcd1c..3915b02 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -1233,8 +1233,8 @@
             }
 
             @Override
-            public void addUserKeyAuth(int userId, int serialNumber,
-                    byte[] token, byte[] secret) throws RemoteException {
+            public void changeUserKey(int userId, int serialNumber,
+                    byte[] token, byte[] oldSecret, byte[] newSecret) throws RemoteException {
                 Parcel _data = Parcel.obtain();
                 Parcel _reply = Parcel.obtain();
                 try {
@@ -1242,23 +1242,9 @@
                     _data.writeInt(userId);
                     _data.writeInt(serialNumber);
                     _data.writeByteArray(token);
-                    _data.writeByteArray(secret);
-                    mRemote.transact(Stub.TRANSACTION_addUserKeyAuth, _data, _reply, 0);
-                    _reply.readException();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-            }
-
-            @Override
-            public void fixateNewestUserKeyAuth(int userId) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeInt(userId);
-                    mRemote.transact(Stub.TRANSACTION_fixateNewestUserKeyAuth, _data, _reply, 0);
+                    _data.writeByteArray(oldSecret);
+                    _data.writeByteArray(newSecret);
+                    mRemote.transact(Stub.TRANSACTION_changeUserKey, _data, _reply, 0);
                     _reply.readException();
                 } finally {
                     _reply.recycle();
@@ -1503,9 +1489,7 @@
 
         static final int TRANSACTION_mountAppFuse = IBinder.FIRST_CALL_TRANSACTION + 69;
 
-        static final int TRANSACTION_addUserKeyAuth = IBinder.FIRST_CALL_TRANSACTION + 70;
-
-        static final int TRANSACTION_fixateNewestUserKeyAuth = IBinder.FIRST_CALL_TRANSACTION + 71;
+        static final int TRANSACTION_changeUserKey = IBinder.FIRST_CALL_TRANSACTION + 70;
 
         /**
          * Cast an IBinder object into an IMountService interface, generating a
@@ -2085,20 +2069,14 @@
                     reply.writeNoException();
                     return true;
                 }
-                case TRANSACTION_addUserKeyAuth: {
+                case TRANSACTION_changeUserKey: {
                     data.enforceInterface(DESCRIPTOR);
                     int userId = data.readInt();
                     int serialNumber = data.readInt();
                     byte[] token = data.createByteArray();
-                    byte[] secret = data.createByteArray();
-                    addUserKeyAuth(userId, serialNumber, token, secret);
-                    reply.writeNoException();
-                    return true;
-                }
-                case TRANSACTION_fixateNewestUserKeyAuth: {
-                    data.enforceInterface(DESCRIPTOR);
-                    int userId = data.readInt();
-                    fixateNewestUserKeyAuth(userId);
+                    byte[] oldSecret = data.createByteArray();
+                    byte[] newSecret = data.createByteArray();
+                    changeUserKey(userId, serialNumber, token, oldSecret, newSecret);
                     reply.writeNoException();
                     return true;
                 }
@@ -2474,9 +2452,8 @@
     public void createUserKey(int userId, int serialNumber, boolean ephemeral)
             throws RemoteException;
     public void destroyUserKey(int userId) throws RemoteException;
-    public void addUserKeyAuth(int userId, int serialNumber,
-            byte[] token, byte[] secret) throws RemoteException;
-    public void fixateNewestUserKeyAuth(int userId) throws RemoteException;
+    public void changeUserKey(int userId, int serialNumber,
+            byte[] token, byte[] oldSecret, byte[] newSecret) throws RemoteException;
 
     public void unlockUserKey(int userId, int serialNumber,
             byte[] token, byte[] secret) throws RemoteException;
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 239f2d0..bb131a0 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -754,15 +754,21 @@
                                 && ellipsize != TextUtils.TruncateAt.MARQUEE));
             if (remainingLineCount > 0 && remainingLineCount < breakCount &&
                     ellipsisMayBeApplied) {
-                // Treat the last line and overflowed lines as a single line.
-                breaks[remainingLineCount - 1] = breaks[breakCount - 1];
                 // Calculate width and flag.
                 float width = 0;
                 int flag = 0;
                 for (int i = remainingLineCount - 1; i < breakCount; i++) {
-                    width += lineWidths[i];
+                    if (i == breakCount - 1) {
+                        width += lineWidths[i];
+                    } else {
+                        for (int j = (i == 0 ? 0 : breaks[i - 1]); j < breaks[i]; j++) {
+                            width += widths[j];
+                        }
+                    }
                     flag |= flags[i] & TAB_MASK;
                 }
+                // Treat the last line and overflowed lines as a single line.
+                breaks[remainingLineCount - 1] = breaks[breakCount - 1];
                 lineWidths[remainingLineCount - 1] = width;
                 flags[remainingLineCount - 1] = flag;
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8cabf42..130b440 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -125,6 +125,7 @@
     private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
     private static final boolean DEBUG_FPS = false;
     private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV;
+    private static final boolean DEBUG_KEEP_SCREEN_ON = false || LOCAL_LOGV;
 
     /**
      * Set to false if we do not want to use the multi threaded renderer. Note that by disabling
@@ -563,9 +564,10 @@
                 attrs = mWindowAttributes;
                 setTag();
 
-                if ((mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
+                if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
+                        & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
                         && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) {
-                    Slog.d(mTag, "setView: FLAG_KEEP_SCREEN_ON changed from true to false!!!");
+                    Slog.d(mTag, "setView: FLAG_KEEP_SCREEN_ON changed from true to false!");
                 }
                 // Keep track of the actual window flags supplied by the client.
                 mClientWindowLayoutFlags = attrs.flags;
@@ -894,9 +896,11 @@
             final int oldInsetBottom = mWindowAttributes.surfaceInsets.bottom;
             final int oldSoftInputMode = mWindowAttributes.softInputMode;
             final boolean oldHasManualSurfaceInsets = mWindowAttributes.hasManualSurfaceInsets;
-            if ((mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
+
+            if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
+                    & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
                     && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) {
-                Slog.d(mTag, "setLayoutParams: FLAG_KEEP_SCREEN_ON from true to false!!!");
+                Slog.d(mTag, "setLayoutParams: FLAG_KEEP_SCREEN_ON from true to false!");
             }
 
             // Keep track of the actual window flags supplied by the client.
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e68d8a6..c2ff4ef 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2420,7 +2420,10 @@
         android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to delete packages.
-    <p>Not for use by third-party applications. -->
+         <p>Not for use by third-party applications.
+         <p>Starting in {@link android.os.Build.VERSION_CODES#N}, user confirmation is requested
+         when the application deleting the package is not the same application that installed the
+         package. -->
     <permission android:name="android.permission.DELETE_PACKAGES"
         android:protectionLevel="signature|privileged" />
 
diff --git a/core/res/res/layout/notification_material_action_list.xml b/core/res/res/layout/notification_material_action_list.xml
index 547d3ca..4670dca 100644
--- a/core/res/res/layout/notification_material_action_list.xml
+++ b/core/res/res/layout/notification_material_action_list.xml
@@ -21,7 +21,7 @@
     <com.android.internal.widget.NotificationActionListLayout
             android:id="@+id/actions"
             android:layout_width="match_parent"
-            android:layout_height="56dp"
+            android:layout_height="@dimen/notification_action_list_height"
             android:paddingEnd="4dp"
             android:orientation="horizontal"
             android:gravity="center_vertical"
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 8ce922e..3ba6ce1 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -152,6 +152,9 @@
     <!-- The margin on the end of the content view with a picture.-->
     <dimen name="notification_content_picture_margin">56dp</dimen>
 
+    <!-- The height of the notification action list -->
+    <dimen name="notification_action_list_height">56dp</dimen>
+
     <!-- height of the content margin to accomodate for the header -->
     <dimen name="notification_content_margin_top">37.5dp</dimen>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c64a934..29818df 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2584,6 +2584,8 @@
   <java-symbol type="dimen" name="input_extract_action_button_width" />
   <java-symbol type="dimen" name="input_extract_action_button_height" />
 
+  <java-symbol type="dimen" name="notification_action_list_height" />
+
   <!-- TV Remote Service package -->
   <java-symbol type="string" name="config_tvRemoteServicePackage" />
 
diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml
index f0986aa..d13a635 100644
--- a/docs/html/_redirects.yaml
+++ b/docs/html/_redirects.yaml
@@ -988,7 +988,7 @@
 - from: /tools/help/theme-editor.html
   to: /studio/write/theme-editor.html
 - from: /tools/help/traceview.html
-  to: /studio/profile/traceview-commandline.html
+  to: /studio/profile/traceview.html
 - from: /tools/help/translations-editor.html
   to: /studio/write/translations-editor.html
 - from: /tools/help/uiautomator/Configurator.html
@@ -1113,6 +1113,26 @@
   to: /studio/test/index.html
 - from: /tools/testing/testing-tools.html
   to: /studio/test/index.html
+- from: /tools/performance/importing-legacy-apps.html
+  to: /studio/projects/index.html
+- from: /tools/performance/comparison.html
+  to: /studio/profile/android-monitor.html
+- from: /tools/performance/memory-monitor/index.html
+  to: /studio/profile/am-memory.html
+- from: /tools/devices/index.html
+  to: /studio/run/managing-avds.html
+- from: /tools/extras/index.html
+  to: /studio/intro/update.html
+- from: /tools/workflow.html
+  to: /studio/guide/workflow.html
+- from: /installing/studio-androidview.html
+  to: /studio/projects/index.html
+- from: /installing/studio-tips.html
+  to: /studio/intro/index.html
+- from: /tools/help/ddms.html
+  to: /studio/profile/ddms.html
+- from: /tools/revisions/index.html
+  to: /studio/releases/index.html
 
 
 # Just incase something was missed, go to intro page
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index 62685c9..359ebad 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -31,7 +31,7 @@
 namespace android {
 
 AssetStream::AssetStream(SkStream* stream)
-    : mStream(stream) {
+    : mStream(stream), mPosition(0) {
 }
 
 AssetStream::~AssetStream() {
@@ -48,7 +48,7 @@
 
     // Read bytes.
     size_t size = mStream->read((void*)data, length);
-    mPosition += size;
+    mPosition = offset + size;
 
     return size == length ? piex::Error::kOk : piex::Error::kFail;
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 9aaddaa..6d6a4b5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -646,7 +646,7 @@
             if (DEBUG) Log.i(TAG, "Rebuilding...");
             for (int i=0; i<apps.size(); i++) {
                 AppEntry entry = apps.get(i);
-                if (filter == null || filter.filterApp(entry)) {
+                if (entry != null && (filter == null || filter.filterApp(entry))) {
                     synchronized (mEntriesMap) {
                         if (DEBUG_LOCKING) Log.v(TAG, "rebuild acquired lock");
                         if (comparator != null) {
diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher.xml b/packages/SystemUI/res/layout/keyguard_user_switcher.xml
index 22834e1..983ba6d 100644
--- a/packages/SystemUI/res/layout/keyguard_user_switcher.xml
+++ b/packages/SystemUI/res/layout/keyguard_user_switcher.xml
@@ -19,14 +19,5 @@
         android:visibility="gone"
         android:layout_height="match_parent"
         android:layout_width="match_parent">
-    <com.android.keyguard.AlphaOptimizedLinearLayout
-            android:id="@+id/keyguard_user_switcher_inner"
-            android:orientation="vertical"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            android:layout_marginTop="@dimen/status_bar_header_height_keyguard"
-            android:layout_gravity="end"
-            android:gravity="end"
-            android:paddingTop="4dp">
-    </com.android.keyguard.AlphaOptimizedLinearLayout>
+    <!-- KeyguardUserSwitcher loads keyguard_user_switcher_inner.xml here -->
 </view>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher_inner.xml b/packages/SystemUI/res/layout/keyguard_user_switcher_inner.xml
new file mode 100644
index 0000000..4c1042e
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyguard_user_switcher_inner.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+<com.android.keyguard.AlphaOptimizedLinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/keyguard_user_switcher_inner"
+    android:orientation="vertical"
+    android:layout_height="wrap_content"
+    android:layout_width="wrap_content"
+    android:layout_marginTop="@dimen/status_bar_header_height_keyguard"
+    android:layout_gravity="end"
+    android:gravity="end"
+    android:paddingTop="4dp">
+</com.android.keyguard.AlphaOptimizedLinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
index 5fde4f6..5cbe635 100644
--- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
@@ -16,6 +16,7 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:layout_height="48dp"
+    android:layout_width="match_parent"
     android:paddingLeft="16dp"
     android:paddingRight="16dp"
     style="@style/BrightnessDialogContainer">
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 527d577..dc5957d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -92,8 +92,8 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardHostView.OnDismissAction;
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
@@ -2193,7 +2193,7 @@
             } else {
                 boolean wasGone = entry.row.getVisibility() == View.GONE;
                 entry.row.setVisibility(View.VISIBLE);
-                if (!childNotification) {
+                if (!childNotification && !entry.row.isRemoved()) {
                     if (wasGone) {
                         // notify the scroller of a child addition
                         mStackScroller.generateAddAnimation(entry.row,
@@ -2213,7 +2213,7 @@
                 mStackScroller.getChildCount() - 3);
     }
 
-    private boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
+    public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
         return mShowLockscreenNotifications && !mNotificationData.isAmbient(sbn.getKey());
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 34c9c0d..5a8d4b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -374,10 +374,42 @@
         mContentHeight = Math.max(Math.min(contentHeight, getHeight()), getMinHeight());;
         mUnrestrictedContentHeight = Math.max(contentHeight, getMinHeight());
         selectLayout(mAnimate /* animate */, false /* force */);
+
+        int minHeightHint = getMinContentHeightHint();
+
+        NotificationViewWrapper wrapper = getVisibleWrapper(mVisibleType);
+        if (wrapper != null) {
+            wrapper.setContentHeight(mContentHeight, minHeightHint);
+        }
+
+        wrapper = getVisibleWrapper(mTransformationStartVisibleType);
+        if (wrapper != null) {
+            wrapper.setContentHeight(mContentHeight, minHeightHint);
+        }
+
         updateClipping();
         invalidateOutline();
     }
 
+    /**
+     * @return the minimum apparent height that the wrapper should allow for the purpose
+     *         of aligning elements at the bottom edge. If this is larger than the content
+     *         height, the notification is clipped instead of being further shrunk.
+     */
+    private int getMinContentHeightHint() {
+        if (mIsChildInGroup && (mVisibleType == VISIBLE_TYPE_SINGLELINE
+                || mTransformationStartVisibleType == VISIBLE_TYPE_SINGLELINE)) {
+            return mContext.getResources().getDimensionPixelSize(
+                        com.android.internal.R.dimen.notification_action_list_height);
+        }
+        if (mHeadsUpChild != null) {
+            return mHeadsUpChild.getHeight();
+        } else {
+            return mContractedChild.getHeight() + mContext.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.notification_action_list_height);
+        }
+    }
+
     private void updateContentTransformation() {
         int visibleType = calculateVisibleType();
         if (visibleType != mVisibleType) {
@@ -493,11 +525,15 @@
         } else {
             int visibleType = calculateVisibleType();
             if (visibleType != mVisibleType || force) {
-            View visibleView = getViewForVisibleType(visibleType);
-            if (visibleView != null) {
-                visibleView.setVisibility(VISIBLE);
-                transferRemoteInputFocus(visibleType);
-            }
+                View visibleView = getViewForVisibleType(visibleType);
+                if (visibleView != null) {
+                    visibleView.setVisibility(VISIBLE);
+                    transferRemoteInputFocus(visibleType);
+                }
+                NotificationViewWrapper visibleWrapper = getVisibleWrapper(visibleType);
+                if (visibleWrapper != null) {
+                    visibleWrapper.setContentHeight(mContentHeight, getMinContentHeightHint());
+                }
 
                 if (animate && ((visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null)
                         || (visibleType == VISIBLE_TYPE_HEADSUP && mHeadsUpChild != null)
@@ -706,7 +742,7 @@
             }
         } else {
             if (noExpandedChild || (viewHeight <= mContractedChild.getHeight()
-                    && (!mIsChildInGroup
+                    && (!mIsChildInGroup || isGroupExpanded()
                             || !mContainingNotification.isExpanded(true /* allowOnKeyguard */)))) {
                 return VISIBLE_TYPE_CONTRACTED;
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActionListTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActionListTransformState.java
new file mode 100644
index 0000000..c0373be
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActionListTransformState.java
@@ -0,0 +1,60 @@
+/*
+ * 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.systemui.statusbar.notification;
+
+import android.text.Layout;
+import android.text.TextUtils;
+import android.util.Pools;
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * A transform state of the action list
+*/
+public class ActionListTransformState extends TransformState {
+
+    private static Pools.SimplePool<ActionListTransformState> sInstancePool
+            = new Pools.SimplePool<>(40);
+
+    @Override
+    protected boolean sameAs(TransformState otherState) {
+        return otherState instanceof ActionListTransformState;
+    }
+
+    public static ActionListTransformState obtain() {
+        ActionListTransformState instance = sInstancePool.acquire();
+        if (instance != null) {
+            return instance;
+        }
+        return new ActionListTransformState();
+    }
+
+    @Override
+    protected void resetTransformedView() {
+        // We need to keep the Y transformation, because this is used to keep the action list
+        // aligned at the bottom, unrelated to transforms.
+        float y = getTransformedView().getTranslationY();
+        super.resetTransformedView();
+        getTransformedView().setTranslationY(y);
+    }
+
+    @Override
+    public void recycle() {
+        super.recycle();
+        sInstancePool.release(this);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index 889bd5c..7ca2df9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -41,6 +41,10 @@
     private ProgressBar mProgressBar;
     private TextView mTitle;
     private TextView mText;
+    private View mActionsContainer;
+
+    private int mContentHeight;
+    private int mMinHeightHint;
 
     protected NotificationTemplateViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
         super(ctx, view, row);
@@ -123,6 +127,7 @@
             // It's still a viewstub
             mProgressBar = null;
         }
+        mActionsContainer = mView.findViewById(com.android.internal.R.id.actions_container);
     }
 
     @Override
@@ -225,4 +230,21 @@
                 (int) (gSource * (1f - t) + gTarget * t),
                 (int) (bSource * (1f - t) + bTarget * t));
     }
+
+    @Override
+    public void setContentHeight(int contentHeight, int minHeightHint) {
+        super.setContentHeight(contentHeight, minHeightHint);
+
+        mContentHeight = contentHeight;
+        mMinHeightHint = minHeightHint;
+        updateActionOffset();
+    }
+
+    private void updateActionOffset() {
+        if (mActionsContainer != null) {
+            // We should never push the actions higher than they are in the headsup view.
+            int constrainedContentHeight = Math.max(mContentHeight, mMinHeightHint);
+            mActionsContainer.setTranslationY(constrainedContentHeight - mView.getHeight());
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index 7a0df1f..22519e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -158,4 +158,7 @@
 
     public void setShowingLegacyBackground(boolean showing) {
     }
+
+    public void setContentHeight(int contentHeight, int minHeightHint) {
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index 8207215..4e643f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -374,6 +374,11 @@
             result.initFrom(view);
             return result;
         }
+        if (view.getId() == com.android.internal.R.id.actions_container) {
+            ActionListTransformState result = ActionListTransformState.obtain();
+            result.initFrom(view);
+            return result;
+        }
         if (view instanceof NotificationHeaderView) {
             HeaderTransformState result = HeaderTransformState.obtain();
             result.initFrom(view);
@@ -467,7 +472,7 @@
         resetTransformedView();
     }
 
-    private void resetTransformedView() {
+    protected void resetTransformedView() {
         mTransformedView.setTranslationX(0);
         mTransformedView.setTranslationY(0);
         mTransformedView.setScaleX(1.0f);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 74bd096..e08b945 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -85,6 +85,11 @@
                         com.android.internal.R.dimen.text_size_small_material));
         mBatteryLevel.setTextSize(TypedValue.COMPLEX_UNIT_PX,
                 getResources().getDimensionPixelSize(R.dimen.battery_level_text_size));
+
+        MarginLayoutParams lp = (MarginLayoutParams) mMultiUserAvatar.getLayoutParams();
+        lp.width = lp.height = getResources().getDimensionPixelSize(
+                R.dimen.multi_user_avatar_keyguard_size);
+        mMultiUserAvatar.setLayoutParams(lp);
     }
 
     private void loadDimens() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 7e2fa2d..5256e4f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -418,11 +418,18 @@
             if (!(child instanceof ExpandableNotificationRow)) {
                 continue;
             }
+            ExpandableNotificationRow row = (ExpandableNotificationRow) child;
             boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
-                    ((ExpandableNotificationRow) child).getStatusBarNotification());
+                    row.getStatusBarNotification());
             if (suppressedSummary) {
                 continue;
             }
+            if (!mStatusBar.shouldShowOnKeyguard(row.getStatusBarNotification())) {
+                continue;
+            }
+            if (row.isRemoved()) {
+                continue;
+            }
             availableSpace -= child.getMinHeight() + notificationPadding;
             if (availableSpace >= 0 && count < maximum) {
                 count++;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 3c6e999..ba13e54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -966,7 +966,9 @@
         super.onDensityOrFontScaleChanged();
         mScrimController.onDensityOrFontScaleChanged();
         mStatusBarView.onDensityOrFontScaleChanged();
-        mBrightnessMirrorController.onDensityOrFontScaleChanged();
+        if (mBrightnessMirrorController != null) {
+            mBrightnessMirrorController.onDensityOrFontScaleChanged();
+        }
         inflateSignalClusters();
         mIconController.onDensityOrFontScaleChanged();
         inflateDismissView();
@@ -975,6 +977,13 @@
         updateEmptyShadeView();
         inflateOverflowContainer();
         mStatusBarKeyguardViewManager.onDensityOrFontScaleChanged();
+        mUserInfoController.onDensityOrFontScaleChanged();
+        if (mUserSwitcherController != null) {
+            mUserSwitcherController.onDensityOrFontScaleChanged();
+        }
+        if (mKeyguardUserSwitcher != null) {
+            mKeyguardUserSwitcher.onDensityOrFontScaleChanged();
+        }
     }
 
     private void inflateSignalClusters() {
@@ -1541,6 +1550,7 @@
             ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>(notificationChildren);
             for (int i = 0; i < toRemove.size(); i++) {
                 toRemove.get(i).setKeepInParent(true);
+                toRemove.get(i).setRemoved(true);
             }
             for (int i = 0; i < toRemove.size(); i++) {
                 removeNotification(toRemove.get(i).getStatusBarNotification().getKey(), ranking);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index c39d718..21f3f5e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -21,8 +21,6 @@
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.database.DataSetObserver;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -47,11 +45,12 @@
     private static final boolean ALWAYS_ON = false;
 
     private final Container mUserSwitcherContainer;
-    private final ViewGroup mUserSwitcher;
     private final KeyguardStatusBarView mStatusBarView;
     private final Adapter mAdapter;
     private final AppearAnimationUtils mAppearAnimationUtils;
     private final KeyguardUserSwitcherScrim mBackground;
+
+    private ViewGroup mUserSwitcher;
     private ObjectAnimator mBgAnimator;
     private UserSwitcherController mUserSwitcherController;
     private boolean mAnimating;
@@ -63,10 +62,8 @@
                 context.getResources().getBoolean(R.bool.config_keyguardUserSwitcher) || ALWAYS_ON;
         if (userSwitcherController != null && keyguardUserSwitcherEnabled) {
             mUserSwitcherContainer = (Container) userSwitcher.inflate();
-            mUserSwitcher = (ViewGroup)
-                    mUserSwitcherContainer.findViewById(R.id.keyguard_user_switcher_inner);
-            mBackground = new KeyguardUserSwitcherScrim(mUserSwitcher);
-            mUserSwitcher.setBackground(mBackground);
+            mBackground = new KeyguardUserSwitcherScrim(context);
+            reinflateViews();
             mStatusBarView = statusBarView;
             mStatusBarView.setKeyguardUserSwitcher(this);
             panelView.setKeyguardUserSwitcher(this);
@@ -78,7 +75,6 @@
             mUserSwitcherContainer.setKeyguardUserSwitcher(this);
         } else {
             mUserSwitcherContainer = null;
-            mUserSwitcher = null;
             mStatusBarView = null;
             mAdapter = null;
             mAppearAnimationUtils = null;
@@ -86,6 +82,22 @@
         }
     }
 
+    private void reinflateViews() {
+        if (mUserSwitcher != null) {
+            mUserSwitcher.setBackground(null);
+            mUserSwitcher.removeOnLayoutChangeListener(mBackground);
+        }
+        mUserSwitcherContainer.removeAllViews();
+
+        LayoutInflater.from(mUserSwitcherContainer.getContext())
+                .inflate(R.layout.keyguard_user_switcher_inner, mUserSwitcherContainer);
+
+        mUserSwitcher = (ViewGroup) mUserSwitcherContainer.findViewById(
+                R.id.keyguard_user_switcher_inner);
+        mUserSwitcher.addOnLayoutChangeListener(mBackground);
+        mUserSwitcher.setBackground(mBackground);
+    }
+
     public void setKeyguard(boolean keyguard, boolean animate) {
         if (mUserSwitcher != null) {
             if (keyguard && shouldExpandByDefault()) {
@@ -228,6 +240,13 @@
         }
     };
 
+    public void onDensityOrFontScaleChanged() {
+        if (mUserSwitcherContainer != null) {
+            reinflateViews();
+            refresh();
+        }
+    }
+
     public static class Adapter extends UserSwitcherController.BaseUserAdapter implements
             View.OnClickListener {
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java
index 353e07d..49f5bcd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.policy;
 
+import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
@@ -45,9 +46,8 @@
     private Paint mRadialGradientPaint = new Paint();
     private int mLayoutWidth;
 
-    public KeyguardUserSwitcherScrim(View host) {
-        host.addOnLayoutChangeListener(this);
-        mDarkColor = host.getContext().getColor(
+    public KeyguardUserSwitcherScrim(Context context) {
+        mDarkColor = context.getColor(
                 R.color.keyguard_user_switcher_background_gradient_color);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index a855aed..095265a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -272,7 +272,7 @@
 
     public boolean requestScrollTo() {
         findScrollContainer();
-        mScrollContainer.scrollTo(mScrollContainerChild);
+        mScrollContainer.lockScrollTo(mScrollContainerChild);
         return true;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
index bae5bda..c5a4f5e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
@@ -50,7 +50,6 @@
             new ArrayList<OnUserInfoChangedListener>();
     private AsyncTask<Void, Void, Pair<String, Drawable>> mUserInfoTask;
 
-    private boolean mUseDefaultAvatar;
     private String mUserName;
     private Drawable mUserDrawable;
 
@@ -58,7 +57,6 @@
         mContext = context;
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_SWITCHED);
-        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
         mContext.registerReceiver(mReceiver, filter);
 
         IntentFilter profileFilter = new IntentFilter();
@@ -83,10 +81,6 @@
             final String action = intent.getAction();
             if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                 reloadUserInfo();
-            } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
-                if (mUseDefaultAvatar) {
-                    reloadUserInfo();
-                }
             }
         }
     };
@@ -159,7 +153,6 @@
                 } else {
                     avatar = UserIcons.getDefaultUserIcon(isGuest? UserHandle.USER_NULL : userId,
                             /* light= */ true);
-                    mUseDefaultAvatar = true;
                 }
 
                 // If it's a single-user device, get the profile name, since the nickname is not
@@ -202,6 +195,10 @@
         }
     }
 
+    public void onDensityOrFontScaleChanged() {
+        reloadUserInfo();
+    }
+
     public interface OnUserInfoChangedListener {
         public void onUserInfoChanged(String name, Drawable picture);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 6800772..415b7a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -23,7 +23,6 @@
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -169,12 +168,13 @@
             return;
         }
 
+        boolean forceAllUsers = mForcePictureLoadForUserId.get(UserHandle.USER_ALL);
         SparseArray<Bitmap> bitmaps = new SparseArray<>(mUsers.size());
         final int N = mUsers.size();
         for (int i = 0; i < N; i++) {
             UserRecord r = mUsers.get(i);
-            if (r == null || r.picture == null ||
-                    r.info == null || mForcePictureLoadForUserId.get(r.info.id)) {
+            if (r == null || r.picture == null || r.info == null || forceAllUsers
+                    || mForcePictureLoadForUserId.get(r.info.id)) {
                 continue;
             }
             bitmaps.put(r.info.id, r.picture);
@@ -600,6 +600,10 @@
         return item.info.name;
     }
 
+    public void onDensityOrFontScaleChanged() {
+        refreshUsers(UserHandle.USER_ALL);
+    }
+
     public static abstract class BaseUserAdapter extends BaseAdapter {
 
         final UserSwitcherController mController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index a1e89b7..dafaf61 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -103,9 +103,8 @@
         int childCount = Math.min(mChildren.size(), NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED);
         for (int i = 0; i < childCount; i++) {
             View child = mChildren.get(i);
-            if (child.getVisibility() == View.GONE) {
-                continue;
-            }
+            // We need to layout all children even the GONE ones, such that the heights are
+            // calculated correctly as they are used to calculate how many we can fit on the screen
             child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());
             mDividers.get(i).layout(0, 0, getWidth(), mDividerHeight);
         }
@@ -138,17 +137,19 @@
         int overflowIndex = childCount > collapsedChildren ? collapsedChildren - 1 : -1;
         for (int i = 0; i < childCount; i++) {
             ExpandableNotificationRow child = mChildren.get(i);
+            // We need to measure all children even the GONE ones, such that the heights are
+            // calculated correctly as they are used to calculate how many we can fit on the screen.
             boolean isOverflow = i == overflowIndex;
             child.setSingleLineWidthIndention(isOverflow && mOverflowNumber != null
                     ? mOverflowNumber.getMeasuredWidth()
                     : 0);
             child.measure(widthMeasureSpec, newHeightSpec);
-            height += child.getMeasuredHeight();
-
             // layout the divider
             View divider = mDividers.get(i);
             divider.measure(widthMeasureSpec, dividerHeightSpec);
-            height += mDividerHeight;
+            if (child.getVisibility() != GONE) {
+                height += child.getMeasuredHeight() + mDividerHeight;
+            }
         }
         mRealHeight = height;
         if (heightMode != MeasureSpec.UNSPECIFIED) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index ffa246a..06412758 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -243,6 +243,7 @@
             = new ViewTreeObserver.OnPreDrawListener() {
         @Override
         public boolean onPreDraw() {
+            updateForcedScroll();
             updateChildren();
             mChildrenUpdateRequested = false;
             getViewTreeObserver().removeOnPreDrawListener(this);
@@ -334,6 +335,7 @@
     private boolean mDrawBackgroundAsSrc;
     private boolean mFadedOut;
     private boolean mGroupExpandedForMeasure;
+    private View mForcedScroll;
     private float mBackgroundFadeAmount = 1.0f;
     private static final Property<NotificationStackScrollLayout, Float> BACKGROUND_FADE =
             new FloatProperty<NotificationStackScrollLayout>("backgroundFade") {
@@ -481,19 +483,22 @@
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        measureChildren(widthMeasureSpec, heightMeasureSpec);
+        // We need to measure all children even the GONE ones, such that the heights are calculated
+        // correctly as they are used to calculate how many we can fit on the screen.
+        final int size = getChildCount();
+        for (int i = 0; i < size; i++) {
+            measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);
+        }
     }
 
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
-
         // we layout all our children centered on the top
         float centerX = getWidth() / 2.0f;
         for (int i = 0; i < getChildCount(); i++) {
             View child = getChildAt(i);
-            if (child.getVisibility() == GONE) {
-                continue;
-            }
+            // We need to layout all children even the GONE ones, such that the heights are
+            // calculated correctly as they are used to calculate how many we can fit on the screen
             float width = child.getMeasuredWidth();
             float height = child.getMeasuredHeight();
             child.layout((int) (centerX - width / 2.0f),
@@ -591,6 +596,23 @@
         clampScrollPosition();
     }
 
+    private void updateForcedScroll() {
+        if (mForcedScroll != null && (!mForcedScroll.hasFocus()
+                || !mForcedScroll.isAttachedToWindow())) {
+            mForcedScroll = null;
+        }
+        if (mForcedScroll != null) {
+            ExpandableView expandableView = (ExpandableView) mForcedScroll;
+            int positionInLinearLayout = getPositionInLinearLayout(expandableView);
+            int targetScroll = targetScrollForView(expandableView, positionInLinearLayout);
+
+            targetScroll = Math.max(0, Math.min(targetScroll, getScrollRange()));
+            if (mOwnScrollY < targetScroll || positionInLinearLayout < mOwnScrollY) {
+                mOwnScrollY = targetScroll;
+            }
+        }
+    }
+
     private void requestChildrenUpdate() {
         if (!mChildrenUpdateRequested) {
             getViewTreeObserver().addOnPreDrawListener(mChildrenUpdater);
@@ -978,11 +1000,19 @@
         mScrollingEnabled = enable;
     }
 
+    @Override
+    public void lockScrollTo(View v) {
+        if (mForcedScroll == v) {
+            return;
+        }
+        mForcedScroll = v;
+        scrollTo(v);
+    }
+
+    @Override
     public boolean scrollTo(View v) {
         ExpandableView expandableView = (ExpandableView) v;
-        int positionInLinearLayout = getPositionInLinearLayout(v);
-        int targetScroll = positionInLinearLayout + expandableView.getIntrinsicHeight() +
-                getImeInset() - getHeight() + getTopPadding();
+        int targetScroll = targetScrollForView(expandableView, getPositionInLinearLayout(v));
 
         if (mOwnScrollY < targetScroll) {
             mScroller.startScroll(mScrollX, mOwnScrollY, 0, targetScroll - mOwnScrollY);
@@ -993,6 +1023,15 @@
         return false;
     }
 
+    /**
+     * @return the scroll necessary to make the bottom edge of {@param v} align with the top of
+     *         the IME.
+     */
+    private int targetScrollForView(ExpandableView v, int positionInLinearLayout) {
+        return positionInLinearLayout + v.getIntrinsicHeight() +
+                getImeInset() - getHeight() + getTopPadding();
+    }
+
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
         mBottomInset = insets.getSystemWindowInsetBottom();
@@ -1111,6 +1150,7 @@
         if (ev.getY() < mQsContainer.getBottom()) {
             return false;
         }
+        mForcedScroll = null;
         initVelocityTrackerIfNotExists();
         mVelocityTracker.addMovement(ev);
 
@@ -2787,6 +2827,14 @@
     }
 
     @Override
+    public void clearChildFocus(View child) {
+        super.clearChildFocus(child);
+        if (mForcedScroll == child) {
+            mForcedScroll = null;
+        }
+    }
+
+    @Override
     public void requestDisallowLongPress() {
         removeLongPressCallback();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java
index 17b7871..b9d12ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java
@@ -36,6 +36,12 @@
     boolean scrollTo(View v);
 
     /**
+     * Like {@link #scrollTo(View)}, but keeps the scroll locked until the user
+     * scrolls, or {@param v} loses focus or is detached.
+     */
+    void lockScrollTo(View v);
+
+    /**
      * Request that the view does not dismiss for the current touch.
      */
     void requestDisallowDismiss();
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index e1695e0..7f977dd 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1737,7 +1737,7 @@
         }
 
         if (userState.mIsDisplayMagnificationEnabled ||
-                userHasMagnificationServicesLocked(userState)) {
+                userHasListeningMagnificationServicesLocked(userState)) {
             // Initialize the magnification controller if necessary
             getMagnificationController();
             mMagnificationController.register();
@@ -1761,6 +1761,22 @@
         return false;
     }
 
+    /**
+     * Returns whether the specified user has any services that are capable of
+     * controlling magnification and are actively listening for magnification updates.
+     */
+    private boolean userHasListeningMagnificationServicesLocked(UserState userState) {
+        final List<Service> services = userState.mBoundServices;
+        for (int i = 0, count = services.size(); i < count; i++) {
+            final Service service = services.get(i);
+            if (mSecurityPolicy.canControlMagnification(service)
+                    && service.mInvocationHandler.mIsMagnificationCallbackEnabled) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private void updateSoftKeyboardShowModeLocked(UserState userState) {
         final int userId = userState.mUserId;
         // Only check whether we need to reset the soft keyboard mode if it is not set to the
@@ -2864,19 +2880,28 @@
         }
 
         @Override
-        public Region getMagnifiedRegion() {
+        public Region getMagnificationRegion() {
             synchronized (mLock) {
-                if (!isCalledForCurrentUserLocked()) {
-                    return Region.obtain();
-                }
-            }
-            final long identity = Binder.clearCallingIdentity();
-            try {
                 final Region region = Region.obtain();
-                getMagnificationController().getMagnificationRegion(region);
-                return region;
-            } finally {
-                Binder.restoreCallingIdentity(identity);
+                if (!isCalledForCurrentUserLocked()) {
+                    return region;
+                }
+                MagnificationController magnificationController = getMagnificationController();
+                boolean forceRegistration = mSecurityPolicy.canControlMagnification(this);
+                boolean initiallyRegistered = magnificationController.isRegisteredLocked();
+                if (!initiallyRegistered && forceRegistration) {
+                    magnificationController.register();
+                }
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    magnificationController.getMagnificationRegion(region);
+                    return region;
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                    if (!initiallyRegistered && forceRegistration) {
+                        magnificationController.unregister();
+                    }
+                }
             }
         }
 
@@ -2940,13 +2965,17 @@
                 if (!permissionGranted) {
                     return false;
                 }
-            }
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                return getMagnificationController().setScaleAndCenter(
-                        scale, centerX, centerY, animate, mId);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    MagnificationController magnificationController = getMagnificationController();
+                    if (!magnificationController.isRegisteredLocked()) {
+                        magnificationController.register();
+                    }
+                    return magnificationController
+                            .setScaleAndCenter(scale, centerX, centerY, animate, mId);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
             }
         }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
index 027b6e2..7886b9e 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
@@ -151,6 +151,15 @@
         }
     }
 
+    /**
+     * Check if we are registered. Note that we may be planning to unregister at any moment.
+     *
+     * @return {@code true} if the controller is registered. {@code false} otherwise.
+     */
+    public boolean isRegisteredLocked() {
+        return mRegistered;
+    }
+
     private void unregisterInternalLocked() {
         if (mRegistered) {
             mSpecAnimationBridge.setEnabled(false);
@@ -179,6 +188,10 @@
      */
     private void onMagnificationRegionChanged(Region magnified, boolean updateSpec) {
         synchronized (mLock) {
+            if (!mRegistered) {
+                // Don't update if we've unregistered
+                return;
+            }
             boolean magnificationChanged = false;
             boolean boundsChanged = false;
 
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index c2a1c50..5b6117d 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -340,8 +340,9 @@
     }
 
     public void onUnlockUser(int userId) {
-        tieManagedProfileLockIfNecessary(userId, null);
+        // Hide notification first, as tie managed profile lock takes time
         hideEncryptionNotification(new UserHandle(userId));
+        tieManagedProfileLockIfNecessary(userId, null);
 
         // Now we have unlocked the parent user we should show notifications
         // about any profiles that exist.
@@ -789,11 +790,10 @@
                 if (isSecure) {
                     tieManagedProfileLockIfNecessary(managedUserId, null);
                 } else {
-                    clearUserKeyProtection(managedUserId);
                     getGateKeeperService().clearSecureUserId(managedUserId);
                     mStorage.writePatternHash(null, managedUserId);
                     setKeystorePassword(null, managedUserId);
-                    fixateNewestUserKeyAuth(managedUserId);
+                    clearUserKeyProtection(managedUserId);
                     mStorage.removeChildProfileLock(managedUserId);
                     removeKeystoreProfileKey(managedUserId);
                 }
@@ -828,11 +828,10 @@
         byte[] currentHandle = getCurrentHandle(userId);
 
         if (pattern == null) {
-            clearUserKeyProtection(userId);
             getGateKeeperService().clearSecureUserId(userId);
             mStorage.writePatternHash(null, userId);
             setKeystorePassword(null, userId);
-            fixateNewestUserKeyAuth(userId);
+            clearUserKeyProtection(userId);
             onUserLockChanged(userId);
             return;
         }
@@ -862,12 +861,8 @@
 
         byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, pattern, userId);
         if (enrolledHandle != null) {
-            CredentialHash willStore
-                = new CredentialHash(enrolledHandle, CredentialHash.VERSION_GATEKEEPER);
-            setUserKeyProtection(userId, pattern,
-                doVerifyPattern(pattern, willStore, true, 0, userId));
             mStorage.writePatternHash(enrolledHandle, userId);
-            fixateNewestUserKeyAuth(userId);
+            setUserKeyProtection(userId, pattern, verifyPattern(pattern, 0, userId));
             onUserLockChanged(userId);
         } else {
             throw new RemoteException("Failed to enroll pattern");
@@ -890,11 +885,10 @@
             throws RemoteException {
         byte[] currentHandle = getCurrentHandle(userId);
         if (password == null) {
-            clearUserKeyProtection(userId);
             getGateKeeperService().clearSecureUserId(userId);
             mStorage.writePasswordHash(null, userId);
             setKeystorePassword(null, userId);
-            fixateNewestUserKeyAuth(userId);
+            clearUserKeyProtection(userId);
             onUserLockChanged(userId);
             return;
         }
@@ -922,12 +916,8 @@
 
         byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, password, userId);
         if (enrolledHandle != null) {
-            CredentialHash willStore
-                = new CredentialHash(enrolledHandle, CredentialHash.VERSION_GATEKEEPER);
-            setUserKeyProtection(userId, password,
-                doVerifyPassword(password, willStore, true, 0, userId));
             mStorage.writePasswordHash(enrolledHandle, userId);
-            fixateNewestUserKeyAuth(userId);
+            setUserKeyProtection(userId, password, verifyPassword(password, 0, userId));
             onUserLockChanged(userId);
         } else {
             throw new RemoteException("Failed to enroll password");
@@ -1032,11 +1022,11 @@
         if (token == null) {
             throw new RemoteException("Empty payload verifying a credential we just set");
         }
-        addUserKeyAuth(userId, token, secretFromCredential(credential));
+        changeUserKey(userId, token, secretFromCredential(credential));
     }
 
     private void clearUserKeyProtection(int userId) throws RemoteException {
-        addUserKeyAuth(userId, null, null);
+        changeUserKey(userId, null, null);
     }
 
     private static byte[] secretFromCredential(String credential) throws RemoteException {
@@ -1055,23 +1045,18 @@
         }
     }
 
-    private void addUserKeyAuth(int userId, byte[] token, byte[] secret)
+    private void changeUserKey(int userId, byte[] token, byte[] secret)
             throws RemoteException {
         final UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId);
         final IMountService mountService = getMountService();
         final long callingId = Binder.clearCallingIdentity();
         try {
-            mountService.addUserKeyAuth(userId, userInfo.serialNumber, token, secret);
+            mountService.changeUserKey(userId, userInfo.serialNumber, token, null, secret);
         } finally {
             Binder.restoreCallingIdentity(callingId);
         }
     }
 
-    private void fixateNewestUserKeyAuth(int userId)
-            throws RemoteException {
-        getMountService().fixateNewestUserKeyAuth(userId);
-    }
-
     @Override
     public VerifyCredentialResponse checkPattern(String pattern, int userId) throws RemoteException {
         return doVerifyPattern(pattern, false, 0, userId);
@@ -1087,11 +1072,6 @@
             long challenge, int userId) throws RemoteException {
        checkPasswordReadPermission(userId);
        CredentialHash storedHash = mStorage.readPatternHash(userId);
-       return doVerifyPattern(pattern, storedHash, hasChallenge, challenge, userId);
-    }
-
-    private VerifyCredentialResponse doVerifyPattern(String pattern, CredentialHash storedHash,
-            boolean hasChallenge, long challenge, int userId) throws RemoteException {
        boolean shouldReEnrollBaseZero = storedHash != null && storedHash.isBaseZeroPattern;
 
        String patternToVerify;
@@ -1129,6 +1109,7 @@
        }
 
        return response;
+
     }
 
     @Override
@@ -1178,11 +1159,6 @@
             long challenge, int userId) throws RemoteException {
        checkPasswordReadPermission(userId);
        CredentialHash storedHash = mStorage.readPasswordHash(userId);
-       return doVerifyPassword(password, storedHash, hasChallenge, challenge, userId);
-    }
-
-    private VerifyCredentialResponse doVerifyPassword(String password, CredentialHash storedHash,
-            boolean hasChallenge, long challenge, int userId) throws RemoteException {
        return verifyCredential(userId, storedHash, password, hasChallenge, challenge,
                new CredentialUtil() {
                    @Override
diff --git a/services/core/java/com/android/server/LockSettingsStorage.java b/services/core/java/com/android/server/LockSettingsStorage.java
index ab91a73..9ab6300 100644
--- a/services/core/java/com/android/server/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/LockSettingsStorage.java
@@ -74,7 +74,7 @@
 
     private SparseArray<Integer> mStoredCredentialType;
 
-    static class CredentialHash {
+    class CredentialHash {
         static final int TYPE_NONE = -1;
         static final int TYPE_PATTERN = 1;
         static final int TYPE_PASSWORD = 2;
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index c89b6ea..25ce485 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -2816,36 +2816,15 @@
         }
     }
 
-    /*
-     * Add this token/secret pair to the set of ways we can recover a disk encryption key.
-     * Changing the token/secret for a disk encryption key is done in two phases: first, adding
-     * a new token/secret pair with this call, then delting all other pairs with
-     * fixateNewestUserKeyAuth. This allows other places where a credential is used, such as
-     * Gatekeeper, to be updated between the two calls.
-     */
     @Override
-    public void addUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) {
+    public void changeUserKey(int userId, int serialNumber,
+            byte[] token, byte[] oldSecret, byte[] newSecret) {
         enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
         waitForReady();
 
         try {
-            mCryptConnector.execute("cryptfs", "add_user_key_auth", userId, serialNumber,
-                encodeBytes(token), encodeBytes(secret));
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
-        }
-    }
-
-    /*
-     * Delete all disk encryption token/secret pairs except the most recently added one
-     */
-    @Override
-    public void fixateNewestUserKeyAuth(int userId) {
-        enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
-        waitForReady();
-
-        try {
-            mCryptConnector.execute("cryptfs", "fixate_newest_user_key_auth", userId);
+            mCryptConnector.execute("cryptfs", "change_user_key", userId, serialNumber,
+                encodeBytes(token), encodeBytes(oldSecret), encodeBytes(newSecret));
         } catch (NativeDaemonConnectorException e) {
             throw e.rethrowAsParcelableException();
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f52bda9..313ca9a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1513,6 +1513,10 @@
 
     PackageManagerInternal mPackageManagerInt;
 
+    // VoiceInteraction session ID that changes for each new request except when
+    // being called for multiwindow assist in a single session.
+    private int mViSessionId = 1000;
+
     final class KillHandler extends Handler {
         static final int KILL_PROCESS_GROUP_MSG = 4000;
 
@@ -11881,7 +11885,8 @@
     @Override
     public Bundle getAssistContextExtras(int requestType) {
         PendingAssistExtras pae = enqueueAssistContext(requestType, null, null, null,
-                null, null, true, UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT);
+                null, null, true /* focused */, true /* newSessionId */,
+                UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT);
         if (pae == null) {
             return null;
         }
@@ -11946,16 +11951,16 @@
     @Override
     public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver,
             Bundle receiverExtras,
-            IBinder activityToken, boolean focused) {
+            IBinder activityToken, boolean focused, boolean newSessionId) {
         return enqueueAssistContext(requestType, null, null, receiver, receiverExtras,
-                activityToken, focused,
+                activityToken, focused, newSessionId,
                 UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_LONG_TIMEOUT)
                 != null;
     }
 
     private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint,
-            IResultReceiver receiver, Bundle receiverExtras, IBinder activityToken, boolean focused,
-            int userHandle, Bundle args, long timeout) {
+            IResultReceiver receiver, Bundle receiverExtras, IBinder activityToken,
+            boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout) {
         enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
                 "enqueueAssistContext()");
         synchronized (this) {
@@ -11995,9 +12000,13 @@
             extras.putInt(Intent.EXTRA_ASSIST_UID, activity.app.uid);
             pae = new PendingAssistExtras(activity, extras, intent, hint, receiver, receiverExtras,
                     userHandle);
+            // Increment the sessionId if necessary
+            if (newSessionId) {
+                mViSessionId++;
+            }
             try {
                 activity.app.thread.requestAssistContextExtras(activity.appToken, pae,
-                        requestType);
+                        requestType, mViSessionId);
                 mPendingAssistExtras.add(pae);
                 mUiHandler.postDelayed(pae, timeout);
             } catch (RemoteException e) {
@@ -12102,7 +12111,8 @@
 
     public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle,
             Bundle args) {
-        return enqueueAssistContext(requestType, intent, hint, null, null, null, true,
+        return enqueueAssistContext(requestType, intent, hint, null, null, null,
+                true /* focused */, true /* newSessionId */,
                 userHandle, args, PENDING_ASSIST_EXTRAS_TIMEOUT) != null;
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index d74e22e..243c887 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3341,14 +3341,12 @@
                         } catch (RemoteException re) {
                             // Ok
                         }
-                        // TODO: VI This is redundant in some cases
                         mService.finishRunningVoiceLocked();
                         break;
                     }
                 }
             }
         }
-        Slog.d(TAG, "ActivityStack.finishVoiceTask()");
 
         if (didOne) {
             mService.updateOomAdjLocked();
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index bc297de..0a081e9 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -441,7 +441,7 @@
                     Notification localForegroundNoti = _foregroundNoti;
                     try {
                         if (localForegroundNoti.getSmallIcon() == null) {
-                            // It is not correct for the caller to supply a notification
+                            // It is not correct for the caller to not supply a notification
                             // icon, but this used to be able to slip through, so for
                             // those dirty apps we will create a notification clearly
                             // blaming the app.
@@ -458,8 +458,8 @@
                             }
                             Context ctx = null;
                             try {
-                                ctx = ams.mContext.createPackageContext(
-                                        appInfo.packageName, 0);
+                                ctx = ams.mContext.createPackageContextAsUser(
+                                        appInfo.packageName, 0, new UserHandle(userId));
 
                                 Notification.Builder notiBuilder = new Notification.Builder(ctx);
 
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index ae01635..142426d 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -968,8 +968,8 @@
                     }
                     daemon.setActiveGroup(userId, fpDir.getAbsolutePath().getBytes());
                     mCurrentUserId = userId;
-                    mCurrentAuthenticatorId = daemon.getAuthenticatorId();
                 }
+                mCurrentAuthenticatorId = daemon.getAuthenticatorId();
             } catch (RemoteException e) {
                 Slog.e(TAG, "Failed to setActiveGroup():", e);
             }
diff --git a/services/core/java/com/android/server/net/NetworkStatsObservers.java b/services/core/java/com/android/server/net/NetworkStatsObservers.java
index 6f781b3..230c2e9 100644
--- a/services/core/java/com/android/server/net/NetworkStatsObservers.java
+++ b/services/core/java/com/android/server/net/NetworkStatsObservers.java
@@ -81,8 +81,6 @@
      */
     public DataUsageRequest register(DataUsageRequest inputRequest, Messenger messenger,
                 IBinder binder, int callingUid, @NetworkStatsAccess.Level int accessLevel) {
-        checkVisibilityUids(callingUid, accessLevel, inputRequest.uids);
-
         DataUsageRequest request = buildRequest(inputRequest);
         RequestInfo requestInfo = buildRequestInfo(request, messenger, binder, callingUid,
                 accessLevel);
@@ -211,14 +209,13 @@
                     + ". Overriding to a safer default of " + thresholdInBytes + " bytes");
         }
         return new DataUsageRequest(mNextDataUsageRequestId.incrementAndGet(),
-                request.templates, request.uids, thresholdInBytes);
+                request.template, thresholdInBytes);
     }
 
     private RequestInfo buildRequestInfo(DataUsageRequest request,
                 Messenger messenger, IBinder binder, int callingUid,
                 @NetworkStatsAccess.Level int accessLevel) {
-        if (accessLevel <= NetworkStatsAccess.Level.USER
-                || request.uids != null && request.uids.length > 0) {
+        if (accessLevel <= NetworkStatsAccess.Level.USER) {
             return new UserUsageRequestInfo(this, request, messenger, binder, callingUid,
                     accessLevel);
         } else {
@@ -229,19 +226,6 @@
         }
     }
 
-    private void checkVisibilityUids(int callingUid, @NetworkStatsAccess.Level int accessLevel,
-                int[] uids) {
-        if (uids == null) {
-            return;
-        }
-        for (int i = 0; i < uids.length; i++) {
-            if (!NetworkStatsAccess.isAccessibleToUser(uids[i], callingUid, accessLevel)) {
-                throw new SecurityException("Caller " + callingUid + " cannot monitor network stats"
-                        + " for uid " + uids[i] + " with accessLevel " + accessLevel);
-            }
-        }
-    }
-
     /**
      * Tracks information relevant to a data usage observer.
      * It will notice when the calling process dies so we can self-expire.
@@ -359,15 +343,13 @@
 
         @Override
         protected boolean checkStats() {
-            for (int i = 0; i < mRequest.templates.length; i++) {
-                long bytesSoFar = getTotalBytesForNetwork(mRequest.templates[i]);
-                if (LOGV) {
-                    Slog.v(TAG, bytesSoFar + " bytes so far since notification for "
-                            + mRequest.templates[i]);
-                }
-                if (bytesSoFar > mRequest.thresholdInBytes) {
-                    return true;
-                }
+            long bytesSoFar = getTotalBytesForNetwork(mRequest.template);
+            if (LOGV) {
+                Slog.v(TAG, bytesSoFar + " bytes so far since notification for "
+                        + mRequest.template);
+            }
+            if (bytesSoFar > mRequest.thresholdInBytes) {
+                return true;
             }
             return false;
         }
@@ -405,20 +387,17 @@
 
         @Override
         protected boolean checkStats() {
-            int[] uidsToMonitor = getUidsToMonitor();
+            int[] uidsToMonitor = mCollection.getRelevantUids(mAccessLevel, mCallingUid);
 
-            for (int i = 0; i < mRequest.templates.length; i++) {
-                for (int j = 0; j < uidsToMonitor.length; j++) {
-                    long bytesSoFar = getTotalBytesForNetworkUid(mRequest.templates[i],
-                            uidsToMonitor[j]);
+            for (int i = 0; i < uidsToMonitor.length; i++) {
+                long bytesSoFar = getTotalBytesForNetworkUid(mRequest.template, uidsToMonitor[i]);
 
-                    if (LOGV) {
-                        Slog.v(TAG, bytesSoFar + " bytes so far since notification for "
-                                + mRequest.templates[i] + " for uid=" + uidsToMonitor[j]);
-                    }
-                    if (bytesSoFar > mRequest.thresholdInBytes) {
-                        return true;
-                    }
+                if (LOGV) {
+                    Slog.v(TAG, bytesSoFar + " bytes so far since notification for "
+                            + mRequest.template + " for uid=" + uidsToMonitor[i]);
+                }
+                if (bytesSoFar > mRequest.thresholdInBytes) {
+                    return true;
                 }
             }
             return false;
@@ -453,21 +432,6 @@
                 return 0;
             }
         }
-
-        private int[] getUidsToMonitor() {
-            if (mRequest.uids == null || mRequest.uids.length == 0) {
-                return mCollection.getRelevantUids(mAccessLevel, mCallingUid);
-            }
-            // Pick only uids from the request that are currently accessible to the user
-            IntArray accessibleUids = new IntArray(mRequest.uids.length);
-            for (int i = 0; i < mRequest.uids.length; i++) {
-                int uid = mRequest.uids[i];
-                if (NetworkStatsAccess.isAccessibleToUser(uid, mCallingUid, mAccessLevel)) {
-                    accessibleUids.add(uid);
-                }
-            }
-            return accessibleUids.toArray();
-        }
     }
 
     private static class StatsContext {
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 2c2e9b9..8610fa1 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -578,9 +578,12 @@
                 if (tag == TAG_NONE) {
                     return getUidComplete().getHistory(template, uid, set, tag, fields, start, end,
                             accessLevel);
-                } else {
+                } else if (uid == Binder.getCallingUid()) {
                     return getUidTagComplete().getHistory(template, uid, set, tag, fields,
                             start, end, accessLevel);
+                } else {
+                    throw new SecurityException("Calling package " + mCallingPackage
+                            + " cannot access tag information from a different uid");
                 }
             }
 
@@ -761,12 +764,11 @@
     }
 
     @Override
-    public DataUsageRequest registerDataUsageCallback(String callingPackage,
+    public DataUsageRequest registerUsageCallback(String callingPackage,
                 DataUsageRequest request, Messenger messenger, IBinder binder) {
         checkNotNull(callingPackage, "calling package is null");
         checkNotNull(request, "DataUsageRequest is null");
-        checkNotNull(request.templates, "NetworkTemplate is null");
-        checkArgument(request.templates.length > 0);
+        checkNotNull(request.template, "NetworkTemplate is null");
         checkNotNull(messenger, "messenger is null");
         checkNotNull(binder, "binder is null");
 
@@ -788,7 +790,7 @@
    }
 
     @Override
-    public void unregisterDataUsageRequest(DataUsageRequest request) {
+    public void unregisterUsageRequest(DataUsageRequest request) {
         checkNotNull(request, "DataUsageRequest is null");
 
         int callingUid = Binder.getCallingUid();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2f83ec4..4e48e4d7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -226,6 +226,7 @@
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.content.PackageHelper;
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.os.IParcelFileDescriptorFactory;
 import com.android.internal.os.InstallerConnection.InstallerException;
 import com.android.internal.os.SomeArgs;
@@ -4264,17 +4265,17 @@
         synchronized (mPackages) {
             final PackageParser.Package pkg = mPackages.get(packageName);
             if (pkg == null) {
-                throw new IllegalArgumentException("Unknown package: " + packageName);
+                return 0;
             }
 
             final BasePermission bp = mSettings.mPermissions.get(name);
             if (bp == null) {
-                throw new IllegalArgumentException("Unknown permission: " + name);
+                return 0;
             }
 
             SettingBase sb = (SettingBase) pkg.mExtras;
             if (sb == null) {
-                throw new IllegalArgumentException("Unknown package: " + packageName);
+                return 0;
             }
 
             PermissionsState permissionsState = sb.getPermissionsState();
@@ -7220,8 +7221,16 @@
             }
         }
 
-        final int elapsedTime = (int) TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime);
-        // TODO: Log events using MetricsLogger.histogram / MetricsLogger.count
+        final int elapsedTimeMs = (int) TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime);
+        // Report the elapsed time in deci-seconds (tenths of a second) rounded upwards
+        // (e.g. 1234 ms will become 13ds). This will help provide histograms at a more reasonable
+        // granularity.
+        final int elapsedTimeDs = ((elapsedTimeMs + 99) / 100);
+        MetricsLogger.histogram(mContext, "opt_dialog_num_dexopted", numberOfPackagesOptimized);
+        MetricsLogger.histogram(mContext, "opt_dialog_num_skipped", numberOfPackagesSkipped);
+        MetricsLogger.histogram(mContext, "opt_dialog_num_failed", numberOfPackagesFailed);
+        MetricsLogger.histogram(mContext, "opt_dialog_num_total", getOptimizablePackages().size());
+        MetricsLogger.histogram(mContext, "opt_dialog_time_decis", elapsedTimeDs);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index 49dab0a..a37b65a 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -185,8 +185,7 @@
         clearThumbnail();
         setNullAnimation();
         if (mAppToken.deferClearAllDrawn) {
-            mAppToken.allDrawn = false;
-            mAppToken.deferClearAllDrawn = false;
+            mAppToken.clearAllDrawn();
         }
         mStackClip = STACK_CLIP_BEFORE_ANIM;
     }
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 805c986..a234241 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -27,6 +27,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.WINDOW_REPLACEMENT_TIMEOUT_DURATION;
+import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN;
 
 import com.android.server.input.InputApplicationHandle;
 import com.android.server.wm.WindowManagerService.H;
@@ -65,10 +66,6 @@
 
     final boolean voiceInteraction;
 
-    // Whether we're performing an entering animation with a saved surface.
-    boolean mAnimatingWithSavedSurface;
-
-
     Task mTask;
     boolean appFullscreen;
     int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -160,6 +157,13 @@
         }
     }
 
+    void setVisibleBeforeClientHidden() {
+        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
+            final WindowState w = allAppWindows.get(i);
+            w.setVisibleBeforeClientHidden();
+        }
+    }
+
     void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) {
         firstWindowDrawn = true;
 
@@ -295,7 +299,7 @@
             // If we're animating with a saved surface, we're already visible.
             // Return true so that the alpha doesn't get cleared.
             if (!win.mAppFreezing
-                    && (win.mViewVisibility == View.VISIBLE || mAnimatingWithSavedSurface
+                    && (win.mViewVisibility == View.VISIBLE || win.isAnimatingWithSavedSurface()
                             || (win.mWinAnimator.isAnimationSet()
                                     && !service.mAppTransition.isTransitionSet()))
                     && !win.mDestroying
@@ -329,11 +333,14 @@
         final DisplayContentList displayList = new DisplayContentList();
         for (int i = allWindows.size() - 1; i >= 0; i--) {
             final WindowState win = allWindows.get(i);
-            if (!win.mDestroying) {
+
+            if (!(mAppStopped || win.mWindowRemovalAllowed)) {
                 continue;
             }
 
-            if (!(mAppStopped || win.mWindowRemovalAllowed)) {
+            win.mWinAnimator.destroyPreservedSurfaceLocked();
+
+            if (!win.mDestroying) {
                 continue;
             }
 
@@ -344,7 +351,6 @@
 
             win.destroyOrSaveSurface();
             if (win.mRemoveOnExit) {
-                win.mAnimatingExit = false;
                 service.removeWindowInnerLocked(win);
             }
             final DisplayContent displayContent = win.getDisplayContent();
@@ -388,43 +394,56 @@
         return allDrawn;
     }
 
-    boolean hasSavedSurface() {
+    boolean canRestoreSurfaces() {
         for (int i = allAppWindows.size() -1; i >= 0; i--) {
-            final WindowState ws = allAppWindows.get(i);
-            if (ws.hasSavedSurface()) {
+            final WindowState w = allAppWindows.get(i);
+            if (w.canRestoreSurface()) {
                 return true;
             }
         }
         return false;
     }
 
+    void clearVisibleBeforeClientHidden() {
+        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
+            final WindowState w = allAppWindows.get(i);
+            w.clearVisibleBeforeClientHidden();
+        }
+    }
+
     void restoreSavedSurfaces() {
-        if (!hasSavedSurface()) {
+        if (!canRestoreSurfaces()) {
+            clearVisibleBeforeClientHidden();
             return;
         }
-        mAnimatingWithSavedSurface = true;
-
         // Check if we have enough drawn windows to mark allDrawn= true.
         int numInteresting = 0;
         int numDrawn = 0;
         for (int i = allAppWindows.size() - 1; i >= 0; i--) {
             WindowState w = allAppWindows.get(i);
-            if (w.hasSavedSurface()) {
-                w.restoreSavedSurface();
-            }
-            if (w != startingWindow && !w.mAppDied
+            if (w != startingWindow && !w.mAppDied && w.wasVisibleBeforeClientHidden()
                     && (!mAppAnimator.freezingScreen || !w.mAppFreezing)) {
                 numInteresting++;
+                if (w.hasSavedSurface()) {
+                    w.restoreSavedSurface();
+                }
                 if (w.isDrawnLw()) {
                     numDrawn++;
                 }
             }
         }
 
-        allDrawn |= (numInteresting > 0) && (numInteresting == numDrawn);
+        if (!allDrawn) {
+            allDrawn = (numInteresting > 0) && (numInteresting == numDrawn);
+            if (allDrawn) {
+                service.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget();
+            }
+        }
+        clearVisibleBeforeClientHidden();
 
         if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG,
-                "restoreSavedSurfaces: " + appWindowToken + " allDrawn=" + allDrawn);
+                "restoreSavedSurfaces: " + appWindowToken + " allDrawn=" + allDrawn
+                + " numInteresting=" + numInteresting + " numDrawn=" + numDrawn);
     }
 
     void destroySavedSurfaces() {
@@ -432,7 +451,11 @@
             WindowState win = allAppWindows.get(i);
             win.destroySavedSurface();
         }
-        mAnimatingWithSavedSurface = false;
+    }
+
+    void clearAllDrawn() {
+        allDrawn = false;
+        deferClearAllDrawn = false;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 1fdc714..fba439f 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -378,6 +378,8 @@
                  * We save the focused task region once we find it, and add it back at the end.
                  */
 
+                task.getDimBounds(mTmpRect);
+
                 if (task == focusedTask) {
                     addBackFocusedTask = true;
                     mTmpRect2.set(mTmpRect);
@@ -385,7 +387,6 @@
 
                 final boolean isFreeformed = task.inFreeformWorkspace();
                 if (task != focusedTask || isFreeformed) {
-                    task.getDimBounds(mTmpRect);
                     if (isFreeformed) {
                         // If the task is freeformed, enlarge the area to account for outside
                         // touch area for resize.
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index ca68d55..61425114 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -377,6 +377,10 @@
         checkMinimizeChanged(true /* animate */);
     }
 
+    boolean isMinimizedDock() {
+        return mMinimizedDock;
+    }
+
     private void checkMinimizeChanged(boolean animate) {
         if (mDisplayContent.getDockedStackVisibleForUserLocked() == null) {
             return;
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index 5d3cc16..f11281e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -75,5 +75,5 @@
     static final boolean DEBUG_WINDOW_CROP = false;
 
     static final String TAG_KEEP_SCREEN_ON = "DebugKeepScreenOn";
-    static final boolean DEBUG_KEEP_SCREEN_ON = true;
+    static final boolean DEBUG_KEEP_SCREEN_ON = false;
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index be888fe..a0b8c35 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2170,7 +2170,7 @@
      * Returns true if we're done setting up any transitions.
      */
     private boolean prepareWindowReplacementTransition(AppWindowToken atoken) {
-        atoken.allDrawn = false;
+        atoken.clearAllDrawn();
         WindowState replacedWindow = null;
         for (int i = atoken.windows.size() - 1; i >= 0 && replacedWindow == null; i--) {
             WindowState candidate = atoken.windows.get(i);
@@ -2316,7 +2316,7 @@
                 if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Preserving " + win + " until the new one is "
                         + "added");
                 // TODO: We are overloading mAnimatingExit flag to prevent the window state from
-                // been removed. We probably need another falg to indicate that window removal
+                // been removed. We probably need another flag to indicate that window removal
                 // should be deffered vs. overloading the flag that says we are playing an exit
                 // animation.
                 win.mAnimatingExit = true;
@@ -2464,7 +2464,7 @@
                 mTokenMap.remove(token.token);
             } else if (atoken != null) {
                 atoken.firstWindowDrawn = false;
-                atoken.allDrawn = false;
+                atoken.clearAllDrawn();
             }
         }
 
@@ -4423,6 +4423,7 @@
                 // Now that the app is going invisible, we can remove it. It will be restarted
                 // if made visible again.
                 wtoken.removeAllDeadWindows();
+                wtoken.setVisibleBeforeClientHidden();
             } else if (visible) {
                 if (!mAppTransition.isTransitionSet() && mAppTransition.isReady()) {
                     // Add the app mOpeningApps if transition is unset but ready. This means
@@ -4434,8 +4435,7 @@
                 // If the token is currently hidden (should be the common case), or has been
                 // stopped, then we need to set up to wait for its windows to be ready.
                 if (wtoken.hidden || wtoken.mAppStopped) {
-                    wtoken.allDrawn = false;
-                    wtoken.deferClearAllDrawn = false;
+                    wtoken.clearAllDrawn();
 
                     // If the app was already visible, don't reset the waitingToShow state.
                     if (wtoken.hidden) {
@@ -7534,6 +7534,7 @@
                 imeTargetStack.getDockSide() : DOCKED_INVALID;
         final boolean imeOnTop = (imeDockSide == DOCKED_TOP);
         final boolean imeOnBottom = (imeDockSide == DOCKED_BOTTOM);
+        final boolean dockMinimized = displayContent.mDividerControllerLocked.isMinimizedDock();
 
         // The divider could be adjusted for IME position, or be thinner than usual,
         // or both. There are three possible cases:
@@ -7541,7 +7542,7 @@
         // - If IME is visible, and focus is on bottom, divider is moved for IME and thinner.
         // - If IME is not visible, divider is not moved and is normal width.
 
-        if (imeVisible && dockVisible && (imeOnTop || imeOnBottom)) {
+        if (imeVisible && dockVisible && (imeOnTop || imeOnBottom) && !dockMinimized) {
             final ArrayList<TaskStack> stacks = displayContent.getStacks();
             for (int i = stacks.size() - 1; i >= 0; --i) {
                 final TaskStack stack = stacks.get(i);
@@ -9233,8 +9234,7 @@
                     }
                     winAnimator.mDrawState = DRAW_PENDING;
                     if (w.mAppToken != null) {
-                        w.mAppToken.allDrawn = false;
-                        w.mAppToken.deferClearAllDrawn = false;
+                        w.mAppToken.clearAllDrawn();
                     }
                 }
                 if (!mResizingWindows.contains(w)) {
@@ -9391,7 +9391,7 @@
                         Slog.w(TAG_WM, "LEAKED SURFACE (app token hidden): "
                                 + ws + " surface=" + wsa.mSurfaceController
                                 + " token=" + ws.mAppToken
-                                + " saved=" + ws.mAppToken.hasSavedSurface());
+                                + " saved=" + ws.hasSavedSurface());
                         if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", false);
                         wsa.destroySurface();
                         leakedSurface = true;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index a89b4aa..b66de89 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -435,7 +435,15 @@
 
     // Whether the window has a saved surface from last pause, which can be
     // used to start an entering animation earlier.
-    public boolean mSurfaceSaved = false;
+    private boolean mSurfaceSaved = false;
+
+    // Whether we're performing an entering animation with a saved surface.
+    private boolean mAnimatingWithSavedSurface;
+
+    // Whether the window was visible when we set the app to invisible last time. WM uses
+    // this as a hint to restore the surface (if available) for early animation next time
+    // the app is brought visible.
+    boolean mWasVisibleBeforeClientHidden;
 
     // This window will be replaced due to relaunch. This allows window manager
     // to differentiate between simple removal of a window and replacement. In the latter case it
@@ -1949,7 +1957,20 @@
     }
 
     boolean isAnimatingWithSavedSurface() {
-        return mAppToken != null && mAppToken.mAnimatingWithSavedSurface;
+        return mAnimatingWithSavedSurface;
+    }
+
+    public void setVisibleBeforeClientHidden() {
+        mWasVisibleBeforeClientHidden |=
+                (mViewVisibility == View.VISIBLE || mAnimatingWithSavedSurface);
+    }
+
+    public void clearVisibleBeforeClientHidden() {
+        mWasVisibleBeforeClientHidden = false;
+    }
+
+    public boolean wasVisibleBeforeClientHidden() {
+        return mWasVisibleBeforeClientHidden;
     }
 
     private boolean shouldSaveSurface() {
@@ -1958,6 +1979,10 @@
             return false;
         }
 
+        if (!mWasVisibleBeforeClientHidden) {
+            return false;
+        }
+
         if ((mAttrs.flags & FLAG_SECURE) != 0) {
             // We don't save secure surfaces since their content shouldn't be shown while the app
             // isn't on screen and content might leak through during the transition animation with
@@ -2020,18 +2045,22 @@
         } else {
             mWinAnimator.destroySurfaceLocked();
         }
+        // Clear animating flags now, since the surface is now gone. (Note this is true even
+        // if the surface is saved, to outside world the surface is still NO_SURFACE.)
+        mAnimatingExit = false;
     }
 
-    public void destroySavedSurface() {
+    void destroySavedSurface() {
         if (mSurfaceSaved) {
             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
                 Slog.v(TAG, "Destroying saved surface: " + this);
             }
             mWinAnimator.destroySurfaceLocked();
         }
+        mWasVisibleBeforeClientHidden = false;
     }
 
-    public void restoreSavedSurface() {
+    void restoreSavedSurface() {
         if (!mSurfaceSaved) {
             return;
         }
@@ -2039,6 +2068,7 @@
         if (mWinAnimator.mSurfaceController != null) {
             setHasSurface(true);
             mWinAnimator.mDrawState = WindowStateAnimator.READY_TO_SHOW;
+            mAnimatingWithSavedSurface = true;
 
             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
                 Slog.v(TAG, "Restoring saved surface: " + this);
@@ -2051,10 +2081,30 @@
         }
     }
 
-    public boolean hasSavedSurface() {
+    boolean canRestoreSurface() {
+        return mWasVisibleBeforeClientHidden && mSurfaceSaved;
+    }
+
+    boolean hasSavedSurface() {
         return mSurfaceSaved;
     }
 
+    void clearHasSavedSurface() {
+        mSurfaceSaved = false;
+        mAnimatingWithSavedSurface = false;
+        mWasVisibleBeforeClientHidden = false;
+    }
+
+    void clearAnimatingWithSavedSurface() {
+        if (mAnimatingWithSavedSurface) {
+            // App has drawn something to its windows, we're no longer animating with
+            // the saved surfaces.
+            if (DEBUG_ANIM) Slog.d(TAG,
+                    "clearAnimatingWithSavedSurface(): win=" + this);
+            mAnimatingWithSavedSurface = false;
+        }
+    }
+
     @Override
     public boolean isDefaultDisplay() {
         final DisplayContent displayContent = getDisplayContent();
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index e5f603c..f0bba4a 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -584,14 +584,8 @@
                     + drawStateToString());
         }
 
-        if (mWin.mAppToken != null && mWin.mAppToken.mAnimatingWithSavedSurface) {
-            // App has drawn something to its windows, we're no longer animating with
-            // the saved surfaces. If the user exits now, we only want to save again
-            // if allDrawn is true.
-            if (DEBUG_ANIM) Slog.d(TAG,
-                    "finishDrawingLocked: mAnimatingWithSavedSurface=false " + mWin);
-            mWin.mAppToken.mAnimatingWithSavedSurface = false;
-        }
+        mWin.clearAnimatingWithSavedSurface();
+
         if (mDrawState == DRAW_PENDING) {
             if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION)
                 Slog.v(TAG, "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING " + mWin + " in "
@@ -659,6 +653,13 @@
         mDestroyPreservedSurfaceUponRedraw = false;
     }
 
+    void markPreservedSurfaceForDestroy() {
+        if (mDestroyPreservedSurfaceUponRedraw
+                && !mService.mDestroyPreservedSurface.contains(mWin)) {
+            mService.mDestroyPreservedSurface.add(mWin);
+        }
+    }
+
     WindowSurfaceController createSurfaceLocked() {
         final WindowState w = mWin;
         if (w.hasSavedSurface()) {
@@ -680,8 +681,7 @@
         mDrawState = DRAW_PENDING;
         if (w.mAppToken != null) {
             if (w.mAppToken.mAppAnimator.animation == null) {
-                w.mAppToken.allDrawn = false;
-                w.mAppToken.deferClearAllDrawn = false;
+                w.mAppToken.clearAllDrawn();
             } else {
                 // Currently animating, persist current state of allDrawn until animation
                 // is complete.
@@ -833,20 +833,19 @@
     }
 
     boolean hasSurface() {
-        return !mWin.mSurfaceSaved
+        return !mWin.hasSavedSurface()
                 && mSurfaceController != null && mSurfaceController.hasSurface();
     }
 
     void destroySurfaceLocked() {
         final AppWindowToken wtoken = mWin.mAppToken;
         if (wtoken != null) {
-            wtoken.mAnimatingWithSavedSurface = false;
             if (mWin == wtoken.startingWindow) {
                 wtoken.startingDisplayed = false;
             }
         }
 
-        mWin.mSurfaceSaved = false;
+        mWin.clearHasSavedSurface();
 
         if (mSurfaceController == null) {
             return;
@@ -1518,9 +1517,7 @@
 
             if (prepared && mLastHidden && mDrawState == HAS_DRAWN) {
                 if (showSurfaceRobustlyLocked()) {
-                    if (mDestroyPreservedSurfaceUponRedraw) {
-                        mService.mDestroyPreservedSurface.add(mWin);
-                    }
+                    markPreservedSurfaceForDestroy();
                     mAnimator.requestRemovalOfReplacedWindows(w);
                     mLastHidden = false;
                     if (mIsWallpaper) {
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
index cff5876..21560ac 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
@@ -56,7 +56,7 @@
 import com.android.server.net.NetworkStatsServiceTest.LatchedHandler;
 
 import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Objects;
 import java.util.List;
 
 import junit.framework.TestCase;
@@ -91,7 +91,6 @@
     private static final long BASE_BYTES = 7 * MB_IN_BYTES;
     private static final int INVALID_TYPE = -1;
 
-    private static final int[] NO_UIDS = null;
     private static final VpnInfo[] VPN_INFO = new VpnInfo[0];
 
     private long mElapsedRealtime;
@@ -134,112 +133,60 @@
 
     public void testRegister_thresholdTooLow_setsDefaultThreshold() throws Exception {
         long thresholdTooLowBytes = 1L;
-        NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateWifi };
         DataUsageRequest inputRequest = new DataUsageRequest(
-                DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, thresholdTooLowBytes);
+                DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, thresholdTooLowBytes);
 
         DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
                 Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
         assertTrue(request.requestId > 0);
-        assertTrue(Arrays.deepEquals(templates, request.templates));
-        assertNull(request.uids);
+        assertTrue(Objects.equals(sTemplateWifi, request.template));
         assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
     }
 
     public void testRegister_highThreshold_accepted() throws Exception {
         long highThresholdBytes = 2 * THRESHOLD_BYTES;
-        NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateWifi };
         DataUsageRequest inputRequest = new DataUsageRequest(
-                DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, highThresholdBytes);
+                DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, highThresholdBytes);
 
         DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
                 Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
         assertTrue(request.requestId > 0);
-        assertTrue(Arrays.deepEquals(templates, request.templates));
-        assertNull(request.uids);
+        assertTrue(Objects.equals(sTemplateWifi, request.template));
         assertEquals(highThresholdBytes, request.thresholdInBytes);
     }
 
     public void testRegister_twoRequests_twoIds() throws Exception {
-        NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateWifi };
         DataUsageRequest inputRequest = new DataUsageRequest(
-                DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+                DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, THRESHOLD_BYTES);
 
         DataUsageRequest request1 = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
                 Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
         assertTrue(request1.requestId > 0);
-        assertTrue(Arrays.deepEquals(templates, request1.templates));
-        assertNull(request1.uids);
+        assertTrue(Objects.equals(sTemplateWifi, request1.template));
         assertEquals(THRESHOLD_BYTES, request1.thresholdInBytes);
 
         DataUsageRequest request2 = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
                 Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
         assertTrue(request2.requestId > request1.requestId);
-        assertTrue(Arrays.deepEquals(templates, request2.templates));
-        assertNull(request2.uids);
+        assertTrue(Objects.equals(sTemplateWifi, request2.template));
         assertEquals(THRESHOLD_BYTES, request2.thresholdInBytes);
     }
 
-    public void testRegister_defaultAccess_otherUids_securityException() throws Exception {
-        NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
-        int[] uids = new int[] { UID_RED, UID_BLUE, UID_GREEN };
-        DataUsageRequest inputRequest = new DataUsageRequest(
-                DataUsageRequest.REQUEST_ID_UNSET, templates, uids, THRESHOLD_BYTES);
-
-        try {
-            mStatsObservers.register(inputRequest, mMessenger, mockBinder, UID_RED,
-                    NetworkStatsAccess.Level.DEFAULT);
-            fail("Should have denied access");
-        } catch (SecurityException expected) {}
-    }
-
-    public void testRegister_userAccess_otherUidsSameUser()
-            throws Exception {
-        NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
-        int[] uids = new int[] { UID_RED, UID_BLUE, UID_GREEN };
-        DataUsageRequest inputRequest = new DataUsageRequest(
-                DataUsageRequest.REQUEST_ID_UNSET, templates, uids, THRESHOLD_BYTES);
-
-        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
-                UID_RED, NetworkStatsAccess.Level.USER);
-        assertTrue(request.requestId > 0);
-        assertTrue(Arrays.deepEquals(templates, request.templates));
-        assertTrue(Arrays.equals(uids, request.uids));
-        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
-    }
-
-    public void testRegister_defaultAccess_sameUid() throws Exception {
-        NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
-        int[] uids = new int[] { UID_RED };
-        DataUsageRequest inputRequest = new DataUsageRequest(
-                DataUsageRequest.REQUEST_ID_UNSET, templates, uids, THRESHOLD_BYTES);
-
-        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
-                UID_RED, NetworkStatsAccess.Level.DEFAULT);
-        assertTrue(request.requestId > 0);
-        assertTrue(Arrays.deepEquals(templates, request.templates));
-        assertTrue(Arrays.equals(uids, request.uids));
-        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
-    }
-
     public void testUnregister_unknownRequest_noop() throws Exception {
-        NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateWifi };
         DataUsageRequest unknownRequest = new DataUsageRequest(
-                123456 /* id */, templates, NO_UIDS, THRESHOLD_BYTES);
+                123456 /* id */, sTemplateWifi, THRESHOLD_BYTES);
 
         mStatsObservers.unregister(unknownRequest, UID_RED);
     }
 
     public void testUnregister_knownRequest_releasesCaller() throws Exception {
-        NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
         DataUsageRequest inputRequest = new DataUsageRequest(
-                DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
 
         DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
                 Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
         assertTrue(request.requestId > 0);
-        assertTrue(Arrays.deepEquals(templates, request.templates));
-        assertNull(request.uids);
+        assertTrue(Objects.equals(sTemplateImsi1, request.template));
         assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
         Mockito.verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
 
@@ -250,15 +197,13 @@
     }
 
     public void testUnregister_knownRequest_invalidUid_doesNotUnregister() throws Exception {
-        NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
         DataUsageRequest inputRequest = new DataUsageRequest(
-                DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
 
         DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
                 UID_RED, NetworkStatsAccess.Level.DEVICE);
         assertTrue(request.requestId > 0);
-        assertTrue(Arrays.deepEquals(templates, request.templates));
-        assertNull(request.uids);
+        assertTrue(Objects.equals(sTemplateImsi1, request.template));
         assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
         Mockito.verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
 
@@ -269,15 +214,13 @@
     }
 
     public void testUpdateStats_initialSample_doesNotNotify() throws Exception {
-        NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
         DataUsageRequest inputRequest = new DataUsageRequest(
-                DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
 
         DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
                 Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
         assertTrue(request.requestId > 0);
-        assertTrue(Arrays.deepEquals(templates, request.templates));
-        assertNull(request.uids);
+        assertTrue(Objects.equals(sTemplateImsi1, request.template));
         assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
 
         NetworkIdentitySet identSet = new NetworkIdentitySet();
@@ -301,15 +244,13 @@
     }
 
     public void testUpdateStats_belowThreshold_doesNotNotify() throws Exception {
-        NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
         DataUsageRequest inputRequest = new DataUsageRequest(
-                DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
 
         DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
                 Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
         assertTrue(request.requestId > 0);
-        assertTrue(Arrays.deepEquals(templates, request.templates));
-        assertNull(request.uids);
+        assertTrue(Objects.equals(sTemplateImsi1, request.template));
         assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
 
         NetworkIdentitySet identSet = new NetworkIdentitySet();
@@ -339,16 +280,14 @@
         assertEquals(INVALID_TYPE, mHandler.mLastMessageType);
     }
 
-    public void testUpdateStats_aboveThresholdNetwork_notifies() throws Exception {
-        NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+    public void testUpdateStats_deviceAccess_notifies() throws Exception {
         DataUsageRequest inputRequest = new DataUsageRequest(
-                DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
 
         DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
                 Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
         assertTrue(request.requestId > 0);
-        assertTrue(Arrays.deepEquals(templates, request.templates));
-        assertNull(request.uids);
+        assertTrue(Objects.equals(sTemplateImsi1, request.template));
         assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
 
         NetworkIdentitySet identSet = new NetworkIdentitySet();
@@ -378,104 +317,14 @@
         assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
     }
 
-    public void testUpdateStats_aboveThresholdMultipleNetwork_notifies() throws Exception {
-        NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1, sTemplateImsi2 };
+    public void testUpdateStats_defaultAccess_notifiesSameUid() throws Exception {
         DataUsageRequest inputRequest = new DataUsageRequest(
-                DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
-
-        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
-                UID_RED, NetworkStatsAccess.Level.DEVICESUMMARY);
-        assertTrue(request.requestId > 0);
-        assertTrue(Arrays.deepEquals(templates, request.templates));
-        assertNull(request.uids);
-        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
-
-        NetworkIdentitySet identSet1 = new NetworkIdentitySet();
-        identSet1.add(new NetworkIdentity(
-                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
-                IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
-        mActiveIfaces.put(TEST_IFACE, identSet1);
-
-        NetworkIdentitySet identSet2 = new NetworkIdentitySet();
-        identSet2.add(new NetworkIdentity(
-                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
-                IMSI_2, null /* networkId */, false /* roaming */, true /* metered */));
-        mActiveIfaces.put(TEST_IFACE2, identSet2);
-
-        // Baseline
-        NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
-                .addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L)
-                .addIfaceValues(TEST_IFACE2, BASE_BYTES + 1234L, 18L, BASE_BYTES, 12L);
-        NetworkStats uidSnapshot = null;
-        mStatsObservers.updateStats(
-                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
-                VPN_INFO, TEST_START);
-
-        // Delta - traffic on IMSI2
-        xtSnapshot = new NetworkStats(TEST_START + MINUTE_IN_MILLIS, 1 /* initialSize */)
-                .addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L)
-                .addIfaceValues(TEST_IFACE2, BASE_BYTES + THRESHOLD_BYTES, 22L,
-                        BASE_BYTES + THRESHOLD_BYTES, 24L);
-        mStatsObservers.updateStats(
-                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
-                VPN_INFO, TEST_START);
-        waitForObserverToIdle();
-
-        assertTrue(mCv.block(WAIT_TIMEOUT));
-        assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
-    }
-
-    public void testUpdateStats_aboveThresholdUid_notifies() throws Exception {
-        NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
-        int[] uids = new int[] { UID_RED, UID_BLUE, UID_GREEN };
-        DataUsageRequest inputRequest = new DataUsageRequest(
-                DataUsageRequest.REQUEST_ID_UNSET, templates, uids, THRESHOLD_BYTES);
-
-        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
-                Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
-        assertTrue(request.requestId > 0);
-        assertTrue(Arrays.deepEquals(templates, request.templates));
-        assertTrue(Arrays.equals(uids,request.uids));
-        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
-
-        NetworkIdentitySet identSet = new NetworkIdentitySet();
-        identSet.add(new NetworkIdentity(
-                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
-                IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
-        mActiveUidIfaces.put(TEST_IFACE, identSet);
-
-        // Baseline
-        NetworkStats xtSnapshot = null;
-        NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
-                        BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
-        mStatsObservers.updateStats(
-                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
-                VPN_INFO, TEST_START);
-
-        // Delta
-        uidSnapshot = new NetworkStats(TEST_START+ 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
-                        BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
-        mStatsObservers.updateStats(
-                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
-                VPN_INFO, TEST_START);
-        waitForObserverToIdle();
-
-        assertTrue(mCv.block(WAIT_TIMEOUT));
-        assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
-    }
-
-    public void testUpdateStats_defaultAccess_noUid_notifiesSameUid() throws Exception {
-        NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
-        DataUsageRequest inputRequest = new DataUsageRequest(
-                DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
 
         DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
                 UID_RED, NetworkStatsAccess.Level.DEFAULT);
         assertTrue(request.requestId > 0);
-        assertTrue(Arrays.deepEquals(templates, request.templates));
-        assertNull(request.uids);
+        assertTrue(Objects.equals(sTemplateImsi1, request.template));
         assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
 
         NetworkIdentitySet identSet = new NetworkIdentitySet();
@@ -494,7 +343,7 @@
                 VPN_INFO, TEST_START);
 
         // Delta
-        uidSnapshot = new NetworkStats(TEST_START+ 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
+        uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
                         BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
         mStatsObservers.updateStats(
@@ -506,16 +355,14 @@
         assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
     }
 
-    public void testUpdateStats_defaultAccess_noUid_usageOtherUid_doesNotNotify() throws Exception {
-        NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+    public void testUpdateStats_defaultAccess_usageOtherUid_doesNotNotify() throws Exception {
         DataUsageRequest inputRequest = new DataUsageRequest(
-                DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
 
         DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
                 UID_BLUE, NetworkStatsAccess.Level.DEFAULT);
         assertTrue(request.requestId > 0);
-        assertTrue(Arrays.deepEquals(templates, request.templates));
-        assertNull(request.uids);
+        assertTrue(Objects.equals(sTemplateImsi1, request.template));
         assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
 
         NetworkIdentitySet identSet = new NetworkIdentitySet();
@@ -534,7 +381,7 @@
                 VPN_INFO, TEST_START);
 
         // Delta
-        uidSnapshot = new NetworkStats(TEST_START+ 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
+        uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
                         BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
         mStatsObservers.updateStats(
@@ -547,15 +394,13 @@
     }
 
     public void testUpdateStats_userAccess_usageSameUser_notifies() throws Exception {
-        NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
         DataUsageRequest inputRequest = new DataUsageRequest(
-                DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
 
         DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
                 UID_BLUE, NetworkStatsAccess.Level.USER);
         assertTrue(request.requestId > 0);
-        assertTrue(Arrays.deepEquals(templates, request.templates));
-        assertNull(request.uids);
+        assertTrue(Objects.equals(sTemplateImsi1, request.template));
         assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
 
         NetworkIdentitySet identSet = new NetworkIdentitySet();
@@ -574,7 +419,7 @@
                 VPN_INFO, TEST_START);
 
         // Delta
-        uidSnapshot = new NetworkStats(TEST_START+ 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
+        uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
                         BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
         mStatsObservers.updateStats(
@@ -587,15 +432,13 @@
     }
 
     public void testUpdateStats_userAccess_usageAnotherUser_doesNotNotify() throws Exception {
-        NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
         DataUsageRequest inputRequest = new DataUsageRequest(
-                DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
 
         DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
                 UID_RED, NetworkStatsAccess.Level.USER);
         assertTrue(request.requestId > 0);
-        assertTrue(Arrays.deepEquals(templates, request.templates));
-        assertNull(request.uids);
+        assertTrue(Objects.equals(sTemplateImsi1, request.template));
         assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
 
         NetworkIdentitySet identSet = new NetworkIdentitySet();
@@ -614,7 +457,7 @@
                 VPN_INFO, TEST_START);
 
         // Delta
-        uidSnapshot = new NetworkStats(TEST_START+ 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
+        uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
                 .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, ROAMING_NO,
                         BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
         mStatsObservers.updateStats(
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
index 74c1984..94c6711 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
@@ -100,7 +100,7 @@
 
 import java.io.File;
 import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Objects;
 import java.util.List;
 
 /**
@@ -887,7 +887,7 @@
 
     }
 
-    public void testRegisterDataUsageCallback_network() throws Exception {
+    public void testRegisterUsageCallback() throws Exception {
         // pretend that wifi network comes online; service should ask about full
         // network state, and poll any existing interfaces before updating.
         expectCurrentTime();
@@ -907,9 +907,8 @@
 
         String callingPackage = "the.calling.package";
         long thresholdInBytes = 1L;  // very small; should be overriden by framework
-        NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateWifi };
         DataUsageRequest inputRequest = new DataUsageRequest(
-                DataUsageRequest.REQUEST_ID_UNSET, templates, null /* uids */, thresholdInBytes);
+                DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, thresholdInBytes);
 
         // Create a messenger that waits for callback activity
         ConditionVariable cv = new ConditionVariable(false);
@@ -931,11 +930,10 @@
 
         // Register and verify request and that binder was called
         DataUsageRequest request =
-                mService.registerDataUsageCallback(callingPackage, inputRequest,
+                mService.registerUsageCallback(callingPackage, inputRequest,
                         messenger, mockBinder);
         assertTrue(request.requestId > 0);
-        assertTrue(Arrays.deepEquals(templates, request.templates));
-        assertNull(request.uids);
+        assertTrue(Objects.equals(sTemplateWifi, request.template));
         long minThresholdInBytes = 2 * 1024 * 1024; // 2 MB
         assertEquals(minThresholdInBytes, request.thresholdInBytes);
 
@@ -997,7 +995,7 @@
         EasyMock.replay(mockBinder);
 
         // Unregister request
-        mService.unregisterDataUsageRequest(request);
+        mService.unregisterUsageRequest(request);
 
         // Wait for the caller to ack receipt of CALLBACK_RELEASED
         assertTrue(cv.block(WAIT_TIMEOUT));
@@ -1007,157 +1005,13 @@
         EasyMock.verify(mockBinder);
     }
 
-    public void testRegisterDataUsageCallback_uids() throws Exception {
-        // pretend that network comes online
-        expectCurrentTime();
-        expectDefaultSettings();
-        expectNetworkState(buildMobile3gState(IMSI_1, true /* isRoaming */));
-        expectNetworkStatsSummary(buildEmptyStats());
-        expectNetworkStatsUidDetail(buildEmptyStats());
-        expectNetworkStatsPoll();
-        expectBandwidthControlCheck();
-
-        replay();
-        mService.forceUpdateIfaces();
-        verifyAndReset();
-
+    public void testUnregisterUsageCallback_unknown_noop() throws Exception {
         String callingPackage = "the.calling.package";
         long thresholdInBytes = 10 * 1024 * 1024;  // 10 MB
-        NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1, sTemplateImsi2 };
-        int[] uids = new int[] { UID_RED };
-        DataUsageRequest inputRequest = new DataUsageRequest(
-                DataUsageRequest.REQUEST_ID_UNSET, templates, uids, thresholdInBytes);
-
-        // Create a messenger that waits for callback activity
-        ConditionVariable cv = new ConditionVariable(false);
-        cv.close();
-        LatchedHandler latchedHandler = new LatchedHandler(Looper.getMainLooper(), cv);
-        Messenger messenger = new Messenger(latchedHandler);
-
-        // Allow binder to connect
-        IBinder mockBinder = createMock(IBinder.class);
-        mockBinder.linkToDeath((IBinder.DeathRecipient) anyObject(), anyInt());
-        EasyMock.replay(mockBinder);
-
-        // Force poll
-        expectCurrentTime();
-        expectDefaultSettings();
-        expectNetworkStatsSummary(buildEmptyStats());
-        expectNetworkStatsUidDetail(buildEmptyStats());
-        expectNetworkStatsPoll();
-        replay();
-
-        // Register and verify request and that binder was called
-        DataUsageRequest request =
-                mService.registerDataUsageCallback(callingPackage, inputRequest,
-                        messenger, mockBinder);
-        assertTrue(request.requestId > 0);
-        assertTrue(Arrays.deepEquals(templates, request.templates));
-        assertTrue(Arrays.equals(uids, request.uids));
-        assertEquals(thresholdInBytes, request.thresholdInBytes);
-
-        // Wait for service to handle internal MSG_REGISTER_DATA_USAGE_LISTENER
-        mHandler.sendMessage(mHandler.obtainMessage(-1));
-        mHandlerThread.waitForIdle(WAIT_TIMEOUT);
-
-        verifyAndReset();
-
-        // Make sure that the caller binder gets connected
-        EasyMock.verify(mockBinder);
-        EasyMock.reset(mockBinder);
-
-        // modify some number on mobile interface, and trigger poll event
-        // not enough traffic to call data usage callback
-        incrementCurrentTime(HOUR_IN_MILLIS);
-        expectCurrentTime();
-        expectDefaultSettings();
-        expectNetworkStatsSummary(buildEmptyStats());
-        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO, 128L, 2L,
-                        128L, 2L, 0L)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 1L, 64L,
-                        1L, 0L));
-        expectNetworkStatsPoll();
-
-        replay();
-        forcePollAndWaitForIdle();
-
-        // verify service recorded history
-        assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 0);
-
-        // verify entire history present
-        NetworkStats stats = mSession.getSummaryForAllUid(
-                sTemplateImsi1, Long.MIN_VALUE, Long.MAX_VALUE, true);
-        assertEquals(2, stats.size());
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_YES, 128L, 2L,
-                128L, 2L, 0);
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_YES, 64L, 1L, 64L,
-                1L, 0);
-
-        verifyAndReset();
-
-        // make sure callback has not being called
-        assertEquals(INVALID_TYPE, latchedHandler.mLastMessageType);
-
-        // and bump forward again, with counters going higher. this is
-        // important, since it will trigger the data usage callback
-        incrementCurrentTime(DAY_IN_MILLIS);
-        expectCurrentTime();
-        expectDefaultSettings();
-        expectNetworkStatsSummary(buildEmptyStats());
-        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_NO,
-                        128000000L, 2L, 128000000L, 2L, 0L)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_NO,
-                        64000000L, 1L, 64000000L, 1L, 0L));
-        expectNetworkStatsPoll();
-
-        replay();
-        forcePollAndWaitForIdle();
-
-        // verify service recorded history
-        assertUidTotal(sTemplateImsi1, UID_RED, 128000000L, 2L, 128000000L, 2L, 0);
-
-        // verify entire history present
-        stats = mSession.getSummaryForAllUid(
-                sTemplateImsi1, Long.MIN_VALUE, Long.MAX_VALUE, true);
-        assertEquals(2, stats.size());
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_YES,
-                128000000L, 2L, 128000000L, 2L, 0);
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_YES,
-                64000000L, 1L, 64000000L, 1L, 0);
-
-        verifyAndReset();
-
-        // Wait for the caller to ack receipt of CALLBACK_LIMIT_REACHED
-        assertTrue(cv.block(WAIT_TIMEOUT));
-        assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, latchedHandler.mLastMessageType);
-        cv.close();
-
-        // Allow binder to disconnect
-        expect(mockBinder.unlinkToDeath((IBinder.DeathRecipient) anyObject(), anyInt()))
-                .andReturn(true);
-        EasyMock.replay(mockBinder);
-
-        // Unregister request
-        mService.unregisterDataUsageRequest(request);
-
-        // Wait for the caller to ack receipt of CALLBACK_RELEASED
-        assertTrue(cv.block(WAIT_TIMEOUT));
-        assertEquals(NetworkStatsManager.CALLBACK_RELEASED, latchedHandler.mLastMessageType);
-
-        // Make sure that the caller binder gets disconnected
-        EasyMock.verify(mockBinder);
-    }
-
-    public void testUnregisterDataUsageCallback_unknown_noop() throws Exception {
-        String callingPackage = "the.calling.package";
-        long thresholdInBytes = 10 * 1024 * 1024;  // 10 MB
-        NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1, sTemplateImsi2 };
         DataUsageRequest unknownRequest = new DataUsageRequest(
-                2, templates, null /* uids */, thresholdInBytes);
+                2 /* requestId */, sTemplateImsi1, thresholdInBytes);
 
-        mService.unregisterDataUsageRequest(unknownRequest);
+        mService.unregisterUsageRequest(unknownRequest);
     }
 
     private static File getBaseDir(File statsDir) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 855a5c4..0694911 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -260,7 +260,8 @@
                             receiverExtras.putInt(KEY_RECEIVER_EXTRA_INDEX, i);
                             receiverExtras.putInt(KEY_RECEIVER_EXTRA_COUNT, count);
                             if (mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL,
-                                    mAssistReceiver, receiverExtras, topActivity, i == 0)) {
+                                    mAssistReceiver, receiverExtras, topActivity,
+                                    /* focused= */ i == 0, /* newSessionId= */ i == 0)) {
                                 needDisclosure = true;
                                 mPendingAssistDataCount++;
                             } else if (i == 0) {
diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
index 7b4f01c..95bbb21 100644
--- a/tests/UiBench/AndroidManifest.xml
+++ b/tests/UiBench/AndroidManifest.xml
@@ -161,5 +161,16 @@
                 <category android:name="com.android.test.uibench.TEST" />
             </intent-filter>
         </activity>
+
+        <!-- WebView -->
+        <activity
+                android:name=".ScrollableWebViewActivity"
+                android:label="WebView/Scrollable WebView" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+
     </application>
 </manifest>
diff --git a/tests/UiBench/src/com/android/test/uibench/ScrollableWebViewActivity.java b/tests/UiBench/src/com/android/test/uibench/ScrollableWebViewActivity.java
new file mode 100644
index 0000000..02c2a08
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/ScrollableWebViewActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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.test.uibench;
+
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.webkit.WebView;
+
+public class ScrollableWebViewActivity extends AppCompatActivity {
+    static String sHtml = "<body style=\"height:10000px;"
+             + "background:repeating-linear-gradient(white, black 10%)\"/>";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        WebView webView = new WebView(this);
+        webView.loadData(sHtml, "text/html", null);
+        webView.setVerticalScrollBarEnabled(true);
+        setContentView(webView);
+    }
+}
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index fe7c3b9..ea36e2c 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -412,8 +412,9 @@
         path.join(ucd_path, 'emoji-zwj-sequences.txt'))
 
     # filter modern pentathlon, as it seems likely to be removed from final spec
+    # also filter rifle
     def is_excluded(n):
-        return n == 0x1f93b
+        return n in [0x1f93b, 0x1f946]
 
     def contains_excluded(t):
         if type(t) == int: