Merge "Accept null subtype in InputMethodSubtypeHandle." into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index 7fe5728..00a2b7a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -30330,7 +30330,7 @@
 
 package android.printservice {
 
-  public class CustomPrinterIconCallback {
+  public final class CustomPrinterIconCallback {
     method public boolean onCustomPrinterIconLoaded(android.graphics.drawable.Icon);
   }
 
diff --git a/api/system-current.txt b/api/system-current.txt
index dfaae6b..f017bb0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -26021,23 +26021,24 @@
   }
 
   public final class CaptivePortalStateChangeEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
-    ctor public CaptivePortalStateChangeEvent(int);
+    ctor public CaptivePortalStateChangeEvent(int, int);
     ctor public CaptivePortalStateChangeEvent(android.os.Parcel);
     method public int describeContents();
-    method public static void logEvent(int);
+    method public static void logEvent(int, int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.metrics.CaptivePortalStateChangeEvent> CREATOR;
     field public static final int NETWORK_MONITOR_CONNECTED = 0; // 0x0
     field public static final int NETWORK_MONITOR_DISCONNECTED = 1; // 0x1
     field public static final int NETWORK_MONITOR_VALIDATED = 2; // 0x2
+    field public final int netId;
     field public final int state;
   }
 
-  public final class ConnectivityServiceChangeEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
+  public final class DefaultNetworkEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
     method public int describeContents();
     method public static void logEvent(int, int[], int, boolean, boolean);
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.net.metrics.ConnectivityServiceChangeEvent> CREATOR;
+    field public static final android.os.Parcelable.Creator<android.net.metrics.DefaultNetworkEvent> CREATOR;
     field public final int netId;
     field public final boolean prevIPv4;
     field public final boolean prevIPv6;
@@ -26111,12 +26112,16 @@
     field public static final int IPCE_IPMGR_PROVISIONING_FAIL = 4097; // 0x1001
     field public static final int IPCE_IPMGR_PROVISIONING_OK = 4096; // 0x1000
     field public static final int IPCE_IPRM_BASE = 0; // 0x0
-    field public static final int IPCE_IPRM_MESSAGE_RECEIVED = 1; // 0x1
-    field public static final int IPCE_IPRM_PROBE_RESULT = 0; // 0x0
-    field public static final int IPCE_IPRM_REACHABILITY_LOST = 2; // 0x2
+    field public static final int IPCE_IPRM_NUD_FAILED = 2; // 0x2
+    field public static final int IPCE_IPRM_PROBE_FAILURE = 1; // 0x1
+    field public static final int IPCE_IPRM_PROBE_STARTED = 0; // 0x0
+    field public static final int IPCE_IPRM_PROVISIONING_LOST = 3; // 0x3
     field public static final int IPCE_NETMON_BASE = 2048; // 0x800
+    field public static final int IPCE_NETMON_CAPPORT_FOUND = 2052; // 0x804
     field public static final int IPCE_NETMON_CHECK_RESULT = 2049; // 0x801
+    field public static final int IPCE_NETMON_PORTAL_PROBE = 2051; // 0x803
     field public static final int IPCE_NETMON_STATE_CHANGE = 2048; // 0x800
+    field public static final int IPCE_NETMON_VALIDATED = 2050; // 0x802
   }
 
   public final class IpManagerEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
@@ -26128,33 +26133,31 @@
     field public final java.lang.String ifName;
   }
 
-  public final class IpReachabilityMonitorLostEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
+  public final class IpReachabilityEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
     method public int describeContents();
-    method public static void logEvent(java.lang.String);
+    method public static void logNudFailed(java.lang.String);
+    method public static void logProbeEvent(java.lang.String, int);
+    method public static void logProvisioningLost(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.net.metrics.IpReachabilityMonitorLostEvent> CREATOR;
+    field public static final android.os.Parcelable.Creator<android.net.metrics.IpReachabilityEvent> CREATOR;
+    field public static final int NUD_FAILED = 512; // 0x200
+    field public static final int PROBE = 256; // 0x100
+    field public static final int PROVISIONING_LOST = 768; // 0x300
+    field public final int eventType;
     field public final java.lang.String ifName;
   }
 
-  public final class IpReachabilityMonitorMessageEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
+  public final class NetworkMonitorEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
+    ctor public NetworkMonitorEvent(android.os.Parcel);
     method public int describeContents();
-    method public static void logEvent(java.lang.String, java.lang.String, int, int);
+    method public static void logCaptivePortalFound(int, long);
+    method public static void logPortalProbeEvent(int, long, int);
+    method public static void logValidated(int, long);
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.net.metrics.IpReachabilityMonitorMessageEvent> CREATOR;
-    field public final java.lang.String destination;
-    field public final java.lang.String ifName;
-    field public final int msgType;
-    field public final int nudState;
-  }
-
-  public final class IpReachabilityMonitorProbeEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
-    method public int describeContents();
-    method public static void logEvent(java.lang.String, java.lang.String, boolean);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.net.metrics.IpReachabilityMonitorProbeEvent> CREATOR;
-    field public final java.lang.String destination;
-    field public final java.lang.String ifName;
-    field public final boolean success;
+    field public static final android.os.Parcelable.Creator<android.net.metrics.NetworkMonitorEvent> CREATOR;
+    field public final long durationMs;
+    field public final int netId;
+    field public final int returnCode;
   }
 
 }
@@ -32829,7 +32832,7 @@
 
 package android.printservice {
 
-  public class CustomPrinterIconCallback {
+  public final class CustomPrinterIconCallback {
     method public boolean onCustomPrinterIconLoaded(android.graphics.drawable.Icon);
   }
 
diff --git a/api/test-current.txt b/api/test-current.txt
index 88031cf..d5ecfd1 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -30402,7 +30402,7 @@
 
 package android.printservice {
 
-  public class CustomPrinterIconCallback {
+  public final class CustomPrinterIconCallback {
     method public boolean onCustomPrinterIconLoaded(android.graphics.drawable.Icon);
   }
 
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 424d355..2f7c550 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -126,6 +126,19 @@
     public static final String META_HOME_ALTERNATE = "android.app.home.alternate";
 
     /**
+     * Result for IActivityManager.startVoiceActivity: active session is currently hidden.
+     * @hide
+     */
+    public static final int START_VOICE_HIDDEN_SESSION = -10;
+
+    /**
+     * Result for IActivityManager.startVoiceActivity: active session does not match
+     * the requesting token.
+     * @hide
+     */
+    public static final int START_VOICE_NOT_ACTIVE_SESSION = -9;
+
+    /**
      * Result for IActivityManager.startActivity: trying to start a background user
      * activity that shouldn't be displayed for all users.
      * @hide
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index ae2ca84..a3f3b2b3 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2959,6 +2959,13 @@
             reply.writeNoException();
             return true;
         }
+        case START_CONFIRM_DEVICE_CREDENTIAL_INTENT: {
+            data.enforceInterface(IActivityManager.descriptor);
+            final Intent intent = Intent.CREATOR.createFromParcel(data);
+            startConfirmDeviceCredentialIntent(intent);
+            reply.writeNoException();
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -6931,5 +6938,16 @@
         reply.recycle();
     }
 
+    public void startConfirmDeviceCredentialIntent(Intent intent) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        intent.writeToParcel(data, 0);
+        mRemote.transact(START_CONFIRM_DEVICE_CREDENTIAL_INTENT, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index b28b5e6..66b4fcf 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -649,6 +649,8 @@
 
     public void notifyLockedProfile(@UserIdInt int userId) throws RemoteException;
 
+    public void startConfirmDeviceCredentialIntent(Intent intent) throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -1032,4 +1034,5 @@
     int IS_VR_PACKAGE_ENABLED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 371;
     int SWAP_DOCKED_AND_FULLSCREEN_STACK = IBinder.FIRST_CALL_TRANSACTION + 372;
     int NOTIFY_LOCKED_PROFILE = IBinder.FIRST_CALL_TRANSACTION + 373;
+    int START_CONFIRM_DEVICE_CREDENTIAL_INTENT = IBinder.FIRST_CALL_TRANSACTION + 374;
 }
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 2fc6533..a42aed6 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -43,7 +43,8 @@
      * new wallpaper content is ready to display.
      */
     ParcelFileDescriptor setWallpaper(String name, in String callingPackage,
-            in Rect cropHint, out Bundle extras, int which, IWallpaperManagerCallback completion);
+            in Rect cropHint, boolean allowBackup, out Bundle extras, int which,
+            IWallpaperManagerCallback completion);
 
     /**
      * Set the live wallpaper. This only affects the system wallpaper.
@@ -125,6 +126,11 @@
     boolean isWallpaperSettingAllowed(in String callingPackage);
 
     /*
+     * Backup: is the current system wallpaper image eligible for off-device backup?
+     */
+    boolean isWallpaperBackupEligible(int userId);
+
+    /*
      * Keyguard: register a callback for being notified that lock-state relevant
      * wallpaper content has changed.
      */
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 4fca69a..95ea2a5 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1797,7 +1797,7 @@
         if (res >= ActivityManager.START_SUCCESS) {
             return;
         }
-        
+
         switch (res) {
             case ActivityManager.START_INTENT_NOT_RESOLVED:
             case ActivityManager.START_CLASS_NOT_FOUND:
@@ -1820,6 +1820,15 @@
             case ActivityManager.START_NOT_VOICE_COMPATIBLE:
                 throw new SecurityException(
                         "Starting under voice control not allowed for: " + intent);
+            case ActivityManager.START_VOICE_NOT_ACTIVE_SESSION:
+                throw new IllegalStateException(
+                        "Session calling startVoiceActivity does not match active session");
+            case ActivityManager.START_VOICE_HIDDEN_SESSION:
+                throw new IllegalStateException(
+                        "Cannot start voice activity on a hidden session");
+            case ActivityManager.START_CANCELED:
+                throw new AndroidRuntimeException("Activity could not be started for "
+                        + intent);
             default:
                 throw new AndroidRuntimeException("Unknown error code "
                         + res + " when starting " + intent);
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index aef92cf..d8a3d4f 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -224,7 +224,7 @@
      * @return a new AssetManager.
     */
     @VisibleForTesting
-    protected AssetManager createAssetManager(@NonNull final ResourcesKey key) {
+    protected @NonNull AssetManager createAssetManager(@NonNull final ResourcesKey key) {
         AssetManager assets = new AssetManager();
 
         // resDir can be null if the 'android' package is creating a new Resources object.
@@ -232,14 +232,15 @@
         // already.
         if (key.mResDir != null) {
             if (assets.addAssetPath(key.mResDir) == 0) {
-                return null;
+                throw new IllegalArgumentException("failed to add asset path " + key.mResDir);
             }
         }
 
         if (key.mSplitResDirs != null) {
             for (final String splitResDir : key.mSplitResDirs) {
                 if (assets.addAssetPath(splitResDir) == 0) {
-                    return null;
+                    throw new IllegalArgumentException(
+                            "failed to add split asset path " + splitResDir);
                 }
             }
         }
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 72b9318..18a5593 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -1,5 +1,5 @@
 /*
-h * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2009 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.
@@ -875,7 +875,7 @@
             /* Set the wallpaper to the default values */
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(
                     "res:" + resources.getResourceName(resid),
-                    mContext.getOpPackageName(), null, result, which, completion);
+                    mContext.getOpPackageName(), null, false, result, which, completion);
             if (fd != null) {
                 FileOutputStream fos = null;
                 boolean ok = false;
@@ -985,7 +985,8 @@
         final WallpaperSetCompletion completion = new WallpaperSetCompletion();
         try {
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
-                    mContext.getOpPackageName(), visibleCropHint, result, which, completion);
+                    mContext.getOpPackageName(), visibleCropHint, allowBackup,
+                    result, which, completion);
             if (fd != null) {
                 FileOutputStream fos = null;
                 try {
@@ -1102,7 +1103,8 @@
         final WallpaperSetCompletion completion = new WallpaperSetCompletion();
         try {
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
-                    mContext.getOpPackageName(), visibleCropHint, result, which, completion);
+                    mContext.getOpPackageName(), visibleCropHint, allowBackup,
+                    result, which, completion);
             if (fd != null) {
                 FileOutputStream fos = null;
                 try {
@@ -1565,6 +1567,25 @@
         }
     }
 
+    /**
+     * Is the current system wallpaper eligible for backup?
+     *
+     * Only the OS itself may use this method.
+     * @hide
+     */
+    public boolean isWallpaperBackupEligible() {
+        if (sGlobals.mService == null) {
+            Log.w(TAG, "WallpaperService not running");
+            return false;
+        }
+        try {
+            return sGlobals.mService.isWallpaperBackupEligible(mContext.getUserId());
+        } catch (RemoteException e) {
+            Log.e(TAG, "Exception querying wallpaper backup eligibility: " + e.getMessage());
+        }
+        return false;
+    }
+
     // Private completion callback for setWallpaper() synchronization
     private class WallpaperSetCompletion extends IWallpaperManagerCallback.Stub {
         final CountDownLatch mLatch;
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index c84a0dc..602d950 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -24,7 +24,7 @@
 import android.os.Parcelable;
 import android.os.PersistableBundle;
 import android.util.Log;
-import static android.util.TimeUtils.formatForLogging;
+import static android.util.TimeUtils.formatDuration;
 
 import java.util.ArrayList;
 
@@ -760,15 +760,27 @@
                         " setRequiresDeviceIdle is an error.");
             }
             JobInfo job = new JobInfo(this);
-            if (job.intervalMillis != job.getIntervalMillis()) {
-                Log.w(TAG, "Specified interval for " + mJobService.getPackageName() + " is "
-                        + formatForLogging(mIntervalMillis) + ". Clamped to " +
-                        formatForLogging(job.getIntervalMillis()));
-            }
-            if (job.flexMillis != job.getFlexMillis()) {
-                Log.w(TAG, "Specified interval for " + mJobService.getPackageName() + " is "
-                        + formatForLogging(mFlexMillis) + ". Clamped to " +
-                        formatForLogging(job.getFlexMillis()));
+            if (job.isPeriodic()) {
+                if (job.intervalMillis != job.getIntervalMillis()) {
+                    StringBuilder builder = new StringBuilder();
+                    builder.append("Specified interval for ")
+                            .append(String.valueOf(mJobId))
+                            .append(" is ");
+                    formatDuration(mIntervalMillis, builder);
+                    builder.append(". Clamped to ");
+                    formatDuration(job.getIntervalMillis(), builder);
+                    Log.w(TAG, builder.toString());
+                }
+                if (job.flexMillis != job.getFlexMillis()) {
+                    StringBuilder builder = new StringBuilder();
+                    builder.append("Specified flex for ")
+                            .append(String.valueOf(mJobId))
+                            .append(" is ");
+                    formatDuration(mFlexMillis, builder);
+                    builder.append(". Clamped to ");
+                    formatDuration(job.getFlexMillis(), builder);
+                    Log.w(TAG, builder.toString());
+                }
             }
             return job;
         }
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 5573896..6736d34 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -628,7 +628,12 @@
      * close the camera further by unconfiguring and then firing {@code onClosed}.</p>
      */
     private void finishPendingSequence(int sequenceId) {
-        mSequenceDrainer.taskFinished(sequenceId);
+        try {
+            mSequenceDrainer.taskFinished(sequenceId);
+        } catch (IllegalStateException e) {
+            // Workaround for b/27870771
+            Log.w(TAG, e.getMessage());
+        }
     }
 
     private class SequenceDrainListener implements TaskDrainer.DrainListener {
diff --git a/core/java/android/net/metrics/CaptivePortalStateChangeEvent.java b/core/java/android/net/metrics/CaptivePortalStateChangeEvent.java
index aabd09b..a67589a 100644
--- a/core/java/android/net/metrics/CaptivePortalStateChangeEvent.java
+++ b/core/java/android/net/metrics/CaptivePortalStateChangeEvent.java
@@ -29,17 +29,21 @@
     public static final int NETWORK_MONITOR_DISCONNECTED = 1;
     public static final int NETWORK_MONITOR_VALIDATED    = 2;
 
+    public final int netId;
     public final int state;
 
-    public CaptivePortalStateChangeEvent(int state) {
+    public CaptivePortalStateChangeEvent(int netId, int state) {
+        this.netId = netId;
         this.state = state;
     }
 
     public CaptivePortalStateChangeEvent(Parcel in) {
+        netId = in.readInt();
         state = in.readInt();
     }
 
     public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(netId);
         out.writeInt(state);
     }
 
@@ -58,7 +62,7 @@
         }
     };
 
-    public static void logEvent(int state) {
-        logEvent(IPCE_NETMON_STATE_CHANGE, new CaptivePortalStateChangeEvent(state));
+    public static void logEvent(int netId, int state) {
+        logEvent(IPCE_NETMON_STATE_CHANGE, new CaptivePortalStateChangeEvent(netId, state));
     }
 };
diff --git a/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java b/core/java/android/net/metrics/DefaultNetworkEvent.java
similarity index 69%
rename from core/java/android/net/metrics/ConnectivityServiceChangeEvent.java
rename to core/java/android/net/metrics/DefaultNetworkEvent.java
index fce68bb..f3c357b 100644
--- a/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java
+++ b/core/java/android/net/metrics/DefaultNetworkEvent.java
@@ -24,8 +24,7 @@
  * {@hide}
  */
 @SystemApi
-public final class ConnectivityServiceChangeEvent extends IpConnectivityEvent
-        implements Parcelable {
+public final class DefaultNetworkEvent extends IpConnectivityEvent implements Parcelable {
     // The ID of the network that has become the new default or NETID_UNSET if none.
     public final int netId;
     // The list of transport types of the new default network, for example TRANSPORT_WIFI, as
@@ -37,7 +36,7 @@
     public final boolean prevIPv4;
     public final boolean prevIPv6;
 
-    private ConnectivityServiceChangeEvent(int netId, int[] transportTypes,
+    private DefaultNetworkEvent(int netId, int[] transportTypes,
                 int prevNetId, boolean prevIPv4, boolean prevIPv6) {
         this.netId = netId;
         this.transportTypes = transportTypes;
@@ -46,7 +45,7 @@
         this.prevIPv6 = prevIPv6;
     }
 
-    private ConnectivityServiceChangeEvent(Parcel in) {
+    private DefaultNetworkEvent(Parcel in) {
         this.netId = in.readInt();
         this.transportTypes = in.createIntArray();
         this.prevNetId = in.readInt();
@@ -66,21 +65,21 @@
         return 0;
     }
 
-    public static final Parcelable.Creator<ConnectivityServiceChangeEvent> CREATOR
-        = new Parcelable.Creator<ConnectivityServiceChangeEvent>() {
-        public ConnectivityServiceChangeEvent createFromParcel(Parcel in) {
-            return new ConnectivityServiceChangeEvent(in);
+    public static final Parcelable.Creator<DefaultNetworkEvent> CREATOR
+        = new Parcelable.Creator<DefaultNetworkEvent>() {
+        public DefaultNetworkEvent createFromParcel(Parcel in) {
+            return new DefaultNetworkEvent(in);
         }
 
-        public ConnectivityServiceChangeEvent[] newArray(int size) {
-            return new ConnectivityServiceChangeEvent[size];
+        public DefaultNetworkEvent[] newArray(int size) {
+            return new DefaultNetworkEvent[size];
         }
     };
 
-    public static void logEvent(int netId, int[] transportTypes,
-            int prevNetId, boolean prevIPv4, boolean prevIPv6) {
-        logEvent(IPCE_CONSRV_DEFAULT_NET_CHANGE,
-                new ConnectivityServiceChangeEvent(
-                        netId, transportTypes, prevNetId, prevIPv4, prevIPv6));
+    public static void logEvent(
+            int netId, int[] transports, int prevNetId, boolean hadIPv4, boolean hadIPv6) {
+        final DefaultNetworkEvent ev =
+                new DefaultNetworkEvent(netId, transports, prevNetId, hadIPv4, hadIPv6);
+        logEvent(IPCE_CONSRV_DEFAULT_NET_CHANGE, ev);
     }
 };
diff --git a/core/java/android/net/metrics/IpConnectivityEvent.java b/core/java/android/net/metrics/IpConnectivityEvent.java
index 2eb8edb..0b5e354 100644
--- a/core/java/android/net/metrics/IpConnectivityEvent.java
+++ b/core/java/android/net/metrics/IpConnectivityEvent.java
@@ -39,9 +39,10 @@
     public static final int IPCE_IPMGR_BASE                = 4 * 1024;
     public static final int IPCE_DNS_BASE                  = 5 * 1024;
 
-    public static final int IPCE_IPRM_PROBE_RESULT         = IPCE_IPRM_BASE + 0;
-    public static final int IPCE_IPRM_MESSAGE_RECEIVED     = IPCE_IPRM_BASE + 1;
-    public static final int IPCE_IPRM_REACHABILITY_LOST    = IPCE_IPRM_BASE + 2;
+    public static final int IPCE_IPRM_PROBE_STARTED        = IPCE_IPRM_BASE + 0;
+    public static final int IPCE_IPRM_PROBE_FAILURE        = IPCE_IPRM_BASE + 1;
+    public static final int IPCE_IPRM_NUD_FAILED           = IPCE_IPRM_BASE + 2;
+    public static final int IPCE_IPRM_PROVISIONING_LOST    = IPCE_IPRM_BASE + 3;
 
     public static final int IPCE_DHCP_RECV_ERROR           = IPCE_DHCP_BASE + 0;
     public static final int IPCE_DHCP_PARSE_ERROR          = IPCE_DHCP_BASE + 1;
@@ -49,6 +50,9 @@
 
     public static final int IPCE_NETMON_STATE_CHANGE       = IPCE_NETMON_BASE + 0;
     public static final int IPCE_NETMON_CHECK_RESULT       = IPCE_NETMON_BASE + 1;
+    public static final int IPCE_NETMON_VALIDATED          = IPCE_NETMON_BASE + 2;
+    public static final int IPCE_NETMON_PORTAL_PROBE       = IPCE_NETMON_BASE + 3;
+    public static final int IPCE_NETMON_CAPPORT_FOUND      = IPCE_NETMON_BASE + 4;
 
     public static final int IPCE_CONSRV_DEFAULT_NET_CHANGE = IPCE_CONSRV_BASE + 0;
 
diff --git a/core/java/android/net/metrics/IpReachabilityEvent.java b/core/java/android/net/metrics/IpReachabilityEvent.java
new file mode 100644
index 0000000..73dcb94
--- /dev/null
+++ b/core/java/android/net/metrics/IpReachabilityEvent.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.metrics;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+@SystemApi
+public final class IpReachabilityEvent extends IpConnectivityEvent implements Parcelable {
+
+    public static final int PROBE             = 1 << 8;
+    public static final int NUD_FAILED        = 2 << 8;
+    public static final int PROVISIONING_LOST = 3 << 8;
+
+    public final String ifName;
+    // eventType byte format (MSB to LSB):
+    // byte 0: unused
+    // byte 1: unused
+    // byte 2: type of event: PROBE, NUD_FAILED, PROVISIONING_LOST
+    // byte 3: kernel errno from RTNetlink or IpReachabilityMonitor
+    public final int eventType;
+
+    private IpReachabilityEvent(String ifName, int eventType) {
+        this.ifName = ifName;
+        this.eventType = eventType;
+    }
+
+    private IpReachabilityEvent(Parcel in) {
+        this.ifName = in.readString();
+        this.eventType = in.readInt();
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(ifName);
+        out.writeInt(eventType);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Parcelable.Creator<IpReachabilityEvent> CREATOR
+        = new Parcelable.Creator<IpReachabilityEvent>() {
+        public IpReachabilityEvent createFromParcel(Parcel in) {
+            return new IpReachabilityEvent(in);
+        }
+
+        public IpReachabilityEvent[] newArray(int size) {
+            return new IpReachabilityEvent[size];
+        }
+    };
+
+    public static void logProbeEvent(String ifName, int nlErrorCode) {
+        final int tag = (nlErrorCode == 0) ? IPCE_IPRM_PROBE_STARTED : IPCE_IPRM_PROBE_FAILURE;
+        final int eventType = PROBE | (nlErrorCode & 0xFF);
+        logEvent(tag, new IpReachabilityEvent(ifName, eventType));
+    }
+
+    public static void logNudFailed(String ifName) {
+        logEvent(IPCE_IPRM_NUD_FAILED, new IpReachabilityEvent(ifName, NUD_FAILED));
+    }
+
+    public static void logProvisioningLost(String ifName) {
+        logEvent(IPCE_IPRM_PROVISIONING_LOST, new IpReachabilityEvent(ifName, PROVISIONING_LOST));
+    }
+};
diff --git a/core/java/android/net/metrics/IpReachabilityMonitorLostEvent.java b/core/java/android/net/metrics/IpReachabilityMonitorLostEvent.java
deleted file mode 100644
index 5215995..0000000
--- a/core/java/android/net/metrics/IpReachabilityMonitorLostEvent.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.metrics;
-
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * {@hide}
- */
-@SystemApi
-public final class IpReachabilityMonitorLostEvent extends IpConnectivityEvent
-        implements Parcelable {
-    public final String ifName;
-
-    private IpReachabilityMonitorLostEvent(String ifName) {
-        this.ifName = ifName;
-    }
-
-    private IpReachabilityMonitorLostEvent(Parcel in) {
-        this.ifName = in.readString();
-    }
-
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeString(ifName);
-    }
-
-    public int describeContents() {
-        return 0;
-    }
-
-    public static final Parcelable.Creator<IpReachabilityMonitorLostEvent> CREATOR
-        = new Parcelable.Creator<IpReachabilityMonitorLostEvent>() {
-        public IpReachabilityMonitorLostEvent createFromParcel(Parcel in) {
-            return new IpReachabilityMonitorLostEvent(in);
-        }
-
-        public IpReachabilityMonitorLostEvent[] newArray(int size) {
-            return new IpReachabilityMonitorLostEvent[size];
-        }
-    };
-
-    public static void logEvent(String ifName) {
-        logEvent(IPCE_IPRM_REACHABILITY_LOST, new IpReachabilityMonitorLostEvent(ifName));
-    }
-};
diff --git a/core/java/android/net/metrics/IpReachabilityMonitorMessageEvent.java b/core/java/android/net/metrics/IpReachabilityMonitorMessageEvent.java
deleted file mode 100644
index 0ed8c1c..0000000
--- a/core/java/android/net/metrics/IpReachabilityMonitorMessageEvent.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.metrics;
-
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * {@hide}
- */
-@SystemApi
-public final class IpReachabilityMonitorMessageEvent extends IpConnectivityEvent
-        implements Parcelable {
-    public final String ifName;
-    public final String destination;
-    public final int msgType;
-    public final int nudState;
-
-    private IpReachabilityMonitorMessageEvent(String ifName, String destination, int msgType,
-            int nudState) {
-        this.ifName = ifName;
-        this.destination = destination;
-        this.msgType = msgType;
-        this.nudState = nudState;
-    }
-
-    private IpReachabilityMonitorMessageEvent(Parcel in) {
-        this.ifName = in.readString();
-        this.destination = in.readString();
-        this.msgType = in.readInt();
-        this.nudState = in.readInt();
-    }
-
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeString(ifName);
-        out.writeString(destination);
-        out.writeInt(msgType);
-        out.writeInt(nudState);
-    }
-
-    public int describeContents() {
-        return 0;
-    }
-
-    public static final Parcelable.Creator<IpReachabilityMonitorMessageEvent> CREATOR
-        = new Parcelable.Creator<IpReachabilityMonitorMessageEvent>() {
-        public IpReachabilityMonitorMessageEvent createFromParcel(Parcel in) {
-            return new IpReachabilityMonitorMessageEvent(in);
-        }
-
-        public IpReachabilityMonitorMessageEvent[] newArray(int size) {
-            return new IpReachabilityMonitorMessageEvent[size];
-        }
-    };
-
-    public static void logEvent(String ifName, String destination, int msgType, int nudState) {
-        logEvent(IPCE_IPRM_MESSAGE_RECEIVED,
-                new IpReachabilityMonitorMessageEvent(ifName, destination, msgType, nudState));
-    }
-};
diff --git a/core/java/android/net/metrics/IpReachabilityMonitorProbeEvent.java b/core/java/android/net/metrics/IpReachabilityMonitorProbeEvent.java
deleted file mode 100644
index a55c2b4..0000000
--- a/core/java/android/net/metrics/IpReachabilityMonitorProbeEvent.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.metrics;
-
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * {@hide}
- */
-@SystemApi
-public final class IpReachabilityMonitorProbeEvent extends IpConnectivityEvent
-        implements Parcelable {
-    public final String ifName;
-    public final String destination;
-    public final boolean success;
-
-    private IpReachabilityMonitorProbeEvent(String ifName, String destination, boolean success) {
-        this.ifName = ifName;
-        this.destination = destination;
-        this.success = success;
-    }
-
-    private IpReachabilityMonitorProbeEvent(Parcel in) {
-        this.ifName = in.readString();
-        this.destination = in.readString();
-        this.success = in.readByte() > 0 ? true : false;
-    }
-
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeString(ifName);
-        out.writeString(destination);
-        out.writeByte((byte)(success ? 1 : 0));
-    }
-
-    public int describeContents() {
-        return 0;
-    }
-
-    public static final Parcelable.Creator<IpReachabilityMonitorProbeEvent> CREATOR
-        = new Parcelable.Creator<IpReachabilityMonitorProbeEvent>() {
-        public IpReachabilityMonitorProbeEvent createFromParcel(Parcel in) {
-            return new IpReachabilityMonitorProbeEvent(in);
-        }
-
-        public IpReachabilityMonitorProbeEvent[] newArray(int size) {
-            return new IpReachabilityMonitorProbeEvent[size];
-        }
-    };
-
-    public static void logEvent(String ifName, String destination, boolean success) {
-        logEvent(IPCE_IPRM_PROBE_RESULT,
-                new IpReachabilityMonitorProbeEvent(ifName, destination, success));
-    }
-};
diff --git a/core/java/android/net/metrics/NetworkMonitorEvent.java b/core/java/android/net/metrics/NetworkMonitorEvent.java
new file mode 100644
index 0000000..2371266
--- /dev/null
+++ b/core/java/android/net/metrics/NetworkMonitorEvent.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.metrics;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+@SystemApi
+public final class NetworkMonitorEvent extends IpConnectivityEvent implements Parcelable {
+    public final int netId;
+    public final long durationMs;
+    public final int returnCode;
+
+    private NetworkMonitorEvent(int netId, long durationMs, int returnCode) {
+        this.netId = netId;
+        this.durationMs = durationMs;
+        this.returnCode = returnCode;
+    }
+
+    public NetworkMonitorEvent(Parcel in) {
+        netId = in.readInt();
+        durationMs = in.readLong();
+        returnCode = in.readInt();
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(netId);
+        out.writeLong(durationMs);
+        out.writeInt(returnCode);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Parcelable.Creator<NetworkMonitorEvent> CREATOR
+        = new Parcelable.Creator<NetworkMonitorEvent>() {
+        public NetworkMonitorEvent createFromParcel(Parcel in) {
+            return new NetworkMonitorEvent(in);
+        }
+
+        public NetworkMonitorEvent[] newArray(int size) {
+            return new NetworkMonitorEvent[size];
+        }
+    };
+
+    private static void logEvent(int eventType, int netId, long durationMs, int returnCode) {
+        logEvent(eventType, new NetworkMonitorEvent(netId, durationMs, returnCode));
+    }
+
+    public static void logValidated(int netId, long durationMs) {
+        logEvent(IPCE_NETMON_VALIDATED, netId, durationMs, 0);
+    }
+
+    public static void logPortalProbeEvent(int netId, long durationMs, int returnCode) {
+        logEvent(IPCE_NETMON_PORTAL_PROBE, netId, durationMs, returnCode);
+    }
+
+    public static void logCaptivePortalFound(int netId, long durationMs) {
+        logEvent(IPCE_NETMON_CAPPORT_FOUND, netId, durationMs, 0);
+    }
+};
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 16d90de..c285acb 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -1023,7 +1023,7 @@
     /**
      * Returns True if the device supports Sustained Performance Mode.
      * Applications Should check if the device supports this mode, before
-     * using {@link #SUSTAINED_PERFORMANCE_WAKE_LOCK}.
+     * using {@link android.view.Window#setSustainedPerformanceMode}.
      */
     public boolean isSustainedPerformanceModeSupported() {
         return mContext.getResources().getBoolean(
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 71f0bd6..5d0ad55 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -778,6 +778,12 @@
 
         public PrintDocumentAdapterDelegate(Activity activity,
                 PrintDocumentAdapter documentAdapter) {
+            if (activity.isFinishing()) {
+                // The activity is already dead hence the onActivityDestroyed callback won't be
+                // triggered. Hence it is not save to print in this situation.
+                throw new IllegalStateException("Cannot start printing for finishing activity");
+            }
+
             mActivity = activity;
             mDocumentAdapter = documentAdapter;
             mHandler = new MyHandler(mActivity.getMainLooper());
diff --git a/core/java/android/printservice/CustomPrinterIconCallback.java b/core/java/android/printservice/CustomPrinterIconCallback.java
index 6b9d0d8..a1fbdab 100644
--- a/core/java/android/printservice/CustomPrinterIconCallback.java
+++ b/core/java/android/printservice/CustomPrinterIconCallback.java
@@ -27,7 +27,7 @@
 /**
  * Callback for {@link PrinterDiscoverySession#onRequestCustomPrinterIcon}.
  */
-public class CustomPrinterIconCallback {
+public final class CustomPrinterIconCallback {
     /** The printer the call back is for */
     private final @NonNull PrinterId mPrinterId;
     private final @NonNull IPrintServiceClient mObserver;
diff --git a/core/java/android/printservice/PrintJob.java b/core/java/android/printservice/PrintJob.java
index 7a7ca23..3226f34 100644
--- a/core/java/android/printservice/PrintJob.java
+++ b/core/java/android/printservice/PrintJob.java
@@ -347,18 +347,15 @@
      * <p />
      * This overrides any previously set status set via {@link #setStatus(CharSequence)},
      * {@link #setStatus(int)}, {@link #block(String)}, or {@link #fail(String)},
-     * <p />
-     * To clear the status use {@link #setStatus(CharSequence) <code>setStatus(null)</code>}
      *
-     * @param status  The new status as a String resource.
+     * @param statusResId The new status as a String resource. If 0 the status will be empty.
      */
     @MainThread
-    public void setStatus(@StringRes int status) {
+    public void setStatus(@StringRes int statusResId) {
         PrintService.throwIfNotCalledOnMainThread();
-        Preconditions.checkArgument(status != 0, "status has to be != 0");
 
         try {
-            mPrintServiceClient.setStatusRes(mCachedInfo.getId(), status,
+            mPrintServiceClient.setStatusRes(mCachedInfo.getId(), statusResId,
                     mContext.getPackageName());
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "Error setting status for job: " + mCachedInfo.getId(), re);
diff --git a/core/java/android/printservice/PrinterDiscoverySession.java b/core/java/android/printservice/PrinterDiscoverySession.java
index 7b9533d..4987e8b 100644
--- a/core/java/android/printservice/PrinterDiscoverySession.java
+++ b/core/java/android/printservice/PrinterDiscoverySession.java
@@ -408,15 +408,15 @@
     public abstract void onStartPrinterStateTracking(@NonNull PrinterId printerId);
 
     /**
-     * Request the custom icon for a printer. Once the icon is available use
-     * {@link CustomPrinterIconCallback#onCustomPrinterIconLoaded} to send the data to the print
-     * service.
+     * Called by the system to request the custom icon for a printer. Once the icon is available the
+     * print services uses {@link CustomPrinterIconCallback#onCustomPrinterIconLoaded} to send the
+     * icon to the system.
      *
      * @param printerId The printer to icon belongs to.
-     * @param cancellationSignal Signal used to cancel the request
-     * @param callback Callback for returning the icon to the print spooler.
+     * @param cancellationSignal Signal used to cancel the request.
+     * @param callback Callback for returning the icon to the system.
      *
-     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon(boolean)
      */
     public void onRequestCustomPrinterIcon(@NonNull PrinterId printerId,
             @NonNull CancellationSignal cancellationSignal,
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 97af8f4..1781d9d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -20619,6 +20619,12 @@
         }
     }
 
+    /**
+     * Updates the drag shadow for the ongoing drag and drop operation.
+     *
+     * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the
+     * new drag shadow.
+     */
     public final void updateDragShadow(DragShadowBuilder shadowBuilder) {
         if (ViewDebug.DEBUG_DRAG) {
             Log.d(VIEW_LOG_TAG, "updateDragShadow");
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 1b52146..27ffb8b 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -94,14 +94,14 @@
 
     private int mStatsType = BatteryStats.STATS_SINCE_CHARGED;
 
-    long mRawRealtime;
-    long mRawUptime;
-    long mBatteryRealtime;
-    long mBatteryUptime;
-    long mTypeBatteryRealtime;
-    long mTypeBatteryUptime;
-    long mBatteryTimeRemaining;
-    long mChargeTimeRemaining;
+    long mRawRealtimeUs;
+    long mRawUptimeUs;
+    long mBatteryRealtimeUs;
+    long mBatteryUptimeUs;
+    long mTypeBatteryRealtimeUs;
+    long mTypeBatteryUptimeUs;
+    long mBatteryTimeRemainingUs;
+    long mChargeTimeRemainingUs;
 
     private long mStatsPeriod = 0;
 
@@ -389,22 +389,22 @@
         mFlashlightPowerCalculator.reset();
 
         mStatsType = statsType;
-        mRawUptime = rawUptimeUs;
-        mRawRealtime = rawRealtimeUs;
-        mBatteryUptime = mStats.getBatteryUptime(rawUptimeUs);
-        mBatteryRealtime = mStats.getBatteryRealtime(rawRealtimeUs);
-        mTypeBatteryUptime = mStats.computeBatteryUptime(rawUptimeUs, mStatsType);
-        mTypeBatteryRealtime = mStats.computeBatteryRealtime(rawRealtimeUs, mStatsType);
-        mBatteryTimeRemaining = mStats.computeBatteryTimeRemaining(rawRealtimeUs);
-        mChargeTimeRemaining = mStats.computeChargeTimeRemaining(rawRealtimeUs);
+        mRawUptimeUs = rawUptimeUs;
+        mRawRealtimeUs = rawRealtimeUs;
+        mBatteryUptimeUs = mStats.getBatteryUptime(rawUptimeUs);
+        mBatteryRealtimeUs = mStats.getBatteryRealtime(rawRealtimeUs);
+        mTypeBatteryUptimeUs = mStats.computeBatteryUptime(rawUptimeUs, mStatsType);
+        mTypeBatteryRealtimeUs = mStats.computeBatteryRealtime(rawRealtimeUs, mStatsType);
+        mBatteryTimeRemainingUs = mStats.computeBatteryTimeRemaining(rawRealtimeUs);
+        mChargeTimeRemainingUs = mStats.computeChargeTimeRemaining(rawRealtimeUs);
 
         if (DEBUG) {
             Log.d(TAG, "Raw time: realtime=" + (rawRealtimeUs/1000) + " uptime="
                     + (rawUptimeUs/1000));
-            Log.d(TAG, "Battery time: realtime=" + (mBatteryRealtime/1000) + " uptime="
-                    + (mBatteryUptime/1000));
-            Log.d(TAG, "Battery type time: realtime=" + (mTypeBatteryRealtime/1000) + " uptime="
-                    + (mTypeBatteryUptime/1000));
+            Log.d(TAG, "Battery time: realtime=" + (mBatteryRealtimeUs /1000) + " uptime="
+                    + (mBatteryUptimeUs /1000));
+            Log.d(TAG, "Battery type time: realtime=" + (mTypeBatteryRealtimeUs /1000) + " uptime="
+                    + (mTypeBatteryUptimeUs /1000));
         }
         mMinDrainedPower = (mStats.getLowDischargeAmountSinceCharge()
                 * mPowerProfile.getBatteryCapacity()) / 100;
@@ -489,7 +489,7 @@
 
     private void processAppUsage(SparseArray<UserHandle> asUsers) {
         final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null);
-        mStatsPeriod = mTypeBatteryRealtime;
+        mStatsPeriod = mTypeBatteryRealtimeUs;
 
         BatterySipper osSipper = null;
         final SparseArray<? extends Uid> uidStats = mStats.getUidStats();
@@ -498,14 +498,14 @@
             final Uid u = uidStats.valueAt(iu);
             final BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, u, 0);
 
-            mCpuPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
-            mWakelockPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
-            mMobileRadioPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
-            mWifiPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
-            mBluetoothPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
-            mSensorPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
-            mCameraPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
-            mFlashlightPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
+            mCpuPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+            mWakelockPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+            mMobileRadioPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+            mWifiPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+            mBluetoothPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+            mSensorPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+            mCameraPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+            mFlashlightPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
 
             final double totalPower = app.sumPower();
             if (DEBUG && totalPower != 0) {
@@ -547,14 +547,14 @@
             // The device has probably been awake for longer than the screen on
             // time and application wake lock time would account for.  Assign
             // this remainder to the OS, if possible.
-            mWakelockPowerCalculator.calculateRemaining(osSipper, mStats, mRawRealtime,
-                                                        mRawUptime, mStatsType);
+            mWakelockPowerCalculator.calculateRemaining(osSipper, mStats, mRawRealtimeUs,
+                    mRawUptimeUs, mStatsType);
             osSipper.sumPower();
         }
     }
 
     private void addPhoneUsage() {
-        long phoneOnTimeMs = mStats.getPhoneOnTime(mRawRealtime, mStatsType) / 1000;
+        long phoneOnTimeMs = mStats.getPhoneOnTime(mRawRealtimeUs, mStatsType) / 1000;
         double phoneOnPower = mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE)
                 * phoneOnTimeMs / (60*60*1000);
         if (phoneOnPower != 0) {
@@ -562,16 +562,19 @@
         }
     }
 
+    /**
+     * Screen power is the additional power the screen takes while the device is running.
+     */
     private void addScreenUsage() {
         double power = 0;
-        long screenOnTimeMs = mStats.getScreenOnTime(mRawRealtime, mStatsType) / 1000;
+        long screenOnTimeMs = mStats.getScreenOnTime(mRawRealtimeUs, mStatsType) / 1000;
         power += screenOnTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON);
         final double screenFullPower =
                 mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL);
         for (int i = 0; i < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; i++) {
             double screenBinPower = screenFullPower * (i + 0.5f)
                     / BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS;
-            long brightnessTime = mStats.getScreenBrightnessTime(i, mRawRealtime, mStatsType)
+            long brightnessTime = mStats.getScreenBrightnessTime(i, mRawRealtimeUs, mStatsType)
                     / 1000;
             double p = screenBinPower*brightnessTime;
             if (DEBUG && p != 0) {
@@ -588,7 +591,7 @@
 
     private void addRadioUsage() {
         BatterySipper radio = new BatterySipper(BatterySipper.DrainType.CELL, null, 0);
-        mMobileRadioPowerCalculator.calculateRemaining(radio, mStats, mRawRealtime, mRawUptime,
+        mMobileRadioPowerCalculator.calculateRemaining(radio, mStats, mRawRealtimeUs, mRawUptimeUs,
                 mStatsType);
         radio.sumPower();
         if (radio.totalPowerMah > 0) {
@@ -606,16 +609,26 @@
         bs.sumPower();
     }
 
+    /**
+     * Calculate the baseline power usage for the device when it is in suspend and idle.
+     * The device is drawing POWER_CPU_IDLE power at its lowest power state.
+     * The device is drawing POWER_CPU_IDLE + POWER_CPU_AWAKE power when a wakelock is held.
+     */
     private void addIdleUsage() {
-        long idleTimeMs = (mTypeBatteryRealtime
-                - mStats.getScreenOnTime(mRawRealtime, mStatsType)) / 1000;
-        double idlePower = (idleTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE))
-                / (60*60*1000);
-        if (DEBUG && idlePower != 0) {
-            Log.d(TAG, "Idle: time=" + idleTimeMs + " power=" + makemAh(idlePower));
+        final double suspendPowerMaMs = (mTypeBatteryRealtimeUs / 1000) *
+                mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE);
+        final double idlePowerMaMs = (mTypeBatteryUptimeUs / 1000) *
+                mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_AWAKE);
+        final double totalPowerMah = (suspendPowerMaMs + idlePowerMaMs) / (60 * 60 * 1000);
+        if (DEBUG && totalPowerMah != 0) {
+            Log.d(TAG, "Suspend: time=" + (mTypeBatteryRealtimeUs / 1000)
+                    + " power=" + makemAh(suspendPowerMaMs / (60 * 60 * 1000)));
+            Log.d(TAG, "Idle: time=" + (mTypeBatteryUptimeUs / 1000)
+                    + " power=" + makemAh(idlePowerMaMs / (60 * 60 * 1000)));
         }
-        if (idlePower != 0) {
-            addEntry(BatterySipper.DrainType.IDLE, idleTimeMs, idlePower);
+
+        if (totalPowerMah != 0) {
+            addEntry(BatterySipper.DrainType.IDLE, mTypeBatteryRealtimeUs / 1000, totalPowerMah);
         }
     }
 
@@ -628,7 +641,7 @@
      */
     private void addWiFiUsage() {
         BatterySipper bs = new BatterySipper(DrainType.WIFI, null, 0);
-        mWifiPowerCalculator.calculateRemaining(bs, mStats, mRawRealtime, mRawUptime, mStatsType);
+        mWifiPowerCalculator.calculateRemaining(bs, mStats, mRawRealtimeUs, mRawUptimeUs, mStatsType);
         aggregateSippers(bs, mWifiSippers, "WIFI");
         if (bs.totalPowerMah > 0) {
             mUsageList.add(bs);
@@ -641,7 +654,7 @@
      */
     private void addBluetoothUsage() {
         BatterySipper bs = new BatterySipper(BatterySipper.DrainType.BLUETOOTH, null, 0);
-        mBluetoothPowerCalculator.calculateRemaining(bs, mStats, mRawRealtime, mRawUptime,
+        mBluetoothPowerCalculator.calculateRemaining(bs, mStats, mRawRealtimeUs, mRawUptimeUs,
                 mStatsType);
         aggregateSippers(bs, mBluetoothSippers, "Bluetooth");
         if (bs.totalPowerMah > 0) {
@@ -709,10 +722,6 @@
         return mMaxDrainedPower;
     }
 
-    public long getBatteryTimeRemaining() { return mBatteryTimeRemaining; }
-
-    public long getChargeTimeRemaining() { return mChargeTimeRemaining; }
-
     public static byte[] readFully(FileInputStream stream) throws java.io.IOException {
         return readFully(stream, stream.available());
     }
diff --git a/core/java/com/android/internal/os/BinderInternal.java b/core/java/com/android/internal/os/BinderInternal.java
index d77b998..ea4575a 100644
--- a/core/java/com/android/internal/os/BinderInternal.java
+++ b/core/java/com/android/internal/os/BinderInternal.java
@@ -93,6 +93,8 @@
      * @hide
      */
     public static final native void disableBackgroundScheduling(boolean disable);
+
+    public static final native void setMaxThreads(int numThreads);
     
     static native final void handleGc();
     
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 79138b7..d217474 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -51,7 +51,7 @@
      * Power consumption when CPU is awake (when a wake lock is held).  This
      * should be 0 on devices that can go into full CPU power collapse even
      * when a wake lock is held.  Otherwise, this is the power consumption in
-     * addition to POWERR_CPU_IDLE due to a wake lock being held but with no
+     * addition to POWER_CPU_IDLE due to a wake lock being held but with no
      * CPU activity.
      */
     public static final String POWER_CPU_AWAKE = "cpu.awake";
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index 2d12fcd..9d296fa 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -76,26 +76,6 @@
     @Override
     public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
             ParcelFileDescriptor newState) throws IOException {
-        // We only back up the data under the current "wallpaper" schema with metadata
-        IWallpaperManager wallpaper = (IWallpaperManager)ServiceManager.getService(
-                Context.WALLPAPER_SERVICE);
-        String[] files = new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO };
-        String[] keys = new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY };
-        if (wallpaper != null) {
-            try {
-                final String wallpaperName = wallpaper.getName();
-                if (wallpaperName != null && wallpaperName.length() > 0) {
-                    // When the wallpaper has a name, back up the info by itself.
-                    // TODO: Don't rely on the innards of the service object like this!
-                    // TODO: Send a delete for any stored wallpaper image in this case?
-                    files = new String[] { WALLPAPER_INFO };
-                    keys = new String[] { WALLPAPER_INFO_KEY };
-                }
-            } catch (RemoteException re) {
-                Slog.e(TAG, "Couldn't get wallpaper name\n" + re);
-            }
-        }
-        addHelper(WALLPAPER_HELPER, new WallpaperBackupHelper(this, files, keys));
         addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this));
         addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper());
         addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this));
@@ -107,30 +87,20 @@
 
     @Override
     public void onFullBackup(FullBackupDataOutput data) throws IOException {
-        // At present we back up only the wallpaper
-        fullWallpaperBackup(data);
-    }
-
-    private void fullWallpaperBackup(FullBackupDataOutput output) {
-        // Back up the data files directly.  We do them in this specific order --
-        // info file followed by image -- because then we need take no special
-        // steps during restore; the restore will happen properly when the individual
-        // files are restored piecemeal.
-        FullBackup.backupToTar(getPackageName(), FullBackup.ROOT_TREE_TOKEN, null,
-                WALLPAPER_INFO_DIR, WALLPAPER_INFO, output);
-        FullBackup.backupToTar(getPackageName(), FullBackup.ROOT_TREE_TOKEN, null,
-                WALLPAPER_IMAGE_DIR, WALLPAPER_IMAGE, output);
+        // At present we don't back up anything
     }
 
     @Override
     public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
             throws IOException {
+        // Slot in a restore helper for the older wallpaper backup schema to support restore
+        // from devices still generating data in that format.
         mWallpaperHelper = new WallpaperBackupHelper(this,
                 new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO },
                 new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY} );
         addHelper(WALLPAPER_HELPER, mWallpaperHelper);
 
-        // On restore, we also support a previous data schema "system_files"
+        // On restore, we also support a long-ago wallpaper data schema "system_files"
         addHelper("system_files", new WallpaperBackupHelper(this,
                 new String[] { WALLPAPER_IMAGE },
                 new String[] { WALLPAPER_IMAGE_KEY} ));
@@ -213,6 +183,9 @@
 
     @Override
     public void onRestoreFinished() {
-        mWallpaperHelper.onRestoreFinished();
+        // helper will be null following 'adb restore' or other full-data operation
+        if (mWallpaperHelper != null) {
+            mWallpaperHelper.onRestoreFinished();
+        }
     }
 }
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index abc6c4b..5559d48 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -917,6 +917,12 @@
     IPCThreadState::disableBackgroundScheduling(disable ? true : false);
 }
 
+static void android_os_BinderInternal_setMaxThreads(JNIEnv* env,
+        jobject clazz, jint maxThreads)
+{
+    ProcessState::self()->setThreadPoolMaxThreadCount(maxThreads);
+}
+
 static void android_os_BinderInternal_handleGc(JNIEnv* env, jobject clazz)
 {
     ALOGV("Gc has executed, clearing binder ops");
@@ -930,6 +936,7 @@
     { "getContextObject", "()Landroid/os/IBinder;", (void*)android_os_BinderInternal_getContextObject },
     { "joinThreadPool", "()V", (void*)android_os_BinderInternal_joinThreadPool },
     { "disableBackgroundScheduling", "(Z)V", (void*)android_os_BinderInternal_disableBackgroundScheduling },
+    { "setMaxThreads", "(I)V", (void*)android_os_BinderInternal_setMaxThreads },
     { "handleGc", "()V", (void*)android_os_BinderInternal_handleGc }
 };
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6776d3b..2040d7de 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -497,14 +497,14 @@
     <string name="bugreport_option_interactive_title">Interactive report</string>
     <!-- Summary in the bugreport dialog for the interactive workflow. [CHAR LIMIT=NONE] -->
     <string name="bugreport_option_interactive_summary">Use this under most circumstances.
-        It allows you to track progress of the report and enter more details about the problem.
+        It allows you to track progress of the report, enter more details about the problem, and take screenshots.
         It might omit some less-used sections that take a long time to report.</string>
     <!-- Title in the bugreport dialog for the full workflow. Should fit in one line. [CHAR LIMIT=30] -->
     <string name="bugreport_option_full_title">Full report</string>
     <!-- Summary in the bugreport dialog for the full workflow. [CHAR LIMIT=NONE] -->
     <string name="bugreport_option_full_summary">Use this option for minimal system interference when
         your device is unresponsive or too slow, or when you need all report sections.
-        Does not take a screenshot or allow you to enter more details.</string>
+        Does not allow you to enter more details or take additional screenshots.</string>
     <!--  Toast message informing user in how many seconds a bugreport screenshot will be taken -->
     <plurals name="bugreport_countdown">
         <item quantity="one">Taking screenshot for bug report in <xliff:g id="number">%d</xliff:g> second.</item>
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 6259466..8857c41 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -247,6 +247,7 @@
     tests/unit/DamageAccumulatorTests.cpp \
     tests/unit/DeviceInfoTests.cpp \
     tests/unit/FatVectorTests.cpp \
+    tests/unit/FontRendererTests.cpp \
     tests/unit/GlopBuilderTests.cpp \
     tests/unit/GpuMemoryTrackerTests.cpp \
     tests/unit/GradientCacheTests.cpp \
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 1b618c6..276c18d 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -689,7 +689,7 @@
 void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
     uint32_t intRadius = Blur::convertRadiusToInt(radius);
 #ifdef ANDROID_ENABLE_RENDERSCRIPT
-    if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF) {
+    if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF && radius <= 25.0f) {
         uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
 
         if (mRs == nullptr) {
diff --git a/libs/hwui/tests/unit/FontRendererTests.cpp b/libs/hwui/tests/unit/FontRendererTests.cpp
new file mode 100644
index 0000000..99080ac
--- /dev/null
+++ b/libs/hwui/tests/unit/FontRendererTests.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "GammaFontRenderer.h"
+#include "tests/common/TestUtils.h"
+
+using namespace android::uirenderer;
+
+static bool isZero(uint8_t* data, int size) {
+    for (int i = 0; i < size; i++) {
+        if (data[i]) return false;
+    }
+    return true;
+}
+
+RENDERTHREAD_TEST(FontRenderer, renderDropShadow) {
+    SkPaint paint;
+    paint.setTextSize(10);
+    paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+    GammaFontRenderer gammaFontRenderer;
+    FontRenderer& fontRenderer = gammaFontRenderer.getFontRenderer();
+    fontRenderer.setFont(&paint, SkMatrix::I());
+
+    std::vector<glyph_t> glyphs;
+    std::vector<float> positions;
+    float totalAdvance;
+    Rect bounds;
+    TestUtils::layoutTextUnscaled(paint, "This is a test",
+            &glyphs, &positions, &totalAdvance, &bounds);
+
+    for (int radius : {28, 20, 2}) {
+        auto result = fontRenderer.renderDropShadow(&paint, glyphs.data(), glyphs.size(),
+                radius, positions.data());
+        ASSERT_NE(nullptr, result.image);
+        EXPECT_FALSE(isZero(result.image, result.width * result.height));
+        EXPECT_LE(bounds.getWidth() + radius * 2, (int) result.width);
+        EXPECT_LE(bounds.getHeight() + radius * 2, (int) result.height);
+        delete result.image;
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
index ecdbe63..32fdb64 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
@@ -70,11 +70,7 @@
     }
 
     public boolean isDocumentEnabled(String docMimeType, int docFlags) {
-        if (isDirectory(docMimeType)) {
-            return true;
-        }
-
-        return MimePredicate.mimeMatches(mState.acceptMimes, docMimeType);
+        return true;
     }
 
     abstract void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch);
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 8c2af45..9aaddaa 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -1213,44 +1213,55 @@
         }
     }
 
+    /**
+     * Compare by label, then package name, then uid.
+     */
     public static final Comparator<AppEntry> ALPHA_COMPARATOR = new Comparator<AppEntry>() {
         private final Collator sCollator = Collator.getInstance();
         @Override
         public int compare(AppEntry object1, AppEntry object2) {
-            return sCollator.compare(object1.label, object2.label);
+            int compareResult = sCollator.compare(object1.label, object2.label);
+            if (compareResult != 0) {
+                return compareResult;
+            }
+            if (object1.info != null && object2.info != null) {
+                compareResult =
+                    sCollator.compare(object1.info.packageName, object2.info.packageName);
+                if (compareResult != 0) {
+                    return compareResult;
+                }
+            }
+            return object1.info.uid - object2.info.uid;
         }
     };
 
     public static final Comparator<AppEntry> SIZE_COMPARATOR
             = new Comparator<AppEntry>() {
-        private final Collator sCollator = Collator.getInstance();
         @Override
         public int compare(AppEntry object1, AppEntry object2) {
             if (object1.size < object2.size) return 1;
             if (object1.size > object2.size) return -1;
-            return sCollator.compare(object1.label, object2.label);
+            return ALPHA_COMPARATOR.compare(object1, object2);
         }
     };
 
     public static final Comparator<AppEntry> INTERNAL_SIZE_COMPARATOR
             = new Comparator<AppEntry>() {
-        private final Collator sCollator = Collator.getInstance();
         @Override
         public int compare(AppEntry object1, AppEntry object2) {
             if (object1.internalSize < object2.internalSize) return 1;
             if (object1.internalSize > object2.internalSize) return -1;
-            return sCollator.compare(object1.label, object2.label);
+            return ALPHA_COMPARATOR.compare(object1, object2);
         }
     };
 
     public static final Comparator<AppEntry> EXTERNAL_SIZE_COMPARATOR
             = new Comparator<AppEntry>() {
-        private final Collator sCollator = Collator.getInstance();
         @Override
         public int compare(AppEntry object1, AppEntry object2) {
             if (object1.externalSize < object2.externalSize) return 1;
             if (object1.externalSize > object2.externalSize) return -1;
-            return sCollator.compare(object1.label, object2.label);
+            return ALPHA_COMPARATOR.compare(object1, object2);
         }
     };
 
@@ -1272,21 +1283,18 @@
         }
     };
 
-    public static final AppFilter FILTER_PERSONAL_WITHOUT_DISABLED_UNTIL_USED = new AppFilter() {
-        private int mCurrentUser;
-
+    public static final AppFilter FILTER_WITHOUT_DISABLED_UNTIL_USED = new AppFilter() {
         public void init() {
-            mCurrentUser = ActivityManager.getCurrentUser();
+            // do nothings
         }
 
         @Override
         public boolean filterApp(AppEntry entry) {
-            return UserHandle.getUserId(entry.info.uid) == mCurrentUser &&
-                    entry.info.enabledSetting != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
+            return entry.info.enabledSetting
+                    != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
         }
     };
 
-
     public static final AppFilter FILTER_WORK = new AppFilter() {
         private int mCurrentUser;
 
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index ec3a7fc..7023a1a 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -198,6 +198,11 @@
     private File mScreenshotsDir;
 
     /**
+     * id of the notification used to set service on foreground.
+     */
+    private int mForegroundId = -1;
+
+    /**
      * Flag indicating whether a screenshot is being taken.
      * <p>
      * This is the only state that is shared between the 2 handlers and hence must have synchronized
@@ -257,6 +262,7 @@
             writer.printf("No monitored processes");
             return;
         }
+        writer.printf("Foreground id: %d\n\n", mForegroundId);
         writer.printf("Monitored dumpstate processes\n");
         writer.printf("-----------------------------\n");
         for (int i = 0; i < size; i++) {
@@ -479,10 +485,21 @@
             return;
         }
         if (DEBUG) {
-            Log.d(TAG, "Sending 'Progress' notification for id " + info.id + "(pid " + info.pid
+            Log.d(TAG, "Sending 'Progress' notification for id " + info.id + " (pid " + info.pid
                     + "): " + percentageText);
         }
-        NotificationManager.from(mContext).notify(TAG, info.id, notification);
+        sendForegroundabledNotification(info.id, notification);
+    }
+
+    private void sendForegroundabledNotification(int id, Notification notification) {
+        if (mForegroundId >= 0) {
+            if (DEBUG) Log.d(TAG, "Already running as foreground service");
+            NotificationManager.from(mContext).notify(id, notification);
+        } else {
+            mForegroundId = id;
+            Log.d(TAG, "Start running as foreground service on id " + mForegroundId);
+            startForeground(mForegroundId, notification);
+        }
     }
 
     /**
@@ -506,8 +523,10 @@
             Log.d(TAG, "Removing ID " + id);
             mProcesses.remove(id);
         }
-        Log.v(TAG, "stopProgress(" + id + "): cancel notification");
-        NotificationManager.from(mContext).cancel(TAG, id);
+        // Must stop foreground service first, otherwise notif.cancel() will fail below.
+        stopForegroundWhenDone(id);
+        Log.d(TAG, "stopProgress(" + id + "): cancel notification");
+        NotificationManager.from(mContext).cancel(id);
         stopSelfWhenDone();
     }
 
@@ -625,7 +644,7 @@
             Log.w(TAG, "launchBugreportInfoDialog(): canceling notification because id " + id
                     + " was not found");
             // TODO: add test case to make sure notification is canceled.
-            NotificationManager.from(mContext).cancel(TAG, id);
+            NotificationManager.from(mContext).cancel(id);
             return;
         }
 
@@ -648,7 +667,7 @@
             Log.w(TAG, "takeScreenshot(): canceling notification because id " + id
                     + " was not found");
             // TODO: add test case to make sure notification is canceled.
-            NotificationManager.from(mContext).cancel(TAG, id);
+            NotificationManager.from(mContext).cancel(id);
             return;
         }
         setTakingScreenshot(true);
@@ -731,7 +750,7 @@
             if (info.finished) {
                 Log.d(TAG, "Screenshot finished after bugreport; updating share notification");
                 info.renameScreenshots(mScreenshotsDir);
-                sendBugreportNotification(mContext, info, mTakingScreenshot);
+                sendBugreportNotification(info, mTakingScreenshot);
             }
             msg = mContext.getString(R.string.bugreport_screenshot_taken);
         } else {
@@ -753,6 +772,33 @@
     }
 
     /**
+     * Stop running on foreground once there is no more active bugreports being watched.
+     */
+    private void stopForegroundWhenDone(int id) {
+        if (id != mForegroundId) {
+            Log.d(TAG, "stopForegroundWhenDone(" + id + "): ignoring since foreground id is "
+                    + mForegroundId);
+            return;
+        }
+
+        Log.d(TAG, "detaching foreground from id " + mForegroundId);
+        stopForeground(Service.STOP_FOREGROUND_DETACH);
+        mForegroundId = -1;
+
+        // Might need to restart foreground using a new notification id.
+        final int total = mProcesses.size();
+        if (total > 0) {
+            for (int i = 0; i < total; i++) {
+                final BugreportInfo info = mProcesses.valueAt(i);
+                if (!info.finished) {
+                    updateProgress(info);
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
      * Finishes the service when it's not monitoring any more processes.
      */
     private void stopSelfWhenDone() {
@@ -797,6 +843,9 @@
         }
         info.finished = true;
 
+        // Stop running on foreground, otherwise share notification cannot be dismissed.
+        stopForegroundWhenDone(id);
+
         final Configuration conf = mContext.getResources().getConfiguration();
         if ((conf.uiMode & Configuration.UI_MODE_TYPE_MASK) != Configuration.UI_MODE_TYPE_WATCH) {
             triggerLocalNotification(mContext, info);
@@ -820,10 +869,10 @@
         boolean isPlainText = info.bugreportFile.getName().toLowerCase().endsWith(".txt");
         if (!isPlainText) {
             // Already zipped, send it right away.
-            sendBugreportNotification(context, info, mTakingScreenshot);
+            sendBugreportNotification(info, mTakingScreenshot);
         } else {
             // Asynchronously zip the file first, then send it.
-            sendZippedBugreportNotification(context, info, mTakingScreenshot);
+            sendZippedBugreportNotification(info, mTakingScreenshot);
         }
     }
 
@@ -905,7 +954,7 @@
             Log.v(TAG, "shareBugReport(): id " + id + " info = " + info);
         }
 
-        addDetailsToZipFile(mContext, info);
+        addDetailsToZipFile(info);
 
         final Intent sendIntent = buildSendIntent(mContext, info);
         if (sendIntent == null) {
@@ -934,36 +983,35 @@
     /**
      * Sends a notification indicating the bugreport has finished so use can share it.
      */
-    private static void sendBugreportNotification(Context context, BugreportInfo info,
-            boolean takingScreenshot) {
+    private void sendBugreportNotification(BugreportInfo info, boolean takingScreenshot) {
 
         // Since adding the details can take a while, do it before notifying user.
-        addDetailsToZipFile(context, info);
+        addDetailsToZipFile(info);
 
         final Intent shareIntent = new Intent(INTENT_BUGREPORT_SHARE);
-        shareIntent.setClass(context, BugreportProgressService.class);
+        shareIntent.setClass(mContext, BugreportProgressService.class);
         shareIntent.setAction(INTENT_BUGREPORT_SHARE);
         shareIntent.putExtra(EXTRA_ID, info.id);
         shareIntent.putExtra(EXTRA_INFO, info);
 
-        final String title = context.getString(R.string.bugreport_finished_title, info.id);
+        final String title = mContext.getString(R.string.bugreport_finished_title, info.id);
         final String content = takingScreenshot ?
-                context.getString(R.string.bugreport_finished_pending_screenshot_text)
-                : context.getString(R.string.bugreport_finished_text);
-        final Notification.Builder builder = newBaseNotification(context)
+                mContext.getString(R.string.bugreport_finished_pending_screenshot_text)
+                : mContext.getString(R.string.bugreport_finished_text);
+        final Notification.Builder builder = newBaseNotification(mContext)
                 .setContentTitle(title)
                 .setTicker(title)
                 .setContentText(content)
-                .setContentIntent(PendingIntent.getService(context, info.id, shareIntent,
+                .setContentIntent(PendingIntent.getService(mContext, info.id, shareIntent,
                         PendingIntent.FLAG_UPDATE_CURRENT))
-                .setDeleteIntent(newCancelIntent(context, info));
+                .setDeleteIntent(newCancelIntent(mContext, info));
 
         if (!TextUtils.isEmpty(info.name)) {
             builder.setSubText(info.name);
         }
 
         Log.v(TAG, "Sending 'Share' notification for ID " + info.id + ": " + title);
-        NotificationManager.from(context).notify(TAG, info.id, builder.build());
+        NotificationManager.from(mContext).notify(info.id, builder.build());
     }
 
     /**
@@ -971,14 +1019,14 @@
      * finishes - at this point there is nothing to be done other than waiting, hence it has no
      * pending action.
      */
-    private static void sendBugreportBeingUpdatedNotification(Context context, int id) {
+    private void sendBugreportBeingUpdatedNotification(Context context, int id) {
         final String title = context.getString(R.string.bugreport_updating_title);
         final Notification.Builder builder = newBaseNotification(context)
                 .setContentTitle(title)
                 .setTicker(title)
                 .setContentText(context.getString(R.string.bugreport_updating_wait));
         Log.v(TAG, "Sending 'Updating zip' notification for ID " + id + ": " + title);
-        NotificationManager.from(context).notify(TAG, id, builder.build());
+        sendForegroundabledNotification(id, builder.build());
     }
 
     private static Notification.Builder newBaseNotification(Context context) {
@@ -999,13 +1047,13 @@
     /**
      * Sends a zipped bugreport notification.
      */
-    private static void sendZippedBugreportNotification(final Context context,
-            final BugreportInfo info, final boolean takingScreenshot) {
+    private void sendZippedBugreportNotification( final BugreportInfo info,
+            final boolean takingScreenshot) {
         new AsyncTask<Void, Void, Void>() {
             @Override
             protected Void doInBackground(Void... params) {
                 zipBugreport(info);
-                sendBugreportNotification(context, info, takingScreenshot);
+                sendBugreportNotification(info, takingScreenshot);
                 return null;
             }
         }.execute();
@@ -1043,7 +1091,7 @@
      * If user provided a title, it will be saved into a {@code title.txt} entry; similarly, the
      * description will be saved on {@code description.txt}.
      */
-    private static void addDetailsToZipFile(Context context, BugreportInfo info) {
+    private void addDetailsToZipFile(BugreportInfo info) {
         if (info.bugreportFile == null) {
             // One possible reason is a bug in the Parcelization code.
             Log.wtf(TAG, "addDetailsToZipFile(): no bugreportFile on " + info);
@@ -1061,7 +1109,8 @@
 
         // It's not possible to add a new entry into an existing file, so we need to create a new
         // zip, copy all entries, then rename it.
-        sendBugreportBeingUpdatedNotification(context, info.id); // ...and that takes time
+        sendBugreportBeingUpdatedNotification(mContext, info.id); // ...and that takes time
+
         final File dir = info.bugreportFile.getParentFile();
         final File tmpZip = new File(dir, "tmp-" + info.bugreportFile.getName());
         Log.d(TAG, "Writing temporary zip file (" + tmpZip + ") with title and/or description");
@@ -1090,6 +1139,7 @@
             // Make sure it only tries to add details once, even it fails the first time.
             info.addedDetailsToZip = true;
             info.addingDetailsToZip = false;
+            stopForegroundWhenDone(info.id);
         }
 
         if (!tmpZip.renameTo(info.bugreportFile)) {
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index f76fb26..07c1546 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -241,14 +241,6 @@
     }
 
     public void testProgress_takeExtraScreenshot() throws Exception {
-        takeExtraScreenshotTest(false);
-    }
-
-    public void testProgress_takeExtraScreenshotServiceDiesAfterScreenshotTaken() throws Exception {
-        takeExtraScreenshotTest(true);
-    }
-
-    private void takeExtraScreenshotTest(boolean serviceDies) throws Exception {
         resetProperties();
         sendBugreportStarted(1000);
 
@@ -259,11 +251,6 @@
 
         sendBugreportFinished(ID, mPlainTextPath, mScreenshotPath);
 
-        if (serviceDies) {
-            waitShareNotification(ID);
-            killService();
-        }
-
         Bundle extras = acceptBugreportAndGetSharedIntent(ID);
         assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE,
                 NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS);
@@ -272,14 +259,6 @@
     }
 
     public void testScreenshotFinishesAfterBugreport() throws Exception {
-        screenshotFinishesAfterBugreportTest(false);
-    }
-
-    public void testScreenshotFinishesAfterBugreportAndServiceDiesBeforeSharing() throws Exception {
-        screenshotFinishesAfterBugreportTest(true);
-    }
-
-    private void screenshotFinishesAfterBugreportTest(boolean serviceDies) throws Exception {
         resetProperties();
 
         sendBugreportStarted(1000);
@@ -291,10 +270,6 @@
         // There's no indication in the UI about the screenshot finish, so just sleep like a baby...
         Thread.sleep(SAFE_SCREENSHOT_DELAY * DateUtils.SECOND_IN_MILLIS);
 
-        if (serviceDies) {
-            killService();
-        }
-
         Bundle extras = acceptBugreportAndGetSharedIntent(ID);
         assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, ID, PID, ZIP_FILE,
                 NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS);
@@ -562,7 +537,7 @@
 
     public void testShareBugreportAfterServiceDies() throws Exception {
         sendBugreportFinished(NO_ID, mPlainTextPath, NO_SCREENSHOT);
-        killService();
+        waitForService(false);
         Bundle extras = acceptBugreportAndGetSharedIntent(NO_ID);
         assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
     }
@@ -841,15 +816,6 @@
         assertFalse("Service '" + service + "' is still running", isServiceRunning(service));
     }
 
-    private void killService() {
-        waitForService(true);
-        Log.v(TAG, "Stopping service");
-        boolean stopped = mContext.stopService(new Intent(mContext, BugreportProgressService.class));
-        Log.d(TAG, "stopService returned " + stopped);
-        waitForService(false);
-        assertServiceNotRunning();  // Sanity check.
-    }
-
     private boolean isServiceRunning(String name) {
         ActivityManager manager = (ActivityManager) mContext
                 .getSystemService(Context.ACTIVITY_SERVICE);
@@ -878,12 +844,6 @@
                 Thread.currentThread().interrupt();
             }
         }
-        if (!expectRunning) {
-            // Typically happens when service is waiting for a screenshot to finish.
-            Log.w(TAG, "Service didn't stop; try to kill it again");
-            killService();
-            return;
-        }
 
         fail("Service status didn't change to " + expectRunning);
     }
diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml
index 7460201..2db97a6 100644
--- a/packages/SystemUI/res/layout/remote_input.xml
+++ b/packages/SystemUI/res/layout/remote_input.xml
@@ -22,8 +22,7 @@
         android:theme="@style/systemui_theme_remote_input"
         android:id="@+id/remote_input"
         android:layout_height="match_parent"
-        android:layout_width="match_parent"
-        android:paddingEnd="12dp">
+        android:layout_width="match_parent">
 
     <view class="com.android.systemui.statusbar.policy.RemoteInputView$RemoteEditText"
             android:id="@+id/remote_input_text"
@@ -48,19 +47,17 @@
 
     <FrameLayout
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_vertical"
-            android:paddingTop="2dp"
-            android:paddingBottom="4dp">
+            android:layout_height="match_parent"
+            android:layout_gravity="center_vertical">
 
         <ImageButton
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_gravity="center"
                 android:paddingStart="12dp"
-                android:paddingEnd="12dp"
-                android:paddingTop="12dp"
-                android:paddingBottom="12dp"
+                android:paddingEnd="24dp"
+                android:paddingTop="16dp"
+                android:paddingBottom="16dp"
                 android:id="@+id/remote_input_send"
                 android:src="@drawable/ic_send"
                 android:contentDescription="@*android:string/ime_action_send"
@@ -72,6 +69,7 @@
                 android:id="@+id/remote_input_progress"
                 android:layout_width="24dp"
                 android:layout_height="24dp"
+                android:layout_marginEnd="6dp"
                 android:layout_gravity="center"
                 android:visibility="invisible"
                 android:indeterminate="true"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index ccefb5f..658571e 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -39,8 +39,8 @@
         android:clipToPadding="false"
         android:clipChildren="false">
 
-        <com.android.systemui.DensityContainer
-            android:id="@+id/qs_density_container"
+        <com.android.systemui.AutoReinflateContainer
+            android:id="@+id/qs_auto_reinflate_container"
             android:layout="@layout/qs_panel"
             android:layout_width="@dimen/notification_panel_width"
             android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/tv_pip_control_button.xml b/packages/SystemUI/res/layout/tv_pip_control_button.xml
index 0beeda1..f18a5da 100644
--- a/packages/SystemUI/res/layout/tv_pip_control_button.xml
+++ b/packages/SystemUI/res/layout/tv_pip_control_button.xml
@@ -38,5 +38,6 @@
         android:alpha="0"
         android:fontFamily="sans-serif"
         android:textSize="12sp"
-        android:textColor="#EEEEEE" />
+        android:textColor="#EEEEEE"
+        android:importantForAccessibility="no" />
 </merge>
diff --git a/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml b/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml
index 1e464d8..4a67000 100644
--- a/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml
+++ b/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml
@@ -23,7 +23,7 @@
     <com.android.systemui.tv.pip.PipRecentsControlsView
         android:id="@+id/pip_controls"
         android:layout_width="wrap_content"
-        android:layout_height="match_parent" />
+        android:layout_height="wrap_content" />
 
     <View
         android:id="@+id/recents"
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 1543360..4306fcc 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -98,7 +98,7 @@
         <attr name="metricsAction" format="integer" />
     </declare-styleable>
 
-    <declare-styleable name="DensityContainer">
+    <declare-styleable name="AutoReinflateContainer">
         <attr name="android:layout" />
     </declare-styleable>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ea55ac2..981b2dd 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -381,6 +381,9 @@
     <!-- Content description of the battery level icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_battery_level">Battery <xliff:g id="number">%d</xliff:g> percent.</string>
 
+    <!-- Content description of the battery level icon for accessibility while the device is charging (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_battery_level_charging">Battery charging, <xliff:g id="battery_percentage">%d</xliff:g> percent.</string>
+
     <!-- Content description of the button for showing a settings panel in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_settings_button">System settings.</string>
 
diff --git a/packages/SystemUI/src/com/android/systemui/DensityContainer.java b/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java
similarity index 66%
rename from packages/SystemUI/src/com/android/systemui/DensityContainer.java
rename to packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java
index 2e3cb49..0afab88 100644
--- a/packages/SystemUI/src/com/android/systemui/DensityContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java
@@ -19,6 +19,7 @@
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
+import android.util.LocaleList;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.FrameLayout;
@@ -26,31 +27,47 @@
 import java.util.ArrayList;
 import java.util.List;
 
-public class DensityContainer extends FrameLayout {
+/**
+ * Custom {@link FrameLayout} that re-inflates when changes to {@link Configuration} happen.
+ * Currently supports changes to density and locale.
+ */
+public class AutoReinflateContainer extends FrameLayout {
 
     private final List<InflateListener> mInflateListeners = new ArrayList<>();
     private final int mLayout;
     private int mDensity;
+    private LocaleList mLocaleList;
 
-    public DensityContainer(Context context, @Nullable AttributeSet attrs) {
+    public AutoReinflateContainer(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
 
         mDensity = context.getResources().getConfiguration().densityDpi;
+        mLocaleList = context.getResources().getConfiguration().getLocales();
 
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DensityContainer);
-        if (!a.hasValue(R.styleable.DensityContainer_android_layout)) {
-            throw new IllegalArgumentException("DensityContainer must contain a layout");
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AutoReinflateContainer);
+        if (!a.hasValue(R.styleable.AutoReinflateContainer_android_layout)) {
+            throw new IllegalArgumentException("AutoReinflateContainer must contain a layout");
         }
-        mLayout = a.getResourceId(R.styleable.DensityContainer_android_layout, 0);
+        mLayout = a.getResourceId(R.styleable.AutoReinflateContainer_android_layout, 0);
         inflateLayout();
     }
 
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        int density = newConfig.densityDpi;
+        boolean shouldInflateLayout = false;
+        final int density = newConfig.densityDpi;
         if (density != mDensity) {
             mDensity = density;
+            shouldInflateLayout = true;
+        }
+        final LocaleList localeList = newConfig.getLocales();
+        if (localeList != mLocaleList) {
+            mLocaleList = localeList;
+            shouldInflateLayout = true;
+        }
+
+        if (shouldInflateLayout) {
             inflateLayout();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 0bf81e9..d8b95cc 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -89,7 +89,8 @@
     @Override
     public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
         setContentDescription(
-                getContext().getString(R.string.accessibility_battery_level, level));
+                getContext().getString(charging ? R.string.accessibility_battery_level_charging
+                        : R.string.accessibility_battery_level, level));
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
index 5e35d76..851ab77 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
@@ -67,7 +67,7 @@
         // If the phone is rotated to landscape, the calculations would be wrong if xdpi and ydpi
         // were to be used separately. Due negligible differences in xdpi and ydpi we can just
         // take the average.
-        // TODO: make this respect DPI changes.
+        // Note that xdpi and ydpi are the physical pixels per inch and are not affected by scaling.
         mDpi = (displayMetrics.xdpi + displayMetrics.ydpi) / 2.0f;
         mClassifierData = new ClassifierData(mDpi);
         mHistoryEvaluator = new HistoryEvaluator();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
index 7378102..4a8abf7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -26,6 +26,7 @@
 import android.view.View;
 import android.view.ViewTreeObserver.OnPreDrawListener;
 import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
 import android.widget.FrameLayout.LayoutParams;
 
 import com.android.systemui.R;
@@ -131,6 +132,7 @@
                 @Override
                 public void onRecentsFocused() {
                     mRecentsView.requestFocus();
+                    mRecentsView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
                 }
             };
     private final View.OnFocusChangeListener mPipViewFocusChangeListener =
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 44a167b..9fd4b05 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -32,7 +32,6 @@
 import android.hardware.display.DisplayManager;
 import android.os.Bundle;
 import android.util.AttributeSet;
-import android.util.MutableInt;
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.GestureDetector;
@@ -105,6 +104,8 @@
             new PathInterpolator(0.5f, 1f, 0.5f, 1f);
     private static final PathInterpolator DIM_INTERPOLATOR =
             new PathInterpolator(.23f, .87f, .52f, -0.11f);
+    private static final Interpolator IME_ADJUST_INTERPOLATOR =
+            new PathInterpolator(0.2f, 0f, 0.1f, 1f);
 
     private DividerHandleView mHandle;
     private View mBackground;
@@ -701,7 +702,7 @@
             resetBackground();
         } else if (mDockSide == WindowManager.DOCKED_TOP) {
             mBackground.setPivotY(0);
-            mBackground.setScaleY(MINIMIZE_DOCK_SCALE);
+            mBackground.setScaleY(ADJUSTED_FOR_IME_SCALE);
         }
         mAdjustedForIme = adjustedForIme;
     }
@@ -709,20 +710,20 @@
     public void setAdjustedForIme(boolean adjustedForIme, long animDuration) {
         updateDockSide();
         mHandle.animate()
-                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                .setInterpolator(IME_ADJUST_INTERPOLATOR)
                 .setDuration(animDuration)
                 .alpha(adjustedForIme ? 0f : 1f)
                 .start();
         if (mDockSide == WindowManager.DOCKED_TOP) {
             mBackground.setPivotY(0);
             mBackground.animate()
-                    .scaleY(adjustedForIme ? MINIMIZE_DOCK_SCALE : 1f);
+                    .scaleY(adjustedForIme ? ADJUSTED_FOR_IME_SCALE : 1f);
         }
         if (!adjustedForIme) {
             mBackground.animate().withEndAction(mResetBackgroundRunnable);
         }
         mBackground.animate()
-                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                .setInterpolator(IME_ADJUST_INTERPOLATOR)
                 .setDuration(animDuration)
                 .start();
         mAdjustedForIme = adjustedForIme;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 2d5b6d4..8bf32c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -537,8 +537,7 @@
                     );
                 }
             } else if (WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION.equals(action)) {
-                final IntentSender intentSender = (IntentSender) intent
-                        .getParcelableExtra(Intent.EXTRA_INTENT);
+                final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
                 final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
                 try {
                     mContext.startIntentSender(intentSender, null, 0, 0, 0);
@@ -1924,11 +1923,23 @@
             callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
             callBackIntent.setPackage(mContext.getPackageName());
 
-            newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-            newIntent.putExtra(Intent.EXTRA_INTENT, PendingIntent
-                    .getBroadcast(mContext, 0, callBackIntent, 0).getIntentSender());
-            mContext.startActivity(newIntent);
+            PendingIntent callBackPendingIntent = PendingIntent.getBroadcast(
+                    mContext,
+                    0,
+                    callBackIntent,
+                    PendingIntent.FLAG_CANCEL_CURRENT |
+                            PendingIntent.FLAG_ONE_SHOT |
+                            PendingIntent.FLAG_IMMUTABLE
+            );
+            newIntent.putExtra(
+                    Intent.EXTRA_INTENT,
+                    callBackPendingIntent.getIntentSender()
+            );
+            try {
+                ActivityManagerNative.getDefault().startConfirmDeviceCredentialIntent(newIntent);
+            } catch (RemoteException ex) {
+                // ignore
+            }
             return true;
         }
 
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 48cf631..8617104 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -41,9 +41,9 @@
 import android.widget.TextView;
 import com.android.internal.logging.MetricsLogger;
 import com.android.keyguard.KeyguardStatusView;
+import com.android.systemui.AutoReinflateContainer;
+import com.android.systemui.AutoReinflateContainer.InflateListener;
 import com.android.systemui.DejankUtils;
-import com.android.systemui.DensityContainer;
-import com.android.systemui.DensityContainer.InflateListener;
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.Interpolators;
@@ -92,7 +92,7 @@
     private KeyguardUserSwitcher mKeyguardUserSwitcher;
     private KeyguardStatusBarView mKeyguardStatusBar;
     protected QSContainer mQsContainer;
-    private DensityContainer mQsDensityContainer;
+    private AutoReinflateContainer mQsAutoReinflateContainer;
     private KeyguardStatusView mKeyguardStatusView;
     private TextView mClockView;
     private View mReserveNotificationSpace;
@@ -219,8 +219,9 @@
         super.onFinishInflate();
         mKeyguardStatusBar = (KeyguardStatusBarView) findViewById(R.id.keyguard_header);
         mKeyguardStatusView = (KeyguardStatusView) findViewById(R.id.keyguard_status_view);
-        mQsDensityContainer = (DensityContainer) findViewById(R.id.qs_density_container);
-        mQsDensityContainer.addInflateListener(new InflateListener() {
+        mQsAutoReinflateContainer =
+                (AutoReinflateContainer) findViewById(R.id.qs_auto_reinflate_container);
+        mQsAutoReinflateContainer.addInflateListener(new InflateListener() {
             @Override
             public void onInflated(View v) {
                 mQsContainer = (QSContainer) v.findViewById(R.id.quick_settings_container);
@@ -280,11 +281,11 @@
         int panelWidth = getResources().getDimensionPixelSize(R.dimen.notification_panel_width);
         int panelGravity = getResources().getInteger(R.integer.notification_panel_layout_gravity);
         FrameLayout.LayoutParams lp =
-                (FrameLayout.LayoutParams) mQsDensityContainer.getLayoutParams();
+                (FrameLayout.LayoutParams) mQsAutoReinflateContainer.getLayoutParams();
         if (lp.width != panelWidth) {
             lp.width = panelWidth;
             lp.gravity = panelGravity;
-            mQsDensityContainer.setLayoutParams(lp);
+            mQsAutoReinflateContainer.setLayoutParams(lp);
             mQsContainer.post(mUpdateHeader);
         }
 
@@ -790,8 +791,8 @@
     }
 
     private boolean isInQsArea(float x, float y) {
-        return (x >= mQsDensityContainer.getX()
-                && x <= mQsDensityContainer.getX() + mQsDensityContainer.getWidth())
+        return (x >= mQsAutoReinflateContainer.getX()
+                && x <= mQsAutoReinflateContainer.getX() + mQsAutoReinflateContainer.getWidth())
                 && (y <= mNotificationStackScroller.getBottomMostNotificationBottom()
                 || y <= mQsContainer.getY() + mQsContainer.getHeight());
     }
@@ -1339,8 +1340,8 @@
             return false;
         }
         View header = mKeyguardShowing ? mKeyguardStatusBar : mQsContainer.getHeader();
-        boolean onHeader = x >= mQsDensityContainer.getX()
-                && x <= mQsDensityContainer.getX() + mQsDensityContainer.getWidth()
+        boolean onHeader = x >= mQsAutoReinflateContainer.getX()
+                && x <= mQsAutoReinflateContainer.getX() + mQsAutoReinflateContainer.getWidth()
                 && y >= header.getTop() && y <= header.getBottom();
         if (mQsExpanded) {
             return onHeader || (yDiff < 0 && isInQsArea(x, y));
@@ -2227,7 +2228,7 @@
 
     protected void setVerticalPanelTranslation(float translation) {
         mNotificationStackScroller.setTranslationX(translation);
-        mQsDensityContainer.setTranslationX(translation);
+        mQsAutoReinflateContainer.setTranslationX(translation);
     }
 
     protected void updateStackHeight(float stackHeight) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index 35fb2a5..36e59db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -24,7 +24,7 @@
 import android.view.ViewStub;
 import android.view.WindowInsets;
 import android.widget.FrameLayout;
-import com.android.systemui.DensityContainer;
+import com.android.systemui.AutoReinflateContainer;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSContainer;
 import com.android.systemui.qs.customize.QSCustomizer;
@@ -33,10 +33,10 @@
  * The container with notification stack scroller and quick settings inside.
  */
 public class NotificationsQuickSettingsContainer extends FrameLayout
-        implements ViewStub.OnInflateListener, DensityContainer.InflateListener {
+        implements ViewStub.OnInflateListener, AutoReinflateContainer.InflateListener {
 
 
-    private DensityContainer mQsContainer;
+    private AutoReinflateContainer mQsContainer;
     private View mUserSwitcher;
     private View mStackScroller;
     private View mKeyguardStatusBar;
@@ -54,7 +54,7 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mQsContainer = (DensityContainer) findViewById(R.id.qs_density_container);
+        mQsContainer = (AutoReinflateContainer) findViewById(R.id.qs_auto_reinflate_container);
         mQsContainer.addInflateListener(this);
         mStackScroller = findViewById(R.id.notification_stack_scroller);
         mStackScrollerMargin = ((LayoutParams) mStackScroller.getLayoutParams()).bottomMargin;
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 712f814..c36c482 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -103,10 +103,10 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.AutoReinflateContainer;
+import com.android.systemui.AutoReinflateContainer.InflateListener;
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.DemoMode;
-import com.android.systemui.DensityContainer;
-import com.android.systemui.DensityContainer.InflateListener;
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.Interpolators;
@@ -871,8 +871,8 @@
         }
 
         // Set up the quick settings tile panel
-        DensityContainer container = (DensityContainer) mStatusBarWindow.findViewById(
-                R.id.qs_density_container);
+        AutoReinflateContainer container = (AutoReinflateContainer) mStatusBarWindow.findViewById(
+                R.id.qs_auto_reinflate_container);
         if (container != null) {
             final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
                     mBluetoothController, mLocationController, mRotationLockController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 3293964..66152fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -61,6 +61,7 @@
     private Calendar mCalendar;
     private String mClockFormatString;
     private SimpleDateFormat mClockFormat;
+    private SimpleDateFormat mContentDescriptionFormat;
     private Locale mLocale;
 
     private static final int AM_PM_STYLE_NORMAL  = 0;
@@ -158,6 +159,7 @@
         if (mDemoMode) return;
         mCalendar.setTimeInMillis(System.currentTimeMillis());
         setText(getSmallTime());
+        setContentDescription(mContentDescriptionFormat.format(mCalendar.getTime()));
     }
 
     @Override
@@ -207,6 +209,7 @@
                 ? is24 ? d.timeFormat_Hms : d.timeFormat_hms
                 : is24 ? d.timeFormat_Hm : d.timeFormat_hm;
         if (!format.equals(mClockFormatString)) {
+            mContentDescriptionFormat = new SimpleDateFormat(format);
             /*
              * Search for an unquoted "a" in the format string, so we can
              * add dummy characters around it to let us find it again after
@@ -295,6 +298,7 @@
                 mCalendar.set(Calendar.MINUTE, mm);
             }
             setText(getSmallTime());
+            setContentDescription(mContentDescriptionFormat.format(mCalendar.getTime()));
         }
     }
 
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 557f166..ecd1772 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -105,7 +105,6 @@
                 return false;
             }
         });
-        mEditText.setOnClickListener(this);
         mEditText.addTextChangedListener(this);
         mEditText.setInnerFocusable(false);
         mEditText.mRemoteInputView = this;
@@ -148,15 +147,19 @@
 
     @Override
     public void onClick(View v) {
-        if (v == mEditText) {
-            if (!mEditText.isFocusable()) {
-                focus();
-            }
-        } else if (v == mSendButton) {
+        if (v == mSendButton) {
             sendRemoteInput();
         }
     }
 
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        super.onTouchEvent(event);
+
+        // We never want for a touch to escape to an outer view or one we covered.
+        return true;
+    }
+
     public void onDefocus() {
         mController.removeRemoteInput(mEntry);
         mEntry.remoteInputText = mEditText.getText();
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlButtonView.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlButtonView.java
index c65415e..bcf2f67 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlButtonView.java
@@ -92,8 +92,8 @@
         TypedArray typedArray =
             context.obtainStyledAttributes(attrs, values, defStyleAttr, defStyleRes);
 
-        mButtonImageView.setImageDrawable(typedArray.getDrawable(0));
-        mDescriptionTextView.setText(typedArray.getText(1));
+        setImageResource(typedArray.getResourceId(0, 0));
+        setText(typedArray.getResourceId(1, 0));
 
         typedArray.recycle();
     }
@@ -132,6 +132,7 @@
      * Sets the text for description the with the given resource id.
      */
     public void setText(int resId) {
+        mButtonImageView.setContentDescription(getContext().getString(resId));
         mDescriptionTextView.setText(resId);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index 5febb9b..d7efca7 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -276,9 +276,6 @@
     void movePipToFullscreen() {
         mState = STATE_NO_PIP;
         mPipTaskId = TASK_ID_NO_PIP;
-        for (int i = mListeners.size() - 1; i >= 0; --i) {
-            mListeners.get(i).onMoveToFullscreen();
-        }
         resizePinnedStack(mState);
     }
 
@@ -638,6 +635,11 @@
         public void onPinnedStackAnimationEnded() {
             if (DEBUG) Log.d(TAG, "onPinnedStackAnimationEnded()");
             switch (mState) {
+                case STATE_NO_PIP:
+                    for (int i = mListeners.size() - 1; i >= 0; --i) {
+                        mListeners.get(i).onMoveToFullscreen();
+                    }
+                    break;
                 case STATE_PIP_OVERLAY:
                     if (!mPipRecentsOverlayManager.isRecentsShown()) {
                         showPipOverlay();
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
index d75561b..dd12360 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
@@ -21,6 +21,7 @@
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManager;
 
@@ -133,7 +134,7 @@
      */
     public void requestFocus(boolean allowRecentsFocusable) {
         mRecentsView.setVisibility(allowRecentsFocusable ? View.VISIBLE : View.GONE);
-        if (!mIsRecentsShown || mIsPipFocusedInRecent) {
+        if (!mIsPipRecentsOverlayShown || !mIsRecentsShown || mIsPipFocusedInRecent) {
             return;
         }
         mIsPipFocusedInRecent = true;
@@ -141,6 +142,7 @@
 
         mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
         mPipControlsView.requestFocus();
+        mPipControlsView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
         mPipControlsView.startFocusGainAnimation();
     }
 
@@ -151,7 +153,7 @@
      * This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}.
      */
     public void clearFocus() {
-        if (!mIsRecentsShown || !mIsPipFocusedInRecent) {
+        if (!mIsPipRecentsOverlayShown || !mIsRecentsShown || !mIsPipFocusedInRecent) {
             return;
         }
         if (!mRecentsView.hasFocus()) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index de70139..0153a40 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -18,6 +18,7 @@
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.animation.LayoutTransition;
+import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.annotation.SuppressLint;
 import android.app.Dialog;
@@ -59,6 +60,7 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
+import android.view.animation.DecelerateInterpolator;
 import android.widget.ImageButton;
 import android.widget.LinearLayout;
 import android.widget.SeekBar;
@@ -92,6 +94,7 @@
     public static final String SHOW_FULL_ZEN = "sysui_show_full_zen";
 
     private static final long USER_ATTEMPT_GRACE_PERIOD = 1000;
+    private static final int UPDATE_ANIMATION_DURATION = 80;
 
     private final Context mContext;
     private final H mHandler = new H();
@@ -369,6 +372,14 @@
         writer.println(mAccessibility.mFeedbackEnabled);
     }
 
+    private static int getImpliedLevel(SeekBar seekBar, int progress) {
+        final int m = seekBar.getMax();
+        final int n = m / 100 - 1;
+        final int level = progress == 0 ? 0
+                : progress == m ? (m / 100) : (1 + (int)((progress / (float) m) * n));
+        return level;
+    }
+
     @SuppressLint("InflateParams")
     private void initRow(final VolumeRow row, final int stream, int iconRes, int iconMuteRes,
             boolean important) {
@@ -707,7 +718,7 @@
                 : false;
 
         // update slider max
-        final int max = ss.levelMax;
+        final int max = ss.levelMax * 100;
         if (max != row.slider.getMax()) {
             row.slider.setMax(max);
         }
@@ -824,7 +835,8 @@
         if (row.tracking) {
             return;  // don't update if user is sliding
         }
-        final int level = row.slider.getProgress();
+        final int progress = row.slider.getProgress();
+        final int level = getImpliedLevel(row.slider, progress);
         final boolean rowVisible = row.view.getVisibility() == View.VISIBLE;
         final boolean inGracePeriod = (SystemClock.uptimeMillis() - row.userAttempt)
                 < USER_ATTEMPT_GRACE_PERIOD;
@@ -840,7 +852,33 @@
                 return;  // don't clamp if visible
             }
         }
-        row.slider.setProgress(vlevel, true);
+        final int newProgress = vlevel * 100;
+        if (progress != newProgress) {
+            if (mShowing && rowVisible) {
+                // animate!
+                if (row.anim != null && row.anim.isRunning()
+                        && row.animTargetProgress == newProgress) {
+                    return;  // already animating to the target progress
+                }
+                // start/update animation
+                if (row.anim == null) {
+                    row.anim = ObjectAnimator.ofInt(row.slider, "progress", progress, newProgress);
+                    row.anim.setInterpolator(new DecelerateInterpolator());
+                } else {
+                    row.anim.cancel();
+                    row.anim.setIntValues(progress, newProgress);
+                }
+                row.animTargetProgress = newProgress;
+                row.anim.setDuration(UPDATE_ANIMATION_DURATION);
+                row.anim.start();
+            } else {
+                // update slider directly to clamped value
+                if (row.anim != null) {
+                    row.anim.cancel();
+                }
+                row.slider.setProgress(newProgress);
+            }
+        }
     }
 
     private void recheckH(VolumeRow row) {
@@ -1060,19 +1098,20 @@
                     + " onProgressChanged " + progress + " fromUser=" + fromUser);
             if (!fromUser) return;
             if (mRow.ss.levelMin > 0) {
-                final int minProgress = mRow.ss.levelMin;
+                final int minProgress = mRow.ss.levelMin * 100;
                 if (progress < minProgress) {
                     seekBar.setProgress(minProgress);
                     progress = minProgress;
                 }
             }
-            if (mRow.ss.level != progress || mRow.ss.muted && progress > 0) {
+            final int userLevel = getImpliedLevel(seekBar, progress);
+            if (mRow.ss.level != userLevel || mRow.ss.muted && userLevel > 0) {
                 mRow.userAttempt = SystemClock.uptimeMillis();
-                if (mRow.requestedLevel != progress) {
-                    mController.setStreamVolume(mRow.stream, progress);
-                    mRow.requestedLevel = progress;
+                if (mRow.requestedLevel != userLevel) {
+                    mController.setStreamVolume(mRow.stream, userLevel);
+                    mRow.requestedLevel = userLevel;
                     Events.writeEvent(mContext, Events.EVENT_TOUCH_LEVEL_CHANGED, mRow.stream,
-                            progress);
+                            userLevel);
                 }
             }
         }
@@ -1089,7 +1128,7 @@
             if (D.BUG) Log.d(TAG, "onStopTrackingTouch"+ " " + mRow.stream);
             mRow.tracking = false;
             mRow.userAttempt = SystemClock.uptimeMillis();
-            final int userLevel = seekBar.getProgress();
+            final int userLevel = getImpliedLevel(seekBar, seekBar.getProgress());
             Events.writeEvent(mContext, Events.EVENT_TOUCH_LEVEL_DONE, mRow.stream, userLevel);
             if (mRow.ss.level != userLevel) {
                 mHandler.sendMessageDelayed(mHandler.obtainMessage(H.RECHECK, mRow),
@@ -1169,6 +1208,8 @@
         private ColorStateList cachedSliderTint;
         private int iconState;  // from Events
         private boolean cachedShowHeaders = VolumePrefs.DEFAULT_SHOW_HEADERS;
+        private ObjectAnimator anim;  // slider progress animation for non-touch-related updates
+        private int animTargetProgress;
         private int lastAudibleLevel = 1;
     }
 
diff --git a/packages/WallpaperBackup/Android.mk b/packages/WallpaperBackup/Android.mk
new file mode 100644
index 0000000..cf04249
--- /dev/null
+++ b/packages/WallpaperBackup/Android.mk
@@ -0,0 +1,34 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+LOCAL_PACKAGE_NAME := WallpaperBackup
+LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := false
+
+include $(BUILD_PACKAGE)
+
+########################
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/packages/WallpaperBackup/AndroidManifest.xml b/packages/WallpaperBackup/AndroidManifest.xml
new file mode 100644
index 0000000..b8cea20
--- /dev/null
+++ b/packages/WallpaperBackup/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016 Google Inc.
+ *
+ * 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.wallpaperbackup"
+    android:sharedUserId="android.uid.system" >
+
+    <application android:allowClearUserData="false"
+                 android:process="system"
+                 android:killAfterRestore="false"
+                 android:allowBackup="true"
+                 android:backupAgent=".WallpaperBackupAgent"
+                 android:fullBackupOnly="true" >
+    </application>
+</manifest>
diff --git a/packages/WallpaperBackup/proguard.flags b/packages/WallpaperBackup/proguard.flags
new file mode 100644
index 0000000..247e6ef
--- /dev/null
+++ b/packages/WallpaperBackup/proguard.flags
@@ -0,0 +1 @@
+-keep class com.android.wallpaperbackup.WallpaperBackupAgent
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
new file mode 100644
index 0000000..2f79079
--- /dev/null
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -0,0 +1,164 @@
+/*
+ * 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.wallpaperbackup;
+
+import android.app.WallpaperManager;
+import android.app.backup.BackupAgent;
+import android.app.backup.BackupDataInput;
+import android.app.backup.BackupDataOutput;
+import android.app.backup.FullBackupDataOutput;
+import android.content.Context;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
+import android.system.Os;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class WallpaperBackupAgent extends BackupAgent {
+    private static final String TAG = "WallpaperBackup";
+    private static final boolean DEBUG = false;
+
+    // NB: must be kept in sync with WallpaperManagerService but has no
+    // compile-time visiblity.
+
+    // Target filenames within the system's wallpaper directory
+    static final String WALLPAPER = "wallpaper_orig";
+    static final String WALLPAPER_INFO = "wallpaper_info.xml";
+
+    // Names of our local-data stage files/links
+    static final String IMAGE_STAGE = "wallpaper-stage";
+    static final String INFO_STAGE = "wallpaper-info-stage";
+    static final String EMPTY_SENTINEL = "empty";
+
+    private File mWallpaperInfo;    // wallpaper metadata file
+    private File mWallpaperFile;    // primary wallpaper image file
+
+    private WallpaperManager mWm;
+
+    @Override
+    public void onCreate() {
+        if (DEBUG) {
+            Slog.v(TAG, "onCreate()");
+        }
+
+        File wallpaperDir = Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM);
+        mWallpaperInfo = new File(wallpaperDir, WALLPAPER_INFO);
+        mWallpaperFile = new File(wallpaperDir, WALLPAPER);
+        mWm = (WallpaperManager) getSystemService(Context.WALLPAPER_SERVICE);
+    }
+
+    @Override
+    public void onFullBackup(FullBackupDataOutput data) throws IOException {
+        // To avoid data duplication and disk churn, use links as the stage.
+        final File filesDir = getFilesDir();
+        final File infoStage = new File(filesDir, INFO_STAGE);
+        final File imageStage = new File (filesDir, IMAGE_STAGE);
+        final File empty = new File (filesDir, EMPTY_SENTINEL);
+
+        try {
+            // We always back up this 'empty' file to ensure that the absence of
+            // storable wallpaper imagery still produces a non-empty backup data
+            // stream, otherwise it'd simply be ignored in preflight.
+            FileOutputStream touch = new FileOutputStream(empty);
+            touch.close();
+            fullBackupFile(empty, data);
+
+            // only back up the wallpaper if we've been told it's allowed
+            if (mWm.isWallpaperBackupEligible()) {
+                if (DEBUG) {
+                    Slog.v(TAG, "Wallpaper is backup-eligible; linking & writing");
+                }
+                Os.link(mWallpaperInfo.getCanonicalPath(), infoStage.getCanonicalPath());
+                fullBackupFile(infoStage, data);
+                Os.link(mWallpaperFile.getCanonicalPath(), imageStage.getCanonicalPath());
+                fullBackupFile(imageStage, data);
+            } else {
+                if (DEBUG) {
+                    Slog.v(TAG, "Wallpaper not backup-eligible; writing no data");
+                }
+            }
+        } catch (Exception e) {
+            Slog.e(TAG, "Unable to back up wallpaper: " + e.getMessage());
+        } finally {
+            if (DEBUG) {
+                Slog.v(TAG, "Removing backup stage links");
+            }
+            infoStage.delete();
+            imageStage.delete();
+        }
+    }
+
+    // We use the default onRestoreFile() implementation that will recreate our stage files,
+    // then postprocess in onRestoreFinished() to move them on top of the live data.
+    //
+    // NOTE: this relies on our local files dir being on the same filesystem as the live
+    // system wallpaper data.  If this is not the case then an actual copy operation will
+    // be needed.
+    @Override
+    public void onRestoreFinished() {
+        if (DEBUG) {
+            Slog.v(TAG, "onRestoreFinished()");
+        }
+        final File infoStage = new File(getFilesDir(), INFO_STAGE);
+        final File imageStage = new File (getFilesDir(), IMAGE_STAGE);
+
+        try {
+            // It is valid for the imagery to be absent; it means that we were not permitted
+            // to back up the original image on the source device.
+            if (imageStage.exists()) {
+                if (DEBUG) {
+                    Slog.v(TAG, "Got restored wallpaper; renaming into place");
+                }
+                // Rename the image file into place last because that is the trigger for
+                // the wallpaper observer to generate a new crop/scale
+                Os.rename(infoStage.getCanonicalPath(), mWallpaperInfo.getCanonicalPath());
+                Os.rename(imageStage.getCanonicalPath(), mWallpaperFile.getCanonicalPath());
+            }
+        } catch (Exception e) {
+            Slog.e(TAG, "Unable to restore wallpaper: " + e.getMessage());
+            mWm.clearWallpaper(WallpaperManager.FLAG_SYSTEM, UserHandle.USER_SYSTEM);
+        } finally {
+            // These "should" not exist because of the renames, but make sure
+            // in case of errors/exceptions/etc.
+            if (DEBUG) {
+                Slog.v(TAG, "Removing restore stage files");
+            }
+            infoStage.delete();
+            imageStage.delete();
+        }
+    }
+
+    //
+    // Key/value API: abstract, so required, but not used
+    //
+
+    @Override
+    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+            ParcelFileDescriptor newState) throws IOException {
+        // Intentionally blank
+    }
+
+    @Override
+    public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
+            throws IOException {
+        // Intentionally blank
+    }
+}
\ No newline at end of file
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 4d7f82d..2a7d945 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -20,6 +20,7 @@
 import android.os.PowerManager;
 import android.util.Pools.SimplePool;
 import android.util.Slog;
+import android.util.SparseBooleanArray;
 import android.view.Choreographer;
 import android.view.InputDevice;
 import android.view.InputEvent;
@@ -637,10 +638,10 @@
     }
 
     /**
-     * Keeps state of stream of events from a keyboard device.
+     * Keeps state of streams of events from all keyboard devices.
      */
     private static class KeyboardEventStreamState extends EventStreamState {
-        private boolean mEventSequenceStarted;
+        private SparseBooleanArray mEventSequenceStartedMap = new SparseBooleanArray();
 
         public KeyboardEventStreamState() {
             reset();
@@ -649,17 +650,35 @@
         @Override
         final public void reset() {
             super.reset();
-            mEventSequenceStarted = false;
+            mEventSequenceStartedMap.clear();
         }
 
+        /*
+         * Key events from different devices may be interleaved. For example, the volume up and
+         * down keys can come from different device IDs.
+         */
+        @Override
+        public boolean updateDeviceId(int deviceId) {
+            return false;
+        }
+
+        // We manage all device ids simultaneously; there is no concept of validity.
+        @Override
+        public boolean deviceIdValid() {
+            return true;
+        }
+
+
         @Override
         final public boolean shouldProcessKeyEvent(KeyEvent event) {
-            // Wait for a down key event to start processing.
-            if (mEventSequenceStarted) {
+            // For each keyboard device, wait for a down event from a device to start processing
+            int deviceId = event.getDeviceId();
+            if (mEventSequenceStartedMap.get(deviceId, false)) {
                 return true;
             }
-            mEventSequenceStarted = event.getAction() == KeyEvent.ACTION_DOWN;
-            return mEventSequenceStarted;
+            boolean shouldProcess = event.getAction() == KeyEvent.ACTION_DOWN;
+            mEventSequenceStartedMap.put(deviceId, shouldProcess);
+            return shouldProcess;
         }
     }
 }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 71506be..b965f64 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -71,7 +71,7 @@
 import android.net.RouteInfo;
 import android.net.UidRange;
 import android.net.Uri;
-import android.net.metrics.ConnectivityServiceChangeEvent;
+import android.net.metrics.DefaultNetworkEvent;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -2217,7 +2217,7 @@
             rematchAllNetworksAndRequests(null, 0);
             if (wasDefault && getDefaultNetwork() == null) {
                 // Log that we lost the default network and there is no replacement.
-                logConnectivityServiceChangeEvent(null, nai);
+                logDefaultNetworkEvent(null, nai);
             }
             if (nai.created) {
                 // Tell netd to clean up the configuration for this network
@@ -2330,6 +2330,18 @@
             if (VDBG || (DBG && nri.isRequest())) log("releasing NetworkRequest " + request);
             nri.unlinkDeathRecipient();
             mNetworkRequests.remove(request);
+            synchronized (mUidToNetworkRequestCount) {
+                int requests = mUidToNetworkRequestCount.get(nri.mUid, 0);
+                if (requests < 1) {
+                    Slog.wtf(TAG, "BUG: too small request count " + requests + " for UID " +
+                            nri.mUid);
+                } else if (requests == 1) {
+                    mUidToNetworkRequestCount.removeAt(
+                            mUidToNetworkRequestCount.indexOfKey(nri.mUid));
+                } else {
+                    mUidToNetworkRequestCount.put(nri.mUid, requests - 1);
+                }
+            }
             mNetworkRequestInfoLogs.log("RELEASE " + nri);
             if (nri.isRequest()) {
                 // Find all networks that are satisfying this request and remove the request
@@ -3677,6 +3689,11 @@
     private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests =
             new HashMap<NetworkRequest, NetworkRequestInfo>();
 
+    private static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
+    // Map from UID to number of NetworkRequests that UID has filed.
+    @GuardedBy("mUidToNetworkRequestCount")
+    private final SparseIntArray mUidToNetworkRequestCount = new SparseIntArray();
+
     private static class NetworkFactoryInfo {
         public final String name;
         public final Messenger messenger;
@@ -3737,6 +3754,7 @@
             mPid = getCallingPid();
             mUid = getCallingUid();
             mType = type;
+            enforceRequestCountLimit();
         }
 
         NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder, NetworkRequestType type) {
@@ -3748,6 +3766,7 @@
             mUid = getCallingUid();
             mType = type;
             mPendingIntent = null;
+            enforceRequestCountLimit();
 
             try {
                 mBinder.linkToDeath(this, 0);
@@ -3756,6 +3775,16 @@
             }
         }
 
+        private void enforceRequestCountLimit() {
+            synchronized (mUidToNetworkRequestCount) {
+                int networkRequests = mUidToNetworkRequestCount.get(mUid, 0) + 1;
+                if (networkRequests >= MAX_NETWORK_REQUESTS_PER_UID) {
+                    throw new IllegalArgumentException("Too many NetworkRequests filed");
+                }
+                mUidToNetworkRequestCount.put(mUid, networkRequests);
+            }
+        }
+
         private String typeString() {
             switch (mType) {
                 case LISTEN: return "Listen";
@@ -4452,8 +4481,7 @@
         handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
         updateTcpBufferSizes(newNetwork);
         setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
-
-        logConnectivityServiceChangeEvent(newNetwork, prevNetwork);
+        logDefaultNetworkEvent(newNetwork, prevNetwork);
     }
 
     // Handles a network appearing or improving its score.
@@ -5075,21 +5103,24 @@
         return new NetworkMonitor(context, handler, nai, defaultRequest);
     }
 
-    private static void logConnectivityServiceChangeEvent(
-            NetworkAgentInfo next, NetworkAgentInfo prev) {
-        final int newNetId = (next == null) ? NETID_UNSET : next.network.netId;
-        final int[] newTransportTypes = (next == null)
-                ? new int[0]
-                : next.networkCapabilities.getTransportTypes();
+    private static void logDefaultNetworkEvent(NetworkAgentInfo newNai, NetworkAgentInfo prevNai) {
+        int newNetid = NETID_UNSET;
+        int prevNetid = NETID_UNSET;
+        int[] transports = new int[0];
+        boolean hadIPv4 = false;
+        boolean hadIPv6 = false;
 
-        final int oldNetId = (prev == null) ? NETID_UNSET : prev.network.netId;
-        final boolean hadIPv4 = (prev != null) &&
-                prev.linkProperties.hasIPv4Address() &&
-                prev.linkProperties.hasIPv4DefaultRoute();
-        final boolean hadIPv6 = (prev != null) &&
-                prev.linkProperties.hasGlobalIPv6Address() &&
-                prev.linkProperties.hasIPv6DefaultRoute();
-        ConnectivityServiceChangeEvent.logEvent(newNetId, newTransportTypes,
-                oldNetId, hadIPv4, hadIPv6);
+        if (newNai != null) {
+            newNetid = newNai.network.netId;
+            transports = newNai.networkCapabilities.getTransportTypes();
+        }
+        if (prevNai != null) {
+            prevNetid = prevNai.network.netId;
+            final LinkProperties lp = prevNai.linkProperties;
+            hadIPv4 = lp.hasIPv4Address() && lp.hasIPv4DefaultRoute();
+            hadIPv6 = lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute();
+        }
+
+        DefaultNetworkEvent.logEvent(newNetid, transports, prevNetid, hadIPv4, hadIPv6);
     }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d7afc13..3b024cf 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -11502,6 +11502,19 @@
     }
 
     @Override
+    public void startConfirmDeviceCredentialIntent(Intent intent) {
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "startConfirmDeviceCredentialIntent");
+        synchronized (this) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mActivityStarter.startConfirmCredentialIntent(intent);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
+    @Override
     public void stopAppSwitches() {
         if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
                 != PackageManager.PERMISSION_GRANTED) {
@@ -17159,6 +17172,7 @@
                     || Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)
                     || Intent.ACTION_GET_PERMISSIONS_COUNT.equals(action)
                     || Intent.ACTION_GET_PERMISSIONS_PACKAGES.equals(action)
+                    || Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(action)
                     || AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
                     || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)
                     || LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) {
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 9c93f2c..4da6976 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -33,6 +33,7 @@
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
+import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
 import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
@@ -582,7 +583,7 @@
                 null /*voiceInteractor*/, null /*resultTo*/, null /*resultWho*/,
                 0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/, null /*callingPackage*/,
                 0 /*realCallingPid*/, 0 /*realCallingUid*/, 0 /*startFlags*/, null /*options*/,
-                false /*ignoreTargetSecurity*/, false /*componentSpecified*/,  null /*outActivity*/,
+                false /*ignoreTargetSecurity*/, false /*componentSpecified*/, null /*outActivity*/,
                 null /*container*/, null /*inTask*/);
         if (mSupervisor.inResumeTopActivity) {
             // If we are in resume section already, home activity will be initialized, but not
@@ -612,11 +613,6 @@
                 .getSystemService(Context.KEYGUARD_SERVICE);
         final Intent credential =
                 km.createConfirmDeviceCredentialIntent(null, null, userId);
-        credential.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
-                Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
-                Intent.FLAG_ACTIVITY_TASK_ON_HOME);
-        final ActivityOptions options = ActivityOptions.makeBasic();
-        options.setLaunchTaskId(mSupervisor.getHomeActivity().task.taskId);
         final ActivityRecord activityRecord = targetStack.topRunningActivityLocked();
         if (activityRecord != null) {
             final IIntentSender target = mService.getIntentSenderLocked(
@@ -633,11 +629,19 @@
                     null);
             credential.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
             // Show confirm credentials activity.
-            mService.mContext.startActivityAsUser(credential, options.toBundle(),
-                    UserHandle.CURRENT);
+            startConfirmCredentialIntent(credential);
         }
     }
 
+    void startConfirmCredentialIntent(Intent intent) {
+        intent.addFlags(FLAG_ACTIVITY_NEW_TASK |
+                FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
+                FLAG_ACTIVITY_TASK_ON_HOME);
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchTaskId(mSupervisor.getHomeActivity().task.taskId);
+        mService.mContext.startActivityAsUser(intent, options.toBundle(),
+                UserHandle.CURRENT);
+    }
 
     final int startActivityMayWait(IApplicationThread caller, int callingUid,
             String callingPackage, Intent intent, String resolvedType,
@@ -1432,7 +1436,7 @@
                             == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
                 if (!willClearTask) {
                     final ActivityStack launchStack = getLaunchStack(
-                            mStartActivity, mLaunchFlags, mStartActivity.task, mOptions, true);
+                            mStartActivity, mLaunchFlags, mStartActivity.task, mOptions);
                     if (launchStack == null || launchStack == mTargetStack) {
                         // We only want to move to the front, if we aren't going to launch on a
                         // different stack. If we launch on a different stack, we will put the
@@ -1606,8 +1610,11 @@
         // We only want to allow changing stack if the target task is not the top one,
         // otherwise we would move the launching task to the other side, rather than show
         // two side by side.
-        final boolean launchToSideAllowed = sourceTask.stack.topTask() != sourceTask;
-        mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task, mOptions, launchToSideAllowed);
+        final boolean moveStackAllowed = sourceTask.stack.topTask() != sourceTask;
+        if (moveStackAllowed) {
+            mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task,
+                    mOptions);
+        }
 
         if (mTargetStack == null) {
             mTargetStack = sourceTask.stack;
@@ -1780,7 +1787,7 @@
             return mSupervisor.mHomeStack;
         }
 
-        ActivityStack stack = getLaunchStack(r, launchFlags, task, aOptions, true);
+        ActivityStack stack = getLaunchStack(r, launchFlags, task, aOptions);
         if (stack != null) {
             return stack;
         }
@@ -1845,7 +1852,7 @@
     }
 
     private ActivityStack getLaunchStack(ActivityRecord r, int launchFlags, TaskRecord task,
-            ActivityOptions aOptions, boolean launchToSideAllowed) {
+            ActivityOptions aOptions) {
         final int launchStackId =
                 (aOptions != null) ? aOptions.getLaunchStackId() : INVALID_STACK_ID;
 
@@ -1857,7 +1864,7 @@
             return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
         }
 
-        if (!launchToSideAllowed || (launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) == 0) {
+        if ((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) == 0) {
             return null;
         }
         // Otherwise handle adjacent launch.
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index a2472ac..48fecd5 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -17,8 +17,6 @@
 package com.android.server.am;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.ActivityManager;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.os.Debug;
@@ -519,7 +517,7 @@
         if (DEBUG) Slog.d(TAG, "removeObsoleteFiles: persistentTaskIds=" + persistentTaskIds +
                 " files=" + files);
         if (files == null) {
-            Slog.e(TAG, "File error accessing recents directory (too many files open?).");
+            Slog.e(TAG, "File error accessing recents directory (directory doesn't exist?).");
             return;
         }
         for (int fileNdx = 0; fileNdx < files.length; ++fileNdx) {
@@ -597,15 +595,12 @@
     }
 
     static File getUserImagesDir(int userId) {
-        File userImagesDir = new File(Environment.getDataSystemCeDirectory(userId), IMAGES_DIRNAME);
+        return new File(Environment.getDataSystemCeDirectory(userId), IMAGES_DIRNAME);
+    }
 
-        if (!userImagesDir.exists()) {
-            if (!userImagesDir.mkdir()) {
-                Slog.e(TAG, "Failure creating images directory for user " + userId + ": "
-                        + userImagesDir);
-            }
-        }
-        return userImagesDir;
+    private static boolean createParentDirectory(String filePath) {
+        File parentDir = new File(filePath).getParentFile();
+        return parentDir.exists() || parentDir.mkdirs();
     }
 
     private class LazyTaskWriterThread extends Thread {
@@ -693,6 +688,10 @@
                 if (item instanceof ImageWriteQueueItem) {
                     ImageWriteQueueItem imageWriteQueueItem = (ImageWriteQueueItem) item;
                     final String filePath = imageWriteQueueItem.mFilePath;
+                    if (!createParentDirectory(filePath)) {
+                        Slog.e(TAG, "Error while creating images directory for file: " + filePath);
+                        continue;
+                    }
                     final Bitmap bitmap = imageWriteQueueItem.mImage;
                     if (DEBUG) Slog.d(TAG, "writing bitmap: filename=" + filePath);
                     FileOutputStream imageFile = null;
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index d330756..381a110 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -36,8 +36,10 @@
 import android.net.Uri;
 import android.net.metrics.CaptivePortalCheckResultEvent;
 import android.net.metrics.CaptivePortalStateChangeEvent;
+import android.net.metrics.NetworkMonitorEvent;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
+import android.net.util.Stopwatch;
 import android.os.Handler;
 import android.os.Message;
 import android.os.Process;
@@ -79,7 +81,7 @@
  */
 public class NetworkMonitor extends StateMachine {
     private static final boolean DBG = false;
-    private static final String TAG = "NetworkMonitor";
+    private static final String TAG = NetworkMonitor.class.getSimpleName();
     private static final String DEFAULT_SERVER = "connectivitycheck.gstatic.com";
     private static final int SOCKET_TIMEOUT_MS = 10000;
     public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
@@ -221,6 +223,7 @@
     private final Context mContext;
     private final Handler mConnectivityServiceHandler;
     private final NetworkAgentInfo mNetworkAgentInfo;
+    private final int mNetId;
     private final TelephonyManager mTelephonyManager;
     private final WifiManager mWifiManager;
     private final AlarmManager mAlarmManager;
@@ -246,6 +249,8 @@
 
     private final LocalLog validationLogs = new LocalLog(20); // 20 lines
 
+    private final Stopwatch mEvaluationTimer = new Stopwatch();
+
     public NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo,
             NetworkRequest defaultRequest) {
         // Add suffix indicating which NetworkMonitor we're talking about.
@@ -254,6 +259,7 @@
         mContext = context;
         mConnectivityServiceHandler = handler;
         mNetworkAgentInfo = networkAgentInfo;
+        mNetId = mNetworkAgentInfo.network.netId;
         mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
@@ -300,12 +306,12 @@
                     transitionTo(mLingeringState);
                     return HANDLED;
                 case CMD_NETWORK_CONNECTED:
-                    CaptivePortalStateChangeEvent.logEvent(
+                    CaptivePortalStateChangeEvent.logEvent(mNetId,
                             CaptivePortalStateChangeEvent.NETWORK_MONITOR_CONNECTED);
                     transitionTo(mEvaluatingState);
                     return HANDLED;
                 case CMD_NETWORK_DISCONNECTED:
-                    CaptivePortalStateChangeEvent.logEvent(
+                    CaptivePortalStateChangeEvent.logEvent(mNetId,
                             CaptivePortalStateChangeEvent.NETWORK_MONITOR_DISCONNECTED);
                     if (mLaunchCaptivePortalAppBroadcastReceiver != null) {
                         mContext.unregisterReceiver(mLaunchCaptivePortalAppBroadcastReceiver);
@@ -336,7 +342,7 @@
                             mUserDoesNotWant = true;
                             mConnectivityServiceHandler.sendMessage(obtainMessage(
                                     EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID,
-                                    mNetworkAgentInfo.network.netId, null));
+                                    mNetId, null));
                             // TODO: Should teardown network.
                             mUidResponsibleForReeval = 0;
                             transitionTo(mEvaluatingState);
@@ -356,7 +362,11 @@
     private class ValidatedState extends State {
         @Override
         public void enter() {
-            CaptivePortalStateChangeEvent.logEvent(
+            if (mEvaluationTimer.isRunning()) {
+                NetworkMonitorEvent.logValidated(mNetId, mEvaluationTimer.stop());
+                mEvaluationTimer.reset();
+            }
+            CaptivePortalStateChangeEvent.logEvent(mNetId,
                    CaptivePortalStateChangeEvent.NETWORK_MONITOR_VALIDATED);
             mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
                     NETWORK_TEST_RESULT_VALID, mNetworkAgentInfo.network.netId, null));
@@ -436,6 +446,12 @@
 
         @Override
         public void enter() {
+            // If we have already started to track time spent in EvaluatingState
+            // don't reset the timer due simply to, say, commands or events that
+            // cause us to exit and re-enter EvaluatingState.
+            if (!mEvaluationTimer.isStarted()) {
+                mEvaluationTimer.start();
+            }
             sendMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
             if (mUidResponsibleForReeval != INVALID_UID) {
                 TrafficStats.setThreadStatsUid(mUidResponsibleForReeval);
@@ -481,22 +497,20 @@
                     // will be unresponsive. isCaptivePortal() could be executed on another Thread
                     // if this is found to cause problems.
                     CaptivePortalProbeResult probeResult = isCaptivePortal();
-                    CaptivePortalCheckResultEvent.logEvent(mNetworkAgentInfo.network.netId,
-                            probeResult.mHttpResponseCode);
+                    CaptivePortalCheckResultEvent.logEvent(mNetId, probeResult.mHttpResponseCode);
                     if (probeResult.mHttpResponseCode == 204) {
                         transitionTo(mValidatedState);
                     } else if (probeResult.mHttpResponseCode >= 200 &&
                             probeResult.mHttpResponseCode <= 399) {
                         mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
-                                NETWORK_TEST_RESULT_INVALID, mNetworkAgentInfo.network.netId,
-                                probeResult.mRedirectUrl));
+                                NETWORK_TEST_RESULT_INVALID, mNetId, probeResult.mRedirectUrl));
                         transitionTo(mCaptivePortalState);
                     } else {
                         final Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
                         sendMessageDelayed(msg, mReevaluateDelayMs);
                         mConnectivityServiceHandler.sendMessage(obtainMessage(
-                                EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID,
-                                mNetworkAgentInfo.network.netId, probeResult.mRedirectUrl));
+                                EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, mNetId,
+                                probeResult.mRedirectUrl));
                         if (mAttempts >= BLAME_FOR_EVALUATION_ATTEMPTS) {
                             // Don't continue to blame UID forever.
                             TrafficStats.clearThreadStatsUid();
@@ -511,7 +525,7 @@
                     // Before IGNORE_REEVALUATE_ATTEMPTS attempts are made,
                     // ignore any re-evaluation requests. After, restart the
                     // evaluation process via EvaluatingState#enter.
-                    return mAttempts < IGNORE_REEVALUATE_ATTEMPTS ? HANDLED : NOT_HANDLED;
+                    return (mAttempts < IGNORE_REEVALUATE_ATTEMPTS) ? HANDLED : NOT_HANDLED;
                 default:
                     return NOT_HANDLED;
             }
@@ -553,6 +567,10 @@
 
         @Override
         public void enter() {
+            if (mEvaluationTimer.isRunning()) {
+                NetworkMonitorEvent.logCaptivePortalFound(mNetId, mEvaluationTimer.stop());
+                mEvaluationTimer.reset();
+            }
             // Don't annoy user with sign-in notifications.
             if (mDontDisplaySigninNotification) return;
             // Create a CustomIntentReceiver that sends us a
@@ -593,7 +611,8 @@
 
         @Override
         public void enter() {
-            final String cmdName = ACTION_LINGER_EXPIRED + "." + mNetworkAgentInfo.network.netId;
+            mEvaluationTimer.reset();
+            final String cmdName = ACTION_LINGER_EXPIRED + "." + mNetId;
             mWakeupMessage = makeWakeupMessage(mContext, getHandler(), cmdName, CMD_LINGER_EXPIRED);
             long wakeupTime = SystemClock.elapsedRealtime() + mLingerDelayMs;
             mWakeupMessage.schedule(wakeupTime);
@@ -663,6 +682,7 @@
         HttpURLConnection urlConnection = null;
         int httpResponseCode = 599;
         String redirectUrl = null;
+        final Stopwatch probeTimer = new Stopwatch().start();
         try {
             URL url = new URL(getCaptivePortalServerUrl(mContext));
             // On networks with a PAC instead of fetching a URL that should result in a 204
@@ -759,6 +779,7 @@
                 urlConnection.disconnect();
             }
         }
+        NetworkMonitorEvent.logPortalProbeEvent(mNetId, probeTimer.stop(), httpResponseCode);
         return new CaptivePortalProbeResult(httpResponseCode, redirectUrl);
     }
 
diff --git a/services/core/java/com/android/server/notification/CalendarTracker.java b/services/core/java/com/android/server/notification/CalendarTracker.java
index 783b16f..5d50f3b 100644
--- a/services/core/java/com/android/server/notification/CalendarTracker.java
+++ b/services/core/java/com/android/server/notification/CalendarTracker.java
@@ -43,14 +43,15 @@
     private static final int EVENT_CHECK_LOOKAHEAD = 24 * 60 * 60 * 1000;
 
     private static final String[] INSTANCE_PROJECTION = {
-        Instances.BEGIN,
-        Instances.END,
-        Instances.TITLE,
-        Instances.VISIBLE,
-        Instances.EVENT_ID,
-        Instances.OWNER_ACCOUNT,
-        Instances.CALENDAR_ID,
-        Instances.AVAILABILITY,
+            Instances.BEGIN,
+            Instances.END,
+            Instances.TITLE,
+            Instances.VISIBLE,
+            Instances.EVENT_ID,
+            Instances.CALENDAR_DISPLAY_NAME,
+            Instances.OWNER_ACCOUNT,
+            Instances.CALENDAR_ID,
+            Instances.AVAILABILITY,
     };
 
     private static final String INSTANCE_ORDER_BY = Instances.BEGIN + " ASC";
@@ -87,49 +88,6 @@
         pw.print(prefix); pw.print("u="); pw.println(mUserContext.getUserId());
     }
 
-    public void dumpContent(Uri uri) {
-        Log.d(TAG, "dumpContent: " + uri);
-        final Cursor cursor = mUserContext.getContentResolver().query(uri, null, null, null, null);
-        try {
-            int r = 0;
-            while (cursor.moveToNext()) {
-                Log.d(TAG, "Row " + (++r) + ": id="
-                        + cursor.getInt(cursor.getColumnIndex(BaseColumns._ID)));
-                for (int i = 0; i < cursor.getColumnCount(); i++) {
-                    final String name = cursor.getColumnName(i);
-                    final int type = cursor.getType(i);
-                    Object o = null;
-                    String typeName = null;
-                    switch (type) {
-                        case Cursor.FIELD_TYPE_INTEGER:
-                            o = cursor.getLong(i);
-                            typeName = "INTEGER";
-                            break;
-                        case Cursor.FIELD_TYPE_STRING:
-                            o = cursor.getString(i);
-                            typeName = "STRING";
-                            break;
-                        case Cursor.FIELD_TYPE_NULL:
-                            o = null;
-                            typeName = "NULL";
-                            break;
-                        default:
-                            throw new UnsupportedOperationException("type: " + type);
-                    }
-                    if (name.equals(BaseColumns._ID)
-                            || name.toLowerCase().contains("sync")
-                            || o == null) {
-                        continue;
-                    }
-                    Log.d(TAG, "  " + name + "(" + typeName + ")=" + o);
-                }
-            }
-            Log.d(TAG, "  " + uri + " " + r + " rows");
-        } finally {
-            cursor.close();
-        }
-    }
-
     private ArraySet<Long> getPrimaryCalendars() {
         final long start = System.currentTimeMillis();
         final ArraySet<Long> rt = new ArraySet<>();
@@ -170,18 +128,21 @@
                 final String title = cursor.getString(2);
                 final boolean calendarVisible = cursor.getInt(3) == 1;
                 final int eventId = cursor.getInt(4);
-                final String owner = cursor.getString(5);
-                final long calendarId = cursor.getLong(6);
-                final int availability = cursor.getInt(7);
+                final String name = cursor.getString(5);
+                final String owner = cursor.getString(6);
+                final long calendarId = cursor.getLong(7);
+                final int availability = cursor.getInt(8);
                 final boolean calendarPrimary = primaryCalendars.contains(calendarId);
-                if (DEBUG) Log.d(TAG, String.format("%s %s-%s v=%s a=%s eid=%s o=%s cid=%s p=%s",
+                if (DEBUG) Log.d(TAG, String.format(
+                        "%s %s-%s v=%s a=%s eid=%s n=%s o=%s cid=%s p=%s",
                         title,
                         new Date(begin), new Date(end), calendarVisible,
-                        availabilityToString(availability), eventId, owner, calendarId,
+                        availabilityToString(availability), eventId, name, owner, calendarId,
                         calendarPrimary));
                 final boolean meetsTime = time >= begin && time < end;
                 final boolean meetsCalendar = calendarVisible && calendarPrimary
-                        && (filter.calendar == null || Objects.equals(filter.calendar, owner));
+                        && (filter.calendar == null || Objects.equals(filter.calendar, owner)
+                        || Objects.equals(filter.calendar, name));
                 final boolean meetsAvailability = availability != Instances.AVAILABILITY_FREE;
                 if (meetsCalendar && meetsAvailability) {
                     if (DEBUG) Log.d(TAG, "  MEETS CALENDAR & AVAILABILITY");
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index 0945065..86ca97d 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -99,9 +99,7 @@
     @Override
     public void onServiceAdded(ComponentName component) {
         if (DEBUG) Log.d(TAG, "onServiceAdded " + component);
-        if (isAutomaticActive(component)) {
-            mHelper.setConfigAsync(mHelper.getConfig(), "zmc.onServiceAdded");
-        }
+        mHelper.setConfigAsync(mHelper.getConfig(), "zmc.onServiceAdded");
     }
 
     @Override
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index eb49e9f..60e00a9 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -643,18 +643,22 @@
                 dispatchOnPolicyChanged();
             }
             mConfig = config;
-            final String val = Integer.toString(config.hashCode());
-            Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
-            if (!evaluateZenMode(reason, setRingerMode)) {
-                applyRestrictions();  // evaluateZenMode will also apply restrictions if changed
-            }
-            mConditions.evaluateConfig(config, true /*processSubscriptions*/);
+            mHandler.postApplyConfig(config, reason, setRingerMode);
             return true;
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
     }
 
+    private void applyConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
+        final String val = Integer.toString(config.hashCode());
+        Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
+        if (!evaluateZenMode(reason, setRingerMode)) {
+            applyRestrictions();  // evaluateZenMode will also apply restrictions if changed
+        }
+        mConditions.evaluateConfig(config, true /*processSubscriptions*/);
+    }
+
     private int getZenModeSetting() {
         return Global.getInt(mContext.getContentResolver(), Global.ZEN_MODE, Global.ZEN_MODE_OFF);
     }
@@ -1071,14 +1075,23 @@
         private static final int MSG_DISPATCH = 1;
         private static final int MSG_METRICS = 2;
         private static final int MSG_SET_CONFIG = 3;
+        private static final int MSG_APPLY_CONFIG = 4;
 
         private final class ConfigMessageData {
             public final ZenModeConfig config;
             public final String reason;
+            public final boolean setRingerMode;
 
             ConfigMessageData(ZenModeConfig config, String reason) {
                 this.config = config;
                 this.reason = reason;
+                this.setRingerMode = false;
+            }
+
+            ConfigMessageData(ZenModeConfig config, String reason, boolean setRingerMode) {
+                this.config = config;
+                this.reason = reason;
+                this.setRingerMode = setRingerMode;
             }
         }
 
@@ -1102,6 +1115,11 @@
             sendMessage(obtainMessage(MSG_SET_CONFIG, new ConfigMessageData(config, reason)));
         }
 
+        private void postApplyConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
+            sendMessage(obtainMessage(MSG_APPLY_CONFIG,
+                    new ConfigMessageData(config, reason, setRingerMode)));
+        }
+
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
@@ -1112,11 +1130,15 @@
                     mMetrics.emit();
                     break;
                 case MSG_SET_CONFIG:
-                    ConfigMessageData configData = (ConfigMessageData)msg.obj;
+                    ConfigMessageData configData = (ConfigMessageData) msg.obj;
                     synchronized (mConfig) {
                         setConfigLocked(configData.config, configData.reason);
                     }
                     break;
+                case MSG_APPLY_CONFIG:
+                    ConfigMessageData applyConfigData = (ConfigMessageData) msg.obj;
+                    applyConfig(applyConfigData.config, applyConfigData.reason,
+                            applyConfigData.setRingerMode);
             }
         }
     }
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 91b6914..d6ace91 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -34,7 +34,6 @@
 import android.app.WallpaperInfo;
 import android.app.WallpaperManager;
 import android.app.admin.DevicePolicyManager;
-import android.app.backup.BackupManager;
 import android.app.backup.WallpaperBackupHelper;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -61,6 +60,7 @@
 import android.os.FileUtils;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
+import android.os.Process;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -205,7 +205,8 @@
             if (path == null) {
                 return;
             }
-            final boolean written = (event == CLOSE_WRITE || event == MOVED_TO);
+            final boolean moved = (event == MOVED_TO);
+            final boolean written = (event == CLOSE_WRITE || moved);
             final File changedFile = new File(mWallpaperDir, path);
 
             // System and system+lock changes happen on the system wallpaper input file;
@@ -224,13 +225,6 @@
                         + " written=" + written);
             }
             synchronized (mLock) {
-                if (sysWallpaperChanged || mWallpaperInfoFile.equals(changedFile)) {
-                    // changing the wallpaper means we'll need to back up the new one
-                    long origId = Binder.clearCallingIdentity();
-                    BackupManager bm = new BackupManager(mContext);
-                    bm.dataChanged();
-                    Binder.restoreCallingIdentity(origId);
-                }
                 if (sysWallpaperChanged || lockWallpaperChanged) {
                     notifyCallbacksLocked(wallpaper);
                     if (wallpaper.wallpaperComponent == null
@@ -244,6 +238,14 @@
                             if (DEBUG) {
                                 Slog.v(TAG, "Wallpaper written; generating crop");
                             }
+                            if (moved) {
+                                // This is a restore, so generate the crop using any just-restored new
+                                // crop guidelines, making sure to preserve our local dimension hints.
+                                if (DEBUG) {
+                                    Slog.v(TAG, "moved-to, therefore restore; reloading metadata");
+                                }
+                                loadSettingsLocked(wallpaper.userId, true);
+                            }
                             generateCrop(wallpaper);
                             if (DEBUG) {
                                 Slog.v(TAG, "Crop done; invoking completion callback");
@@ -491,6 +493,11 @@
         IWallpaperManagerCallback setComplete;
 
         /**
+         * Is the OS allowed to back up this wallpaper imagery?
+         */
+        boolean allowBackup;
+
+        /**
          * Resource name if using a picture from the wallpaper gallery
          */
         String name = "";
@@ -811,7 +818,7 @@
         mMonitor = new MyPackageMonitor();
         mMonitor.register(context, null, UserHandle.ALL, true);
         getWallpaperDir(UserHandle.USER_SYSTEM).mkdirs();
-        loadSettingsLocked(UserHandle.USER_SYSTEM);
+        loadSettingsLocked(UserHandle.USER_SYSTEM, false);
     }
 
     private static File getWallpaperDir(int userId) {
@@ -1024,7 +1031,7 @@
             wallpaper = mWallpaperMap.get(userId);
             if (wallpaper == null) {
                 // Might need to bring it in the first time to establish our rewrite
-                loadSettingsLocked(userId);
+                loadSettingsLocked(userId, false);
                 wallpaper = mWallpaperMap.get(userId);
             }
         }
@@ -1102,7 +1109,7 @@
                 WallpaperData wd = mWallpaperMap.get(user.id);
                 if (wd == null) {
                     // User hasn't started yet, so load her settings to peek at the wallpaper
-                    loadSettingsLocked(user.id);
+                    loadSettingsLocked(user.id, false);
                     wd = mWallpaperMap.get(user.id);
                 }
                 if (wd != null && name.equals(wd.name)) {
@@ -1235,7 +1242,7 @@
             if (wallpaper == null) {
                 // common case, this is the first lookup post-boot of the system or
                 // unified lock, so we bring up the saved state lazily now and recheck.
-                loadSettingsLocked(wallpaperUserId);
+                loadSettingsLocked(wallpaperUserId, false);
                 wallpaper = whichSet.get(wallpaperUserId);
                 if (wallpaper == null) {
                     return null;
@@ -1304,7 +1311,8 @@
 
     @Override
     public ParcelFileDescriptor setWallpaper(String name, String callingPackage,
-            Rect cropHint, Bundle extras, int which, IWallpaperManagerCallback completion) {
+            Rect cropHint, boolean allowBackup, Bundle extras, int which,
+            IWallpaperManagerCallback completion) {
         checkPermission(android.Manifest.permission.SET_WALLPAPER);
 
         if ((which & (FLAG_LOCK|FLAG_SYSTEM)) == 0) {
@@ -1342,6 +1350,9 @@
                     wallpaper.whichPending = which;
                     wallpaper.setComplete = completion;
                     wallpaper.cropHint.set(cropHint);
+                    if ((which & FLAG_SYSTEM) != 0) {
+                        wallpaper.allowBackup = allowBackup;
+                    }
                 }
                 return pfd;
             } finally {
@@ -1651,6 +1662,16 @@
         return !um.hasUserRestriction(UserManager.DISALLOW_SET_WALLPAPER);
     }
 
+    @Override
+    public boolean isWallpaperBackupEligible(int userId) {
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+            throw new SecurityException("Only the system may call isWallpaperBackupEligible");
+        }
+
+        WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
+        return (wallpaper != null) ? wallpaper.allowBackup : false;
+    }
+
     private static JournaledFile makeJournaledFile(int userId) {
         final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath();
         return new JournaledFile(new File(base), new File(base + ".tmp"));
@@ -1721,6 +1742,11 @@
             out.attribute(null, "component",
                     wallpaper.wallpaperComponent.flattenToShortString());
         }
+
+        if (wallpaper.allowBackup) {
+            out.attribute(null, "backup", "true");
+        }
+
         out.endTag(null, tag);
     }
 
@@ -1764,7 +1790,7 @@
         if (wallpaper == null) {
             // common case, this is the first lookup post-boot of the system or
             // unified lock, so we bring up the saved state lazily now and recheck.
-            loadSettingsLocked(userId);
+            loadSettingsLocked(userId, false);
             wallpaper = whichSet.get(userId);
             // if it's still null here, this is a lock-only operation and there is not
             // yet a lock-only wallpaper set for this user, so we need to establish
@@ -1788,7 +1814,7 @@
         return wallpaper;
     }
 
-    private void loadSettingsLocked(int userId) {
+    private void loadSettingsLocked(int userId, boolean keepDimensionHints) {
         if (DEBUG) Slog.v(TAG, "loadSettingsLocked");
 
         JournaledFile journal = makeJournaledFile(userId);
@@ -1801,6 +1827,7 @@
         WallpaperData wallpaper = mWallpaperMap.get(userId);
         if (wallpaper == null) {
             wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP);
+            wallpaper.allowBackup = true;
             mWallpaperMap.put(userId, wallpaper);
             if (!wallpaper.cropExists()) {
                 generateCrop(wallpaper);
@@ -1819,7 +1846,7 @@
                     String tag = parser.getName();
                     if ("wp".equals(tag)) {
                         // Common to system + lock wallpapers
-                        parseWallpaperAttributes(parser, wallpaper);
+                        parseWallpaperAttributes(parser, wallpaper, keepDimensionHints);
 
                         // A system wallpaper might also be a live wallpaper
                         String comp = parser.getAttributeValue(null, "component");
@@ -1848,7 +1875,7 @@
                                     WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
                             mLockWallpaperMap.put(userId, lockWallpaper);
                         }
-                        parseWallpaperAttributes(parser, lockWallpaper);
+                        parseWallpaperAttributes(parser, lockWallpaper, false);
                     }
                 }
             } while (type != XmlPullParser.END_DOCUMENT);
@@ -1909,7 +1936,8 @@
         }
     }
 
-    private void parseWallpaperAttributes(XmlPullParser parser, WallpaperData wallpaper) {
+    private void parseWallpaperAttributes(XmlPullParser parser, WallpaperData wallpaper,
+            boolean keepDimensionHints) {
         final String idString = parser.getAttributeValue(null, "id");
         if (idString != null) {
             final int id = wallpaper.wallpaperId = Integer.parseInt(idString);
@@ -1920,9 +1948,11 @@
             wallpaper.wallpaperId = makeWallpaperIdLocked();
         }
 
-        wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
-        wallpaper.height = Integer.parseInt(parser
-                .getAttributeValue(null, "height"));
+        if (!keepDimensionHints) {
+            wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
+            wallpaper.height = Integer.parseInt(parser
+                    .getAttributeValue(null, "height"));
+        }
         wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0);
         wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0);
         wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0);
@@ -1932,6 +1962,7 @@
         wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0);
         wallpaper.padding.bottom = getAttributeInt(parser, "paddingBottom", 0);
         wallpaper.name = parser.getAttributeValue(null, "name");
+        wallpaper.allowBackup = "true".equals(parser.getAttributeValue(null, "backup"));
     }
 
     private int getMaximumSizeDimension() {
@@ -1952,9 +1983,10 @@
         WallpaperData wallpaper = null;
         boolean success = false;
         synchronized (mLock) {
-            loadSettingsLocked(UserHandle.USER_SYSTEM);
+            loadSettingsLocked(UserHandle.USER_SYSTEM, false);
             wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
             wallpaper.wallpaperId = makeWallpaperIdLocked();    // always bump id at restore
+            wallpaper.allowBackup = true;   // by definition if it was restored
             if (wallpaper.nextWallpaperComponent != null
                     && !wallpaper.nextWallpaperComponent.equals(mImageWallpaper)) {
                 if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index eacdd81..1f44b29 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -129,15 +129,19 @@
         public void onAnimationStart(Animator animation) {
             if (DEBUG) Slog.d(TAG, "onAnimationStart: mTarget=" + mTarget
                     + " mReplacement=" + mReplacement);
+            // Ensure that we have prepared the target for animation before
+            // we trigger any size changes, so it can swap surfaces
+            // in to appropriate modes, or do as it wishes otherwise.
             if (!mReplacement) {
                 mTarget.onAnimationStart();
             }
 
-            // Ensure that we have prepared the target for animation before
-            // we trigger any size changes, so it can swap surfaces
-            // in to appropriate modes, or do as it wishes otherwise.
+            // Immediately update the task bounds if they have to become larger, but preserve
+            // the starting position so we don't jump at the beginning of the animation.
             if (animatingToLargerSize()) {
-                mTarget.setPinnedStackSize(mFrom, mTo);
+                mTmpRect.set(mFrom.left, mFrom.top,
+                        mFrom.left + mFrozenTaskWidth, mFrom.top + mFrozenTaskHeight);
+                mTarget.setPinnedStackSize(mFrom, mTmpRect);
             }
         }
 
@@ -145,11 +149,15 @@
         public void onAnimationEnd(Animator animation) {
             if (DEBUG) Slog.d(TAG, "onAnimationEnd: mTarget=" + mTarget
                     + " mMoveToFullScreen=" + mMoveToFullScreen + " mWillReplace=" + mWillReplace);
-
-            finishAnimation();
             if (mMoveToFullScreen && !mWillReplace) {
                 mTarget.moveToFullscreen();
             }
+
+            // If we finish the animation before we move the target to fullscreen,
+            // recents may close itself and we may try and resume the previous
+            // fullscreen app leading to churn and flicker after we then move
+            // our target to fullscreen.
+            finishAnimation();
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9994af3..6ff09b1 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1805,6 +1805,16 @@
         return true;
     }
 
+    private static boolean excludeWindowTypeFromTapOutTask(int windowType) {
+        switch (windowType) {
+            case TYPE_STATUS_BAR:
+            case TYPE_NAVIGATION_BAR:
+            case TYPE_INPUT_METHOD_DIALOG:
+                return true;
+        }
+        return false;
+    }
+
     public int addWindow(Session session, IWindow client, int seq,
             WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
             Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
@@ -2003,7 +2013,7 @@
 
             res = WindowManagerGlobal.ADD_OKAY;
 
-            if (type == TYPE_STATUS_BAR || type == TYPE_NAVIGATION_BAR) {
+            if (excludeWindowTypeFromTapOutTask(type)) {
                 displayContent.mTapExcludedWindows.add(win);
             }
 
@@ -2395,7 +2405,7 @@
         }
 
         final int type = win.mAttrs.type;
-        if (type == TYPE_STATUS_BAR || type == TYPE_NAVIGATION_BAR) {
+        if (excludeWindowTypeFromTapOutTask(type)) {
             final DisplayContent displaycontent = win.getDisplayContent();
             displaycontent.mTapExcludedWindows.remove(win);
         }
diff --git a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
index 774577d..8ea9bfc 100644
--- a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
+++ b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
@@ -661,6 +661,16 @@
     TranslateToObject(lastLocation, locationObject);
   }
 
+  // sCallbacksObject is created when FlpHardwareProvider on Java side is
+  // initialized. Sometimes the hardware may call this function before the Java
+  // side is ready. In order to prevent the system crash, check whether
+  // sCallbacksObj has been created. If not, simply ignore this event from
+  // hardware.
+  if (sCallbacksObj == NULL) {
+    ALOGE("FlpHardwareProvider hasn't been initialized.");
+    return;
+  }
+
   sCallbackEnv->CallVoidMethod(
       sCallbacksObj,
       sOnGeofenceMonitorStatus,
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 058b631..c5c90e0 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1194,7 +1194,7 @@
     JavaObject object(env, "android/location/GnssMeasurement");
     GpsMeasurementFlags flags = measurement->flags;
     SET(Svid, static_cast<int32_t>(measurement->prn));
-    if (measurement->prn >= 1 || measurement->prn <= 32) {
+    if (measurement->prn >= 1 && measurement->prn <= 32) {
         SET(ConstellationType, static_cast<int32_t>(GNSS_CONSTELLATION_GPS));
     } else {
         ALOGD("Unknown constellation type with Svid = %d.", measurement->prn);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 8c2f559..9f2ca59 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -165,6 +165,10 @@
     private static final String UNCRYPT_PACKAGE_FILE = "/cache/recovery/uncrypt_file";
     private static final String BLOCK_MAP_FILE = "/cache/recovery/block.map";
 
+    // maximum number of binder threads used for system_server
+    // will be higher than the system default
+    private static final int sMaxBinderThreads = 31;
+
     /**
      * Default theme used by the system context. This is used to style
      * system-provided dialogs, such as the Power Off dialog, and other
@@ -285,6 +289,9 @@
             // Ensure binder calls into the system always run at foreground priority.
             BinderInternal.disableBackgroundScheduling(true);
 
+            // Increase the number of binder threads in system_server
+            BinderInternal.setMaxThreads(sMaxBinderThreads);
+
             // Prepare the main looper thread (this thread).
             android.os.Process.setThreadPriority(
                 android.os.Process.THREAD_PRIORITY_FOREGROUND);
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index c8dbe02..27600a7 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -24,9 +24,7 @@
 import android.net.LinkProperties.ProvisioningChange;
 import android.net.ProxyInfo;
 import android.net.RouteInfo;
-import android.net.metrics.IpReachabilityMonitorMessageEvent;
-import android.net.metrics.IpReachabilityMonitorProbeEvent;
-import android.net.metrics.IpReachabilityMonitorLostEvent;
+import android.net.metrics.IpReachabilityEvent;
 import android.net.netlink.NetlinkConstants;
 import android.net.netlink.NetlinkErrorMessage;
 import android.net.netlink.NetlinkMessage;
@@ -168,47 +166,54 @@
      * Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND)
      * for the given IP address on the specified interface index.
      *
-     * @return true, if the request was successfully passed to the kernel; false otherwise.
+     * @return 0 if the request was successfully passed to the kernel; otherwise return
+     *         a non-zero error code.
      */
-    public static boolean probeNeighbor(int ifIndex, InetAddress ip) {
-        final long IO_TIMEOUT = 300L;
+    private static int probeNeighbor(int ifIndex, InetAddress ip) {
         final String msgSnippet = "probing ip=" + ip.getHostAddress() + "%" + ifIndex;
         if (DBG) { Log.d(TAG, msgSnippet); }
 
         final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage(
                 1, ip, StructNdMsg.NUD_PROBE, ifIndex, null);
-        boolean returnValue = false;
 
+        int errno = -OsConstants.EPROTO;
         try (NetlinkSocket nlSocket = new NetlinkSocket(OsConstants.NETLINK_ROUTE)) {
+            final long IO_TIMEOUT = 300L;
             nlSocket.connectToKernel();
             nlSocket.sendMessage(msg, 0, msg.length, IO_TIMEOUT);
             final ByteBuffer bytes = nlSocket.recvMessage(IO_TIMEOUT);
+            // recvMessage() guaranteed to not return null if it did not throw.
             final NetlinkMessage response = NetlinkMessage.parse(bytes);
             if (response != null && response instanceof NetlinkErrorMessage &&
-                    (((NetlinkErrorMessage) response).getNlMsgError() != null) &&
-                    (((NetlinkErrorMessage) response).getNlMsgError().error == 0)) {
-                returnValue = true;
-            } else {
-                String errmsg;
-                if (bytes == null) {
-                    errmsg = "null recvMessage";
-                } else if (response == null) {
-                    bytes.position(0);
-                    errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes);
-                } else {
+                    (((NetlinkErrorMessage) response).getNlMsgError() != null)) {
+                errno = ((NetlinkErrorMessage) response).getNlMsgError().error;
+                if (errno != 0) {
                     // TODO: consider ignoring EINVAL (-22), which appears to be
                     // normal when probing a neighbor for which the kernel does
                     // not already have / no longer has a link layer address.
+                    Log.e(TAG, "Error " + msgSnippet + ", errmsg=" + response.toString());
+                }
+            } else {
+                String errmsg;
+                if (response == null) {
+                    bytes.position(0);
+                    errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes);
+                } else {
                     errmsg = response.toString();
                 }
                 Log.e(TAG, "Error " + msgSnippet + ", errmsg=" + errmsg);
             }
-        } catch (ErrnoException | InterruptedIOException | SocketException e) {
-            Log.d(TAG, "Error " + msgSnippet, e);
+        } catch (ErrnoException e) {
+            Log.e(TAG, "Error " + msgSnippet, e);
+            errno = -e.errno;
+        } catch (InterruptedIOException e) {
+            Log.e(TAG, "Error " + msgSnippet, e);
+            errno = -OsConstants.ETIMEDOUT;
+        } catch (SocketException e) {
+            Log.e(TAG, "Error " + msgSnippet, e);
+            errno = -OsConstants.EIO;
         }
-        IpReachabilityMonitorProbeEvent.logEvent("ifindex-" + ifIndex, ip.getHostAddress(),
-                returnValue);
-        return returnValue;
+        return errno;
     }
 
     public IpReachabilityMonitor(Context context, String ifName, Callback callback)
@@ -354,7 +359,7 @@
         }
 
         if (delta == ProvisioningChange.LOST_PROVISIONING) {
-            IpReachabilityMonitorLostEvent.logEvent(mInterfaceName);
+            IpReachabilityEvent.logProvisioningLost(mInterfaceName);
             final String logMsg = "FAILURE: LOST_PROVISIONING, " + msg;
             Log.w(TAG, logMsg);
             if (mCallback != null) {
@@ -362,6 +367,8 @@
                 // an InetAddress argument.
                 mCallback.notifyLost(ip, logMsg);
             }
+        } else {
+            IpReachabilityEvent.logNudFailed(mInterfaceName);
         }
     }
 
@@ -385,7 +392,8 @@
             if (!stillRunning()) {
                 break;
             }
-            probeNeighbor(mInterfaceIndex, target);
+            final int returnValue = probeNeighbor(mInterfaceIndex, target);
+            IpReachabilityEvent.logProbeEvent(mInterfaceName, returnValue);
         }
     }
 
@@ -523,8 +531,6 @@
 
             final short msgType = neighMsg.getHeader().nlmsg_type;
             final short nudState = ndMsg.ndm_state;
-            IpReachabilityMonitorMessageEvent.logEvent(mInterfaceName,
-                    destination.getHostAddress(), msgType, nudState);
             final String eventMsg = "NeighborEvent{"
                     + "elapsedMs=" + whenMs + ", "
                     + destination.getHostAddress() + ", "
diff --git a/services/net/java/android/net/util/Stopwatch.java b/services/net/java/android/net/util/Stopwatch.java
new file mode 100644
index 0000000..cb15ee5
--- /dev/null
+++ b/services/net/java/android/net/util/Stopwatch.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.util;
+
+import android.os.SystemClock;
+
+
+/**
+ * @hide
+ */
+public class Stopwatch {
+    private long mStartTimeMs;
+    private long mStopTimeMs;
+
+    public boolean isStarted() {
+        return (mStartTimeMs > 0);
+    }
+
+    public boolean isStopped() {
+        return (mStopTimeMs > 0);
+    }
+
+    public boolean isRunning() {
+        return (isStarted() && !isStopped());
+    }
+
+    // Returning |this| makes possible the following usage pattern:
+    //
+    //     Stopwatch s = new Stopwatch().start();
+    public Stopwatch start() {
+        if (!isStarted()) {
+            mStartTimeMs = SystemClock.elapsedRealtime();
+        }
+        return this;
+    }
+
+    // Returns the total time recorded, in milliseconds, or 0 if not started.
+    public long stop() {
+        if (isRunning()) {
+            mStopTimeMs = SystemClock.elapsedRealtime();
+        }
+        // Return either the delta after having stopped, or 0.
+        return (mStopTimeMs - mStartTimeMs);
+    }
+
+    // Returns the total time recorded to date, in milliseconds.
+    // If the Stopwatch is not running, returns the same value as stop(),
+    // i.e. either the total time recorded before stopping or 0.
+    public long lap() {
+        if (isRunning()) {
+            return (SystemClock.elapsedRealtime() - mStartTimeMs);
+        } else {
+            return stop();
+        }
+    }
+
+    public void reset() {
+        mStartTimeMs = 0;
+        mStopTimeMs = 0;
+    }
+}
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 23f186c..7017d81 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -42,6 +42,7 @@
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
     <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
+    <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 26eed24..4fae4a7 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -74,6 +74,7 @@
 import com.android.server.net.NetworkPinner;
 
 import java.net.InetAddress;
+import java.util.ArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
@@ -1788,4 +1789,96 @@
         waitFor(cv);
         assertPinnedToWifiWithCellDefault();
     }
+
+    @SmallTest
+    public void testNetworkRequestMaximum() {
+        final int MAX_REQUESTS = 100;
+        // Test that the limit is enforced when MAX_REQUESTS simultaneous requests are added.
+        NetworkRequest networkRequest = new NetworkRequest.Builder().build();
+        ArrayList<NetworkCallback> networkCallbacks = new ArrayList<NetworkCallback>();
+        try {
+            for (int i = 0; i < MAX_REQUESTS; i++) {
+                NetworkCallback networkCallback = new NetworkCallback();
+                mCm.requestNetwork(networkRequest, networkCallback);
+                networkCallbacks.add(networkCallback);
+            }
+            fail("Registering " + MAX_REQUESTS + " NetworkRequests did not throw exception");
+        } catch (IllegalArgumentException expected) {}
+        for (NetworkCallback networkCallback : networkCallbacks) {
+            mCm.unregisterNetworkCallback(networkCallback);
+        }
+        networkCallbacks.clear();
+
+        try {
+            for (int i = 0; i < MAX_REQUESTS; i++) {
+                NetworkCallback networkCallback = new NetworkCallback();
+                mCm.registerNetworkCallback(networkRequest, networkCallback);
+                networkCallbacks.add(networkCallback);
+            }
+            fail("Registering " + MAX_REQUESTS + " NetworkCallbacks did not throw exception");
+        } catch (IllegalArgumentException expected) {}
+        for (NetworkCallback networkCallback : networkCallbacks) {
+            mCm.unregisterNetworkCallback(networkCallback);
+        }
+        networkCallbacks.clear();
+
+        ArrayList<PendingIntent> pendingIntents = new ArrayList<PendingIntent>();
+        try {
+            for (int i = 0; i < MAX_REQUESTS + 1; i++) {
+                PendingIntent pendingIntent =
+                        PendingIntent.getBroadcast(mContext, 0, new Intent("a" + i), 0);
+                mCm.requestNetwork(networkRequest, pendingIntent);
+                pendingIntents.add(pendingIntent);
+            }
+            fail("Registering " + MAX_REQUESTS +
+                    " PendingIntent NetworkRequests did not throw exception");
+        } catch (IllegalArgumentException expected) {}
+        for (PendingIntent pendingIntent : pendingIntents) {
+            mCm.unregisterNetworkCallback(pendingIntent);
+        }
+        pendingIntents.clear();
+
+        try {
+            for (int i = 0; i < MAX_REQUESTS + 1; i++) {
+                PendingIntent pendingIntent =
+                        PendingIntent.getBroadcast(mContext, 0, new Intent("a" + i), 0);
+                mCm.registerNetworkCallback(networkRequest, pendingIntent);
+                pendingIntents.add(pendingIntent);
+            }
+            fail("Registering " + MAX_REQUESTS +
+                    " PendingIntent NetworkCallbacks did not throw exception");
+        } catch (IllegalArgumentException expected) {}
+        for (PendingIntent pendingIntent : pendingIntents) {
+            mCm.unregisterNetworkCallback(pendingIntent);
+        }
+        pendingIntents.clear();
+        mService.waitForIdle(5000);
+
+        // Test that the limit is not hit when MAX_REQUESTS requests are added and removed.
+        for (int i = 0; i < MAX_REQUESTS; i++) {
+            NetworkCallback networkCallback = new NetworkCallback();
+            mCm.requestNetwork(networkRequest, networkCallback);
+            mCm.unregisterNetworkCallback(networkCallback);
+        }
+        mService.waitForIdle();
+        for (int i = 0; i < MAX_REQUESTS; i++) {
+            NetworkCallback networkCallback = new NetworkCallback();
+            mCm.registerNetworkCallback(networkRequest, networkCallback);
+            mCm.unregisterNetworkCallback(networkCallback);
+        }
+        mService.waitForIdle();
+        for (int i = 0; i < MAX_REQUESTS; i++) {
+            PendingIntent pendingIntent =
+                    PendingIntent.getBroadcast(mContext, 0, new Intent("b" + i), 0);
+            mCm.requestNetwork(networkRequest, pendingIntent);
+            mCm.unregisterNetworkCallback(pendingIntent);
+        }
+        mService.waitForIdle();
+        for (int i = 0; i < MAX_REQUESTS; i++) {
+            PendingIntent pendingIntent =
+                    PendingIntent.getBroadcast(mContext, 0, new Intent("c" + i), 0);
+            mCm.registerNetworkCallback(networkRequest, pendingIntent);
+            mCm.unregisterNetworkCallback(pendingIntent);
+        }
+    }
 }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 1e9db18..3f9da4c 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -183,11 +183,11 @@
         try {
             if (mActiveSession == null || token != mActiveSession.mToken) {
                 Slog.w(TAG, "startVoiceActivity does not match active session");
-                return ActivityManager.START_CANCELED;
+                return ActivityManager.START_VOICE_NOT_ACTIVE_SESSION;
             }
             if (!mActiveSession.mShown) {
                 Slog.w(TAG, "startVoiceActivity not allowed on hidden session");
-                return ActivityManager.START_CANCELED;
+                return ActivityManager.START_VOICE_HIDDEN_SESSION;
             }
             intent = new Intent(intent);
             intent.addCategory(Intent.CATEGORY_VOICE);
diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java
index 84883d8..03ce2d8 100644
--- a/telephony/java/android/telephony/ModemActivityInfo.java
+++ b/telephony/java/android/telephony/ModemActivityInfo.java
@@ -151,12 +151,24 @@
      * @return if the record is valid
      */
     public boolean isValid() {
-        int totalTxTimeMs = 0;
-        int txTime [] = getTxTimeMillis();
-        for (int i = 0; i < TX_POWER_LEVELS; i++) {
-            totalTxTimeMs += txTime[i];
+        for (int txVal : getTxTimeMillis()) {
+            if(txVal < 0) {
+                return false;
+            }
         }
-        return ((getIdleTimeMillis() >= 0) && (totalTxTimeMs >= 0)
-                && (getSleepTimeMillis() >= 0) && (getIdleTimeMillis() >= 0));
+
+        return ((getIdleTimeMillis() >= 0) && (getSleepTimeMillis() >= 0)
+                && (getRxTimeMillis() >= 0) && (getEnergyUsed() >= 0) && !isEmpty());
+    }
+
+    private boolean isEmpty() {
+        for (int txVal : getTxTimeMillis()) {
+            if(txVal != 0) {
+                return false;
+            }
+        }
+
+        return ((getIdleTimeMillis() == 0) && (getSleepTimeMillis() == 0)
+                && (getRxTimeMillis() == 0) && (getEnergyUsed() == 0));
     }
 }