Merge "Wi-Fi, now corporeal!" into pi-dev
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index f3091b1..4ae888e 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -879,6 +879,7 @@
 Landroid/app/ProgressDialog;->mProgress:Landroid/widget/ProgressBar;
 Landroid/app/ProgressDialog;->mProgressNumber:Landroid/widget/TextView;
 Landroid/app/QueuedWork;->addFinisher(Ljava/lang/Runnable;)V
+Landroid/app/QueuedWork;->getHandler()Landroid/os/Handler;
 Landroid/app/QueuedWork;->removeFinisher(Ljava/lang/Runnable;)V
 Landroid/app/QueuedWork;->sFinishers:Ljava/util/LinkedList;
 Landroid/app/ResourcesManager;-><init>()V
@@ -1865,6 +1866,7 @@
 Landroid/content/res/ObbInfo;->salt:[B
 Landroid/content/res/Resources$Theme;->mThemeImpl:Landroid/content/res/ResourcesImpl$ThemeImpl;
 Landroid/content/res/Resources$Theme;->resolveAttributes([I[I)Landroid/content/res/TypedArray;
+Landroid/content/res/Resources;-><init>()V
 Landroid/content/res/Resources;-><init>(Ljava/lang/ClassLoader;)V
 Landroid/content/res/Resources;->getCompatibilityInfo()Landroid/content/res/CompatibilityInfo;
 Landroid/content/res/Resources;->getDisplayAdjustments()Landroid/view/DisplayAdjustments;
@@ -1906,6 +1908,7 @@
 Landroid/content/res/ResourcesKey;->mSplitResDirs:[Ljava/lang/String;
 Landroid/content/res/StringBlock;-><init>(JZ)V
 Landroid/content/res/StringBlock;->get(I)Ljava/lang/CharSequence;
+Landroid/content/res/ThemedResourceCache;->mThemedEntries:Landroid/util/ArrayMap;
 Landroid/content/res/ThemedResourceCache;->onConfigurationChange(I)V
 Landroid/content/res/TypedArray;->extractThemeAttrs()[I
 Landroid/content/res/TypedArray;->extractThemeAttrs([I)[I
@@ -2431,6 +2434,7 @@
 Landroid/hardware/camera2/CaptureRequest;->JPEG_GPS_PROCESSING_METHOD:Landroid/hardware/camera2/CaptureRequest$Key;
 Landroid/hardware/camera2/CaptureRequest;->JPEG_GPS_TIMESTAMP:Landroid/hardware/camera2/CaptureRequest$Key;
 Landroid/hardware/camera2/CaptureRequest;->LED_TRANSMIT:Landroid/hardware/camera2/CaptureRequest$Key;
+Landroid/hardware/camera2/CaptureRequest;->mLogicalCameraSettings:Landroid/hardware/camera2/impl/CameraMetadataNative;
 Landroid/hardware/camera2/CaptureRequest;->REQUEST_ID:Landroid/hardware/camera2/CaptureRequest$Key;
 Landroid/hardware/camera2/CaptureRequest;->TONEMAP_CURVE_BLUE:Landroid/hardware/camera2/CaptureRequest$Key;
 Landroid/hardware/camera2/CaptureRequest;->TONEMAP_CURVE_GREEN:Landroid/hardware/camera2/CaptureRequest$Key;
@@ -2443,6 +2447,7 @@
 Landroid/hardware/camera2/CaptureResult;->JPEG_GPS_PROCESSING_METHOD:Landroid/hardware/camera2/CaptureResult$Key;
 Landroid/hardware/camera2/CaptureResult;->JPEG_GPS_TIMESTAMP:Landroid/hardware/camera2/CaptureResult$Key;
 Landroid/hardware/camera2/CaptureResult;->LED_TRANSMIT:Landroid/hardware/camera2/CaptureResult$Key;
+Landroid/hardware/camera2/CaptureResult;->mResults:Landroid/hardware/camera2/impl/CameraMetadataNative;
 Landroid/hardware/camera2/CaptureResult;->QUIRKS_PARTIAL_RESULT:Landroid/hardware/camera2/CaptureResult$Key;
 Landroid/hardware/camera2/CaptureResult;->REQUEST_FRAME_COUNT:Landroid/hardware/camera2/CaptureResult$Key;
 Landroid/hardware/camera2/CaptureResult;->REQUEST_ID:Landroid/hardware/camera2/CaptureResult$Key;
@@ -5499,6 +5504,7 @@
 Landroid/telephony/TelephonyManager$MultiSimVariants;->values()[Landroid/telephony/TelephonyManager$MultiSimVariants;
 Landroid/telephony/TelephonyManager;-><init>()V
 Landroid/telephony/TelephonyManager;-><init>(Landroid/content/Context;)V
+Landroid/telephony/TelephonyManager;-><init>(Landroid/content/Context;I)V
 Landroid/telephony/TelephonyManager;->ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED:Ljava/lang/String;
 Landroid/telephony/TelephonyManager;->from(Landroid/content/Context;)Landroid/telephony/TelephonyManager;
 Landroid/telephony/TelephonyManager;->getCallState(I)I
@@ -5802,6 +5808,7 @@
 Landroid/util/MathUtils;->constrain(III)I
 Landroid/util/MathUtils;->lerp(FFF)F
 Landroid/util/MathUtils;->max(II)F
+Landroid/util/NtpTrustedTime;->currentTimeMillis()J
 Landroid/util/NtpTrustedTime;->forceRefresh()Z
 Landroid/util/NtpTrustedTime;->getCachedNtpTime()J
 Landroid/util/NtpTrustedTime;->getCachedNtpTimeReference()J
@@ -6474,6 +6481,7 @@
 Landroid/view/ViewGroup$MarginLayoutParams;->endMargin:I
 Landroid/view/ViewGroup$MarginLayoutParams;->setMarginsRelative(IIII)V
 Landroid/view/ViewGroup$MarginLayoutParams;->startMargin:I
+Landroid/view/ViewGroup$TouchTarget;-><init>()V
 Landroid/view/ViewGroup$TouchTarget;->child:Landroid/view/View;
 Landroid/view/ViewGroup;->addTransientView(Landroid/view/View;I)V
 Landroid/view/ViewGroup;->cancelTouchTarget(Landroid/view/View;)V
@@ -6783,6 +6791,7 @@
 Landroid/widget/AbsListView;->smoothScrollBy(IIZZ)V
 Landroid/widget/AbsListView;->trackMotionScroll(II)Z
 Landroid/widget/AbsListView;->updateSelectorState()V
+Landroid/widget/AbsSeekBar;->drawThumb(Landroid/graphics/Canvas;)V
 Landroid/widget/AbsSeekBar;->mDisabledAlpha:F
 Landroid/widget/AbsSeekBar;->mIsDragging:Z
 Landroid/widget/AbsSeekBar;->mIsUserSeekable:Z
@@ -7133,6 +7142,7 @@
 Landroid/widget/RemoteViewsAdapter;->saveRemoteViewsCache()V
 Landroid/widget/RemoteViewsAdapter;->setRemoteViewsOnClickHandler(Landroid/widget/RemoteViews$OnClickHandler;)V
 Landroid/widget/RemoteViewsAdapter;->setVisibleRangeHint(II)V
+Landroid/widget/ScrollBarDrawable;-><init>()V
 Landroid/widget/ScrollBarDrawable;->mVerticalThumb:Landroid/graphics/drawable/Drawable;
 Landroid/widget/ScrollBarDrawable;->setHorizontalThumbDrawable(Landroid/graphics/drawable/Drawable;)V
 Landroid/widget/ScrollBarDrawable;->setVerticalThumbDrawable(Landroid/graphics/drawable/Drawable;)V
@@ -7302,6 +7312,7 @@
 Landroid/widget/TextView;->startMarquee()V
 Landroid/widget/TextView;->startStopMarquee(Z)V
 Landroid/widget/TextView;->stopTextActionMode()V
+Landroid/widget/TextView;->updateTextServicesLocaleLocked()V
 Landroid/widget/TextView;->viewportToContentVerticalOffset()I
 Landroid/widget/TimePicker;->mDelegate:Landroid/widget/TimePicker$TimePickerDelegate;
 Landroid/widget/Toast$TN;->handleHide()V
@@ -8260,6 +8271,7 @@
 Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->endCall()Z
 Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->endCallForSubscriber(I)Z
 Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->getDeviceId(Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->isRadioOn(Ljava/lang/String;)Z
 Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->mRemote:Landroid/os/IBinder;
 Lcom/android/internal/telephony/ITelephony$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ITelephony;
 Lcom/android/internal/telephony/ITelephony$Stub;->DESCRIPTOR:Ljava/lang/String;
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 7338bfe..1d5f49a 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -207,7 +207,7 @@
     /**
      * Allow DeviceIdleController to tell us about what apps are whitelisted.
      */
-    public abstract void setDeviceIdleWhitelist(int[] appids);
+    public abstract void setDeviceIdleWhitelist(int[] allAppids, int[] exceptIdleAppids);
 
     /**
      * Update information about which app IDs are on the temp whitelist.
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 9db642b..494b547 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -745,6 +745,44 @@
             }
         }
 
+        // /vendor/lib, /odm/lib and /product/lib are added to the native lib search
+        // paths of the classloader. Note that this is done AFTER the classloader is
+        // created by ApplicationLoaders.getDefault().getClassLoader(...). The
+        // reason is because if we have added the paths when creating the classloader
+        // above, the paths are also added to the search path of the linker namespace
+        // 'classloader-namespace', which will allow ALL libs in the paths to apps.
+        // Since only the libs listed in <partition>/etc/public.libraries.txt can be
+        // available to apps, we shouldn't add the paths then.
+        //
+        // However, we need to add the paths to the classloader (Java) though. This
+        // is because when a native lib is requested via System.loadLibrary(), the
+        // classloader first tries to find the requested lib in its own native libs
+        // search paths. If a lib is not found in one of the paths, dlopen() is not
+        // called at all. This can cause a problem that a vendor public native lib
+        // is accessible when directly opened via dlopen(), but inaccesible via
+        // System.loadLibrary(). In order to prevent the problem, we explicitly
+        // add the paths only to the classloader, and not to the native loader
+        // (linker namespace).
+        List<String> extraLibPaths = new ArrayList<>(3);
+        String abiSuffix = VMRuntime.getRuntime().is64Bit() ? "64" : "";
+        if (!defaultSearchPaths.contains("/vendor/lib")) {
+            extraLibPaths.add("/vendor/lib" + abiSuffix);
+        }
+        if (!defaultSearchPaths.contains("/odm/lib")) {
+            extraLibPaths.add("/odm/lib" + abiSuffix);
+        }
+        if (!defaultSearchPaths.contains("/product/lib")) {
+            extraLibPaths.add("/product/lib" + abiSuffix);
+        }
+        if (!extraLibPaths.isEmpty()) {
+            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+            try {
+                ApplicationLoaders.getDefault().addNative(mClassLoader, extraLibPaths);
+            } finally {
+                StrictMode.setThreadPolicy(oldPolicy);
+            }
+        }
+
         if (addedPaths != null && addedPaths.size() > 0) {
             final String add = TextUtils.join(File.pathSeparator, addedPaths);
             ApplicationLoaders.getDefault().addPath(mClassLoader, add);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 8d56c3e..1ea93a4 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2676,7 +2676,8 @@
                 return true;
             }
             for (int i = 0; i < firstAs.length; i++) {
-                if (!Objects.equals(firstAs[i].title, secondAs[i].title)) {
+                if (!Objects.equals(String.valueOf(firstAs[i].title),
+                        String.valueOf(secondAs[i].title))) {
                     return true;
                 }
                 RemoteInput[] firstRs = firstAs[i].getRemoteInputs();
@@ -2691,25 +2692,10 @@
                     return true;
                 }
                 for (int j = 0; j < firstRs.length; j++) {
-                    if (!Objects.equals(firstRs[j].getLabel(), secondRs[j].getLabel())) {
+                    if (!Objects.equals(String.valueOf(firstRs[j].getLabel()),
+                            String.valueOf(secondRs[j].getLabel()))) {
                         return true;
                     }
-                    CharSequence[] firstCs = firstRs[j].getChoices();
-                    CharSequence[] secondCs = secondRs[j].getChoices();
-                    if (firstCs == null) {
-                        firstCs = new CharSequence[0];
-                    }
-                    if (secondCs == null) {
-                        secondCs = new CharSequence[0];
-                    }
-                    if (firstCs.length != secondCs.length) {
-                        return true;
-                    }
-                    for (int k = 0; k < firstCs.length; k++) {
-                        if (!Objects.equals(firstCs[k], secondCs[k])) {
-                            return true;
-                        }
-                    }
                 }
             }
         }
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 56d61ef..020e8c2 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import android.Manifest;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -40,9 +41,12 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
+
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 
+import libcore.io.IoUtils;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -61,8 +65,6 @@
 import java.util.List;
 import java.util.Map;
 
-import libcore.io.IoUtils;
-
 /**
  * Cache of registered services. This cache is lazily built by interrogating
  * {@link PackageManager} on a per-user basis. It's updated as packages are
@@ -72,7 +74,7 @@
  * <p>
  * The services are referred to by type V and are made available via the
  * {@link #getServiceInfo} method.
- * 
+ *
  * @hide
  */
 public abstract class RegisteredServicesCache<V> {
@@ -98,6 +100,8 @@
         Map<V, ServiceInfo<V>> services = null;
         @GuardedBy("mServicesLock")
         boolean mPersistentServicesFileDidNotExist = true;
+        @GuardedBy("mServicesLock")
+        boolean mBindInstantServiceAllowed = false;
     }
 
     @GuardedBy("mServicesLock")
@@ -273,7 +277,7 @@
             Log.d(TAG, "notifyListener: " + type + " is " + (removed ? "removed" : "added"));
         }
         RegisteredServicesCacheListener<V> listener;
-        Handler handler; 
+        Handler handler;
         synchronized (this) {
             listener = mListener;
             handler = mHandler;
@@ -281,7 +285,7 @@
         if (listener == null) {
             return;
         }
-        
+
         final RegisteredServicesCacheListener<V> listener2 = listener;
         handler.post(new Runnable() {
             public void run() {
@@ -387,6 +391,34 @@
         }
     }
 
+    /**
+     * @return whether the binding to service is allowed for instant apps.
+     */
+    public boolean getBindInstantServiceAllowed(int userId) {
+        mContext.enforceCallingOrSelfPermission(
+                Manifest.permission.MANAGE_BIND_INSTANT_SERVICE,
+                "getBindInstantServiceAllowed");
+
+        synchronized (mServicesLock) {
+            final UserServices<V> user = findOrCreateUserLocked(userId);
+            return user.mBindInstantServiceAllowed;
+        }
+    }
+
+    /**
+     * Set whether the binding to service is allowed or not for instant apps.
+     */
+    public void setBindInstantServiceAllowed(int userId, boolean allowed) {
+        mContext.enforceCallingOrSelfPermission(
+                Manifest.permission.MANAGE_BIND_INSTANT_SERVICE,
+                "setBindInstantServiceAllowed");
+
+        synchronized (mServicesLock) {
+            final UserServices<V> user = findOrCreateUserLocked(userId);
+            user.mBindInstantServiceAllowed = allowed;
+        }
+    }
+
     @VisibleForTesting
     protected boolean inSystemImage(int callerUid) {
         String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid);
@@ -409,10 +441,16 @@
     @VisibleForTesting
     protected List<ResolveInfo> queryIntentServices(int userId) {
         final PackageManager pm = mContext.getPackageManager();
-        return pm.queryIntentServicesAsUser(new Intent(mInterfaceName),
-                PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE
-                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
-                userId);
+        int flags = PackageManager.GET_META_DATA
+                | PackageManager.MATCH_DIRECT_BOOT_AWARE
+                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+        synchronized (mServicesLock) {
+            final UserServices<V> user = findOrCreateUserLocked(userId);
+            if (user.mBindInstantServiceAllowed) {
+                flags |= PackageManager.MATCH_INSTANT;
+            }
+        }
+        return pm.queryIntentServicesAsUser(new Intent(mInterfaceName), flags, userId);
     }
 
     /**
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 316c796..101fb82 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -296,7 +296,9 @@
             final boolean useCompatibilityWal = mConfiguration.useCompatibilityWal();
             if (walEnabled || useCompatibilityWal) {
                 setJournalMode("WAL");
-                if (useCompatibilityWal && SQLiteCompatibilityWalFlags.areFlagsSet()) {
+                if (mConfiguration.syncMode != null) {
+                    setSyncMode(mConfiguration.syncMode);
+                } else if (useCompatibilityWal && SQLiteCompatibilityWalFlags.areFlagsSet()) {
                     setSyncMode(SQLiteCompatibilityWalFlags.getWALSyncMode());
                 } else {
                     setSyncMode(SQLiteGlobal.getWALSyncMode());
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index b463d8d..6adae25 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -2413,8 +2413,7 @@
 
         /**
          * Returns <a href="https://sqlite.org/pragma.html#pragma_synchronous">synchronous mode</a>.
-         * This value will only be used when {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} flag
-         * is not set, otherwise a system wide default will be used.
+         * If not set, a system wide default will be used.
          * @see Builder#setSynchronousMode(String)
          */
         @Nullable
@@ -2601,7 +2600,7 @@
 
             /**
              * Sets <a href="https://sqlite.org/pragma.html#pragma_synchronous">synchronous mode</a>
-             * to use when {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} flag is not set.
+             * .
              * @return
              */
             @NonNull
diff --git a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
index 8b9dfcf..bb62268 100644
--- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
+++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
@@ -117,8 +117,9 @@
     public String journalMode;
 
     /**
-     * Synchronous mode to use when {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} is not set.
+     * Synchronous mode to use.
      * <p>Default is returned by {@link SQLiteGlobal#getDefaultSyncMode()}
+     * or {@link SQLiteGlobal#getWALSyncMode()} depending on journal mode
      */
     public String syncMode;
 
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 437153b..0fb84b7 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -384,7 +384,7 @@
         if (scheme != null) {
             if (scheme.equalsIgnoreCase("tel") || scheme.equalsIgnoreCase("sip")
                     || scheme.equalsIgnoreCase("sms") || scheme.equalsIgnoreCase("smsto")
-                    || scheme.equalsIgnoreCase("mailto")) {
+                    || scheme.equalsIgnoreCase("mailto") || scheme.equalsIgnoreCase("nfc")) {
                 StringBuilder builder = new StringBuilder(64);
                 builder.append(scheme);
                 builder.append(':');
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 3d76c250..8e8565c35 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -138,15 +138,6 @@
     }
 
     /**
-     * Dump proxy debug information.
-     *
-     * @hide
-     */
-    public static void dumpProxyDebugInfo() {
-        BinderProxy.dumpProxyDebugInfo();
-    }
-
-    /**
      * Check if binder transaction tracing is enabled.
      *
      * @hide
@@ -950,7 +941,8 @@
                     // about to crash.
                     final int totalUnclearedSize = unclearedSize();
                     if (totalUnclearedSize >= CRASH_AT_SIZE) {
-                        dumpProxyDebugInfo();
+                        dumpProxyInterfaceCounts();
+                        dumpPerUidProxyCounts();
                         Runtime.getRuntime().gc();
                         throw new AssertionError("Binder ProxyMap has too many entries: "
                                 + totalSize + " (total), " + totalUnclearedSize + " (uncleared), "
@@ -1035,11 +1027,21 @@
     private static ProxyMap sProxyMap = new ProxyMap();
 
     /**
+      * Dump proxy debug information.
+      *
+      * Note: this method is not thread-safe; callers must serialize with other
+      * accesses to sProxyMap, in particular {@link #getInstance(long, long)}.
+      *
       * @hide
       */
-    public static void dumpProxyDebugInfo() {
-        sProxyMap.dumpProxyInterfaceCounts();
-        sProxyMap.dumpPerUidProxyCounts();
+    private static void dumpProxyDebugInfo() {
+        if (Build.IS_DEBUGGABLE) {
+            sProxyMap.dumpProxyInterfaceCounts();
+            // Note that we don't call dumpPerUidProxyCounts(); this is because this
+            // method may be called as part of the uid limit being hit, and calling
+            // back into the UID tracking code would cause us to try to acquire a mutex
+            // that is held during that callback.
+        }
     }
 
     /**
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index aa97b2a..09af85d 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1004,6 +1004,32 @@
         return TextUtils.packRangeInLong(0, getLineEnd(line));
     }
 
+    /**
+     * Checks if the trailing BiDi level should be used for an offset
+     *
+     * This method is useful when the offset is at the BiDi level transition point and determine
+     * which run need to be used. For example, let's think about following input: (L* denotes
+     * Left-to-Right characters, R* denotes Right-to-Left characters.)
+     * Input (Logical Order): L1 L2 L3 R1 R2 R3 L4 L5 L6
+     * Input (Display Order): L1 L2 L3 R3 R2 R1 L4 L5 L6
+     *
+     * Then, think about selecting the range (3, 6). The offset=3 and offset=6 are ambiguous here
+     * since they are at the BiDi transition point.  In Android, the offset is considered to be
+     * associated with the trailing run if the BiDi level of the trailing run is higher than of the
+     * previous run.  In this case, the BiDi level of the input text is as follows:
+     *
+     * Input (Logical Order): L1 L2 L3 R1 R2 R3 L4 L5 L6
+     *              BiDi Run: [ Run 0 ][ Run 1 ][ Run 2 ]
+     *            BiDi Level:  0  0  0  1  1  1  0  0  0
+     *
+     * Thus, offset = 3 is part of Run 1 and this method returns true for offset = 3, since the BiDi
+     * level of Run 1 is higher than the level of Run 0.  Similarly, the offset = 6 is a part of Run
+     * 1 and this method returns false for the offset = 6 since the BiDi level of Run 1 is higher
+     * than the level of Run 2.
+     *
+     * @returns true if offset is at the BiDi level transition point and trailing BiDi level is
+     *          higher than previous BiDi level. See above for the detail.
+     */
     private boolean primaryIsTrailingPrevious(int offset) {
         int line = getLineForOffset(offset);
         int lineStart = getLineStart(line);
@@ -1054,6 +1080,41 @@
     }
 
     /**
+     * Computes in linear time the results of calling
+     * #primaryIsTrailingPrevious for all offsets on a line.
+     * @param line The line giving the offsets we compute the information for
+     * @return The array of results, indexed from 0, where 0 corresponds to the line start offset
+     */
+    private boolean[] primaryIsTrailingPreviousAllLineOffsets(int line) {
+        int lineStart = getLineStart(line);
+        int lineEnd = getLineEnd(line);
+        int[] runs = getLineDirections(line).mDirections;
+
+        boolean[] trailing = new boolean[lineEnd - lineStart + 1];
+
+        byte[] level = new byte[lineEnd - lineStart + 1];
+        for (int i = 0; i < runs.length; i += 2) {
+            int start = lineStart + runs[i];
+            int limit = start + (runs[i + 1] & RUN_LENGTH_MASK);
+            if (limit > lineEnd) {
+                limit = lineEnd;
+            }
+            level[limit - lineStart - 1] =
+                    (byte) ((runs[i + 1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK);
+        }
+
+        for (int i = 0; i < runs.length; i += 2) {
+            int start = lineStart + runs[i];
+            byte currentLevel = (byte) ((runs[i + 1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK);
+            trailing[start - lineStart] = currentLevel > (start == lineStart
+                    ? (getParagraphDirection(line) == 1 ? 0 : 1)
+                    : level[start - lineStart - 1]);
+        }
+
+        return trailing;
+    }
+
+    /**
      * Get the primary horizontal position for the specified text offset.
      * This is the location where a new character would be inserted in
      * the paragraph's primary direction.
@@ -1133,6 +1194,60 @@
     }
 
     /**
+     * Computes in linear time the results of calling
+     * #getHorizontal for all offsets on a line.
+     * @param line The line giving the offsets we compute information for
+     * @param clamped Whether to clamp the results to the width of the layout
+     * @param primary Whether the results should be the primary or the secondary horizontal
+     * @return The array of results, indexed from 0, where 0 corresponds to the line start offset
+     */
+    private float[] getLineHorizontals(int line, boolean clamped, boolean primary) {
+        int start = getLineStart(line);
+        int end = getLineEnd(line);
+        int dir = getParagraphDirection(line);
+        boolean hasTab = getLineContainsTab(line);
+        Directions directions = getLineDirections(line);
+
+        TabStops tabStops = null;
+        if (hasTab && mText instanceof Spanned) {
+            // Just checking this line should be good enough, tabs should be
+            // consistent across all lines in a paragraph.
+            TabStopSpan[] tabs = getParagraphSpans((Spanned) mText, start, end, TabStopSpan.class);
+            if (tabs.length > 0) {
+                tabStops = new TabStops(TAB_INCREMENT, tabs); // XXX should reuse
+            }
+        }
+
+        TextLine tl = TextLine.obtain();
+        tl.set(mPaint, mText, start, end, dir, directions, hasTab, tabStops);
+        boolean[] trailings = primaryIsTrailingPreviousAllLineOffsets(line);
+        if (!primary) {
+            for (int offset = 0; offset < trailings.length; ++offset) {
+                trailings[offset] = !trailings[offset];
+            }
+        }
+        float[] wid = tl.measureAllOffsets(trailings, null);
+        TextLine.recycle(tl);
+
+        if (clamped) {
+            for (int offset = 0; offset <= wid.length; ++offset) {
+                if (wid[offset] > mWidth) {
+                    wid[offset] = mWidth;
+                }
+            }
+        }
+        int left = getParagraphLeft(line);
+        int right = getParagraphRight(line);
+
+        int lineStartPos = getLineStartPos(line, left, right);
+        float[] horizontal = new float[end - start + 1];
+        for (int offset = 0; offset < horizontal.length; ++offset) {
+            horizontal[offset] = lineStartPos + wid[offset];
+        }
+        return horizontal;
+    }
+
+    /**
      * Get the leftmost position that should be exposed for horizontal
      * scrolling on the specified line.
      */
@@ -1360,6 +1475,8 @@
         // XXX: we don't care about tabs as we just use TextLine#getOffsetToLeftRightOf here.
         tl.set(mPaint, mText, lineStartOffset, lineEndOffset, getParagraphDirection(line), dirs,
                 false, null);
+        final HorizontalMeasurementProvider horizontal =
+                new HorizontalMeasurementProvider(line, primary);
 
         final int max;
         if (line == getLineCount() - 1) {
@@ -1369,7 +1486,7 @@
                     !isRtlCharAt(lineEndOffset - 1)) + lineStartOffset;
         }
         int best = lineStartOffset;
-        float bestdist = Math.abs(getHorizontal(best, primary) - horiz);
+        float bestdist = Math.abs(horizontal.get(lineStartOffset) - horiz);
 
         for (int i = 0; i < dirs.mDirections.length; i += 2) {
             int here = lineStartOffset + dirs.mDirections[i];
@@ -1385,7 +1502,7 @@
                 guess = (high + low) / 2;
                 int adguess = getOffsetAtStartOf(guess);
 
-                if (getHorizontal(adguess, primary) * swap >= horiz * swap) {
+                if (horizontal.get(adguess) * swap >= horiz * swap) {
                     high = guess;
                 } else {
                     low = guess;
@@ -1399,9 +1516,9 @@
                 int aft = tl.getOffsetToLeftRightOf(low - lineStartOffset, isRtl) + lineStartOffset;
                 low = tl.getOffsetToLeftRightOf(aft - lineStartOffset, !isRtl) + lineStartOffset;
                 if (low >= here && low < there) {
-                    float dist = Math.abs(getHorizontal(low, primary) - horiz);
+                    float dist = Math.abs(horizontal.get(low) - horiz);
                     if (aft < there) {
-                        float other = Math.abs(getHorizontal(aft, primary) - horiz);
+                        float other = Math.abs(horizontal.get(aft) - horiz);
 
                         if (other < dist) {
                             dist = other;
@@ -1416,7 +1533,7 @@
                 }
             }
 
-            float dist = Math.abs(getHorizontal(here, primary) - horiz);
+            float dist = Math.abs(horizontal.get(here) - horiz);
 
             if (dist < bestdist) {
                 bestdist = dist;
@@ -1424,7 +1541,7 @@
             }
         }
 
-        float dist = Math.abs(getHorizontal(max, primary) - horiz);
+        float dist = Math.abs(horizontal.get(max) - horiz);
 
         if (dist <= bestdist) {
             best = max;
@@ -1435,6 +1552,46 @@
     }
 
     /**
+     * Responds to #getHorizontal queries, by selecting the better strategy between:
+     * - calling #getHorizontal explicitly for each query
+     * - precomputing all #getHorizontal measurements, and responding to any query in constant time
+     * The first strategy is used for LTR-only text, while the second is used for all other cases.
+     * The class is currently only used in #getOffsetForHorizontal, so reuse with care in other
+     * contexts.
+     */
+    private class HorizontalMeasurementProvider {
+        private final int mLine;
+        private final boolean mPrimary;
+
+        private float[] mHorizontals;
+        private int mLineStartOffset;
+
+        HorizontalMeasurementProvider(final int line, final boolean primary) {
+            mLine = line;
+            mPrimary = primary;
+            init();
+        }
+
+        private void init() {
+            final Directions dirs = getLineDirections(mLine);
+            if (dirs == DIRS_ALL_LEFT_TO_RIGHT) {
+                return;
+            }
+
+            mHorizontals = getLineHorizontals(mLine, false, mPrimary);
+            mLineStartOffset = getLineStart(mLine);
+        }
+
+        float get(final int offset) {
+            if (mHorizontals == null) {
+                return getHorizontal(offset, mPrimary);
+            } else {
+                return mHorizontals[offset - mLineStartOffset];
+            }
+        }
+    }
+
+    /**
      * Return the text offset after the last character on the specified line.
      */
     public final int getLineEnd(int line) {
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index fcb7d62..5bfd3e9 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -388,6 +388,98 @@
     }
 
     /**
+     * @see #measure(int, boolean, FontMetricsInt)
+     * @return The measure results for all possible offsets
+     */
+    float[] measureAllOffsets(boolean[] trailing, FontMetricsInt fmi) {
+        float[] measurement = new float[mLen + 1];
+
+        int[] target = new int[mLen + 1];
+        for (int offset = 0; offset < target.length; ++offset) {
+            target[offset] = trailing[offset] ? offset - 1 : offset;
+        }
+        if (target[0] < 0) {
+            measurement[0] = 0;
+        }
+
+        float h = 0;
+
+        if (!mHasTabs) {
+            if (mDirections == Layout.DIRS_ALL_LEFT_TO_RIGHT) {
+                for (int offset = 0; offset <= mLen; ++offset) {
+                    measurement[offset] = measureRun(0, offset, mLen, false, fmi);
+                }
+                return measurement;
+            }
+            if (mDirections == Layout.DIRS_ALL_RIGHT_TO_LEFT) {
+                for (int offset = 0; offset <= mLen; ++offset) {
+                    measurement[offset] = measureRun(0, offset, mLen, true, fmi);
+                }
+                return measurement;
+            }
+        }
+
+        char[] chars = mChars;
+        int[] runs = mDirections.mDirections;
+        for (int i = 0; i < runs.length; i += 2) {
+            int runStart = runs[i];
+            int runLimit = runStart + (runs[i + 1] & Layout.RUN_LENGTH_MASK);
+            if (runLimit > mLen) {
+                runLimit = mLen;
+            }
+            boolean runIsRtl = (runs[i + 1] & Layout.RUN_RTL_FLAG) != 0;
+
+            int segstart = runStart;
+            for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; ++j) {
+                int codept = 0;
+                if (mHasTabs && j < runLimit) {
+                    codept = chars[j];
+                    if (codept >= 0xD800 && codept < 0xDC00 && j + 1 < runLimit) {
+                        codept = Character.codePointAt(chars, j);
+                        if (codept > 0xFFFF) {
+                            ++j;
+                            continue;
+                        }
+                    }
+                }
+
+                if (j == runLimit || codept == '\t') {
+                    float oldh = h;
+                    boolean advance = (mDir == Layout.DIR_RIGHT_TO_LEFT) == runIsRtl;
+                    float w = measureRun(segstart, j, j, runIsRtl, fmi);
+                    h += advance ? w : -w;
+
+                    float baseh = advance ? oldh : h;
+                    FontMetricsInt crtfmi = advance ? fmi : null;
+                    for (int offset = segstart; offset <= j && offset <= mLen; ++offset) {
+                        if (target[offset] >= segstart && target[offset] < j) {
+                            measurement[offset] =
+                                    baseh + measureRun(segstart, offset, j, runIsRtl, crtfmi);
+                        }
+                    }
+
+                    if (codept == '\t') {
+                        if (target[j] == j) {
+                            measurement[j] = h;
+                        }
+                        h = mDir * nextTab(h * mDir);
+                        if (target[j + 1] == j) {
+                            measurement[j + 1] =  h;
+                        }
+                    }
+
+                    segstart = j + 1;
+                }
+            }
+        }
+        if (target[mLen] == mLen) {
+            measurement[mLen] = h;
+        }
+
+        return measurement;
+    }
+
+    /**
      * Draws a unidirectional (but possibly multi-styled) run of text.
      *
      *
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 37aca26..fc34a25 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -278,7 +278,8 @@
             TRANSIT_KEYGUARD_OCCLUDE,
             TRANSIT_KEYGUARD_UNOCCLUDE,
             TRANSIT_TRANSLUCENT_ACTIVITY_OPEN,
-            TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE
+            TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE,
+            TRANSIT_CRASHING_ACTIVITY_CLOSE
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface TransitionType {}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 10de449..d07721a 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1688,6 +1688,11 @@
         if (ims == null) {
             return false;
         }
+        final boolean wasContentChanged = ims.mContentChanged;
+        if (!wasContentChanged && !ims.mSelectionModeChanged) {
+            return false;
+        }
+        ims.mContentChanged = false;
         ims.mSelectionModeChanged = false;
         final ExtractedTextRequest req = ims.mExtractedTextRequest;
         if (req == null) {
@@ -1703,7 +1708,7 @@
                     + " end=" + ims.mChangedEnd
                     + " delta=" + ims.mChangedDelta);
         }
-        if (ims.mChangedStart < 0 && !ims.mContentChanged) {
+        if (ims.mChangedStart < 0 && !wasContentChanged) {
             ims.mChangedStart = EXTRACT_NOTHING;
         }
         if (extractTextInternal(req, ims.mChangedStart, ims.mChangedEnd,
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 4f567d2..c31f17a 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -934,7 +934,7 @@
         public static final int TARGET_STANDARD = 2;
 
         private static final int MAX_SERVICE_TARGETS = 4;
-        private static final int MAX_TARGETS_PER_SERVICE = 4;
+        private static final int MAX_TARGETS_PER_SERVICE = 2;
 
         private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
         private final List<TargetInfo> mCallerTargets = new ArrayList<>();
@@ -942,6 +942,8 @@
 
         private float mLateFee = 1.f;
 
+        private boolean mTargetsNeedPruning = false;
+
         private final BaseChooserTargetComparator mBaseTargetComparator
                 = new BaseChooserTargetComparator();
 
@@ -1030,7 +1032,13 @@
             }
 
             if (mServiceTargets != null) {
-                pruneServiceTargets();
+                if (getDisplayInfoCount() == 0) {
+                    // b/109676071: When packages change, onListRebuilt() is called before
+                    // ResolverActivity.mDisplayList is re-populated; pruning now would cause the
+                    // list to disappear briefly, so instead we detect this case (the
+                    // set of targets suddenly dropping to zero) and remember to prune later.
+                    mTargetsNeedPruning = true;
+                }
             }
             if (DEBUG) Log.d(TAG, "List built querying services");
             queryTargetServices(this);
@@ -1117,6 +1125,14 @@
         public void addServiceResults(DisplayResolveInfo origTarget, List<ChooserTarget> targets) {
             if (DEBUG) Log.d(TAG, "addServiceResults " + origTarget + ", " + targets.size()
                     + " targets");
+
+            if (mTargetsNeedPruning && targets.size() > 0) {
+                // First proper update since we got an onListRebuilt() with (transient) 0 items.
+                // Clear out the target list and rebuild.
+                mServiceTargets.clear();
+                mTargetsNeedPruning = false;
+            }
+
             final float parentScore = getScore(origTarget);
             Collections.sort(targets, mBaseTargetComparator);
             float lastScore = 0;
@@ -1169,17 +1185,6 @@
             }
             mServiceTargets.add(chooserTargetInfo);
         }
-
-        private void pruneServiceTargets() {
-            if (DEBUG) Log.d(TAG, "pruneServiceTargets");
-            for (int i = mServiceTargets.size() - 1; i >= 0; i--) {
-                final ChooserTargetInfo cti = mServiceTargets.get(i);
-                if (!hasResolvedTarget(cti.getResolveInfo())) {
-                    if (DEBUG) Log.d(TAG, " => " + i + " " + cti);
-                    mServiceTargets.remove(i);
-                }
-            }
-        }
     }
 
     static class BaseChooserTargetComparator implements Comparator<ChooserTarget> {
diff --git a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
index 1959301..d8ee4dd 100644
--- a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
+++ b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
@@ -112,7 +112,7 @@
             }
 
             case KeyEvent.KEYCODE_CALL: {
-                if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) {
+                if (isNotInstantAppAndKeyguardRestricted(dispatcher)) {
                     break;
                 }
                 if (event.getRepeatCount() == 0) {
@@ -139,7 +139,7 @@
             }
 
             case KeyEvent.KEYCODE_CAMERA: {
-                if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) {
+                if (isNotInstantAppAndKeyguardRestricted(dispatcher)) {
                     break;
                 }
                 if (event.getRepeatCount() == 0) {
@@ -164,7 +164,7 @@
             }
 
             case KeyEvent.KEYCODE_SEARCH: {
-                if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) {
+                if (isNotInstantAppAndKeyguardRestricted(dispatcher)) {
                     break;
                 }
                 if (event.getRepeatCount() == 0) {
@@ -202,6 +202,11 @@
         return false;
     }
 
+    private boolean isNotInstantAppAndKeyguardRestricted(KeyEvent.DispatcherState dispatcher) {
+        return !mContext.getPackageManager().isInstantApp()
+                && (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null);
+    }
+
     boolean onKeyUp(int keyCode, KeyEvent event) {
         if (DEBUG) {
             Log.d(TAG, "up " + keyCode);
@@ -238,7 +243,7 @@
             }
 
             case KeyEvent.KEYCODE_CAMERA: {
-                if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
+                if (isNotInstantAppAndKeyguardRestricted(dispatcher)) {
                     break;
                 }
                 if (event.isTracking() && !event.isCanceled()) {
@@ -248,7 +253,7 @@
             }
 
             case KeyEvent.KEYCODE_CALL: {
-                if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
+                if (isNotInstantAppAndKeyguardRestricted(dispatcher)) {
                     break;
                 }
                 if (event.isTracking() && !event.isCanceled()) {
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index a794b7b..0ba9a8c 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -1787,8 +1787,8 @@
                     results.find(ANDROID_LENS_DISTORTION);
             if (entry3.count == 5) {
                 gotDistortion = true;
-                float m_x = std::fmaxf(preWidth - cx, cx);
-                float m_y = std::fmaxf(preHeight - cy, cy);
+                float m_x = std::fmaxf(preWidth-1 - cx, cx);
+                float m_y = std::fmaxf(preHeight-1 - cy, cy);
                 float m_sq = m_x*m_x + m_y*m_y;
                 float m = sqrtf(m_sq); // distance to farthest corner from optical center
                 float f_sq = f * f;
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 1b206fd..c3ba9ba 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -108,6 +108,7 @@
     jclass mClass;
     jmethodID mGetInstance;
     jmethodID mSendDeathNotice;
+    jmethodID mDumpProxyDebugInfo;
 
     // Object state.
     jfieldID mNativeData;  // Field holds native pointer to BinderProxyNativeData.
@@ -1006,9 +1007,27 @@
 static void android_os_BinderInternal_proxyLimitcallback(int uid)
 {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
+    {
+        // Calls into BinderProxy must be serialized
+        AutoMutex _l(gProxyLock);
+        env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
+                                    gBinderProxyOffsets.mDumpProxyDebugInfo);
+    }
+    if (env->ExceptionCheck()) {
+        ScopedLocalRef<jthrowable> excep(env, env->ExceptionOccurred());
+        report_exception(env, excep.get(),
+            "*** Uncaught exception in dumpProxyDebugInfo");
+    }
+
     env->CallStaticVoidMethod(gBinderInternalOffsets.mClass,
                               gBinderInternalOffsets.mProxyLimitCallback,
                               uid);
+
+    if (env->ExceptionCheck()) {
+        ScopedLocalRef<jthrowable> excep(env, env->ExceptionOccurred());
+        report_exception(env, excep.get(),
+            "*** Uncaught exception in binderProxyLimitCallbackFromNative");
+    }
 }
 
 static void android_os_BinderInternal_setBinderProxyCountEnabled(JNIEnv* env, jobject clazz,
@@ -1389,6 +1408,8 @@
             "(JJ)Landroid/os/BinderProxy;");
     gBinderProxyOffsets.mSendDeathNotice = GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice",
             "(Landroid/os/IBinder$DeathRecipient;)V");
+    gBinderProxyOffsets.mDumpProxyDebugInfo = GetStaticMethodIDOrDie(env, clazz, "dumpProxyDebugInfo",
+            "()V");
     gBinderProxyOffsets.mNativeData = GetFieldIDOrDie(env, clazz, "mNativeData", "J");
 
     clazz = FindClassOrDie(env, "java/lang/Class");
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 066e17c..030fa60 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -352,8 +352,11 @@
      * selected alias or null will be returned via the
      * KeyChainAliasCallback callback.
      *
-     * <p>The device or profile owner can intercept this before the activity
-     * is shown, to pick a specific private key alias.
+     * <p>A device policy controller (as a device or profile owner) can
+     * intercept the request before the activity is shown, to pick a
+     * specific private key alias by implementing
+     * {@link android.app.admin.DeviceAdminReceiver#onChoosePrivateKeyAlias
+     * onChoosePrivateKeyAlias}.
      *
      * <p>{@code keyTypes} and {@code issuers} may be used to
      * highlight suggested choices to the user, although to cope with
@@ -363,7 +366,7 @@
      * <p>{@code host} and {@code port} may be used to give the user
      * more context about the server requesting the credentials.
      *
-     * <p>{@code alias} allows the chooser to preselect an existing
+     * <p>{@code alias} allows the caller to preselect an existing
      * alias which will still be subject to user confirmation.
      *
      * @param activity The {@link Activity} context to use for
@@ -403,18 +406,21 @@
      * selected alias or null will be returned via the
      * KeyChainAliasCallback callback.
      *
-     * <p>The device or profile owner can intercept this before the activity
-     * is shown, to pick a specific private key alias.</p>
+     * <p>A device policy controller (as a device or profile owner) can
+     * intercept the request before the activity is shown, to pick a
+     * specific private key alias by implementing
+     * {@link android.app.admin.DeviceAdminReceiver#onChoosePrivateKeyAlias
+     * onChoosePrivateKeyAlias}.
      *
      * <p>{@code keyTypes} and {@code issuers} may be used to
      * highlight suggested choices to the user, although to cope with
      * sometimes erroneous values provided by servers, the user may be
      * able to override these suggestions.
      *
-     * <p>{@code host} and {@code port} may be used to give the user
-     * more context about the server requesting the credentials.
+     * <p>{@code uri} may be used to give the user more context about
+     * the server requesting the credentials.
      *
-     * <p>{@code alias} allows the chooser to preselect an existing
+     * <p>{@code alias} allows the caller to preselect an existing
      * alias which will still be subject to user confirmation.
      *
      * @param activity The {@link Activity} context to use for
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java b/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java
index 44e7b07..4c45a75 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java
@@ -25,6 +25,7 @@
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Log;
@@ -42,6 +43,7 @@
 @Deprecated
 public final class UserManagerHelper {
     private static final String TAG = "UserManagerHelper";
+    private static final String HEADLESS_SYSTEM_USER = "android.car.systemuser.headless";
     private final Context mContext;
     private final UserManager mUserManager;
     private final ActivityManager mActivityManager;
@@ -77,6 +79,15 @@
     }
 
     /**
+     * Returns {@code true} if the system is in the headless user 0 model.
+     *
+     * @return {@boolean true} if headless system user.
+     */
+    public boolean isHeadlessSystemUser() {
+        return SystemProperties.getBoolean(HEADLESS_SYSTEM_USER, false);
+    }
+
+    /**
      * Gets UserInfo for the foreground user.
      *
      * Concept of foreground user is relevant for the multi-user deployment. Foreground user
@@ -153,7 +164,7 @@
      * @return All users other than user with userId.
      */
     public List<UserInfo> getAllUsersExceptUser(int userId) {
-        List<UserInfo> others = getAllUsers();
+        List<UserInfo> others = mUserManager.getUsers(/* excludeDying= */true);
 
         for (Iterator<UserInfo> iterator = others.iterator(); iterator.hasNext(); ) {
             UserInfo userInfo = iterator.next();
@@ -169,7 +180,10 @@
      * Gets all the users on the system that are not currently being removed.
      */
     public List<UserInfo> getAllUsers() {
-        return mUserManager.getUsers(true /* excludeDying */);
+        if (isHeadlessSystemUser()) {
+            return getAllUsersExcludesSystemUser();
+        }
+        return mUserManager.getUsers(/* excludeDying= */true);
     }
 
     // User information accessors
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 1c5df58..713356b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -148,7 +148,7 @@
             mCurrentInFrontAlpha = 0;
             mAnimationDuration = StatusBar.FADE_KEYGUARD_DURATION;
 
-            if (previousState == ScrimState.AOD) {
+            if (previousState == ScrimState.AOD || previousState == ScrimState.PULSING) {
                 // Fade from black to transparent when coming directly from AOD
                 updateScrimColor(mScrimInFront, 1, Color.BLACK);
                 updateScrimColor(mScrimBehind, 1, Color.BLACK);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index a2a866e..40337b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -351,6 +351,23 @@
     }
 
     @Test
+    public void scrimBlanksWhenUnlockingFromPulse() {
+        boolean[] blanked = {false};
+        // Simulate unlock with fingerprint
+        mScrimController.transitionTo(ScrimState.PULSING);
+        mScrimController.finishAnimationsImmediately();
+        mScrimController.transitionTo(ScrimState.UNLOCKED,
+                new ScrimController.Callback() {
+                    @Override
+                    public void onDisplayBlanked() {
+                        blanked[0] = true;
+                    }
+                });
+        mScrimController.finishAnimationsImmediately();
+        Assert.assertTrue("Scrim should blank when unlocking from pulse.", blanked[0]);
+    }
+
+    @Test
     public void testScrimCallback() {
         int[] callOrder = {0, 0, 0};
         int[] currentCall = {0};
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index cf310e9..f14c8f1 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -114,7 +114,7 @@
             int sessionId, boolean compatMode) {
         final LogMaker log = new LogMaker(category)
                 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, servicePackageName)
-                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SESSION_ID, sessionId);
+                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SESSION_ID, Integer.toString(sessionId));
         if (compatMode) {
             log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, 1);
         }
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index aa86ea8..786d757 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -1335,10 +1335,10 @@
         int watchedUid = -1;
         final int callingUid = Binder.getCallingUid();
         final int callingPid = Binder.getCallingPid();
-        if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
-                != PackageManager.PERMISSION_GRANTED) {
-            watchedUid = callingUid;
-        }
+        // TODO: should have a privileged permission to protect this.
+        // Also, if the caller has requested WATCH_FOREGROUND_CHANGES, should we require
+        // the USAGE_STATS permission since this can provide information about when an
+        // app is in the foreground?
         Preconditions.checkArgumentInRange(op, AppOpsManager.OP_NONE,
                 AppOpsManager._NUM_OP - 1, "Invalid op code: " + op);
         if (callback == null) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 2d2c4cd..c995c1e 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4690,7 +4690,7 @@
         // The NetworkAgentInfo does not know whether clatd is running on its network or not. Before
         // we do anything else, make sure its LinkProperties are accurate.
         if (networkAgent.clatd != null) {
-            networkAgent.clatd.fixupLinkProperties(oldLp);
+            networkAgent.clatd.fixupLinkProperties(oldLp, newLp);
         }
 
         updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities);
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 0f4702c..b8f395b 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -1535,7 +1535,8 @@
                 filter.addAction(Intent.ACTION_SCREEN_ON);
                 getContext().registerReceiver(mInteractivityReceiver, filter);
 
-                mLocalActivityManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
+                mLocalActivityManager.setDeviceIdleWhitelist(
+                        mPowerSaveWhitelistAllAppIdArray, mPowerSaveWhitelistExceptIdleAppIdArray);
                 mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
 
                 mLocalActivityManager.registerScreenObserver(mScreenObserver);
@@ -2576,11 +2577,8 @@
         mPowerSaveWhitelistUserAppIdArray = buildAppIdArray(null,
                 mPowerSaveWhitelistUserApps, mPowerSaveWhitelistUserAppIds);
         if (mLocalActivityManager != null) {
-            if (DEBUG) {
-                Slog.d(TAG, "Setting activity manager whitelist to "
-                        + Arrays.toString(mPowerSaveWhitelistAllAppIdArray));
-            }
-            mLocalActivityManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
+            mLocalActivityManager.setDeviceIdleWhitelist(
+                    mPowerSaveWhitelistAllAppIdArray, mPowerSaveWhitelistExceptIdleAppIdArray);
         }
         if (mLocalPowerManager != null) {
             if (DEBUG) {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index b2797f9..426a0c15 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -79,6 +79,8 @@
 import android.os.Process;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
 import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -408,6 +410,15 @@
         });
     }
 
+
+    boolean getBindInstantServiceAllowed(int userId) {
+        return  mAuthenticatorCache.getBindInstantServiceAllowed(userId);
+    }
+
+    void setBindInstantServiceAllowed(int userId, boolean allowed) {
+        mAuthenticatorCache.setBindInstantServiceAllowed(userId, allowed);
+    }
+
     private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
             boolean checkAccess) {
         Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
@@ -4647,6 +4658,14 @@
         }
     }
 
+    @Override
+    public void onShellCommand(FileDescriptor in, FileDescriptor out,
+            FileDescriptor err, String[] args, ShellCallback callback,
+            ResultReceiver resultReceiver) {
+        new AccountManagerServiceShellCommand(this).exec(this, in, out, err, args,
+                callback, resultReceiver);
+    }
+
     private abstract class Session extends IAccountAuthenticatorResponse.Stub
             implements IBinder.DeathRecipient, ServiceConnection {
         IAccountManagerResponse mResponse;
@@ -5018,8 +5037,11 @@
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
                 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
             }
-            if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
-                    UserHandle.of(mAccounts.userId))) {
+            int flags = Context.BIND_AUTO_CREATE;
+            if (mAuthenticatorCache.getBindInstantServiceAllowed(mAccounts.userId)) {
+                flags |= Context.BIND_ALLOW_INSTANT;
+            }
+            if (!mContext.bindServiceAsUser(intent, this, flags, UserHandle.of(mAccounts.userId))) {
                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
                     Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
                 }
diff --git a/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java b/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java
new file mode 100644
index 0000000..9e5f722
--- /dev/null
+++ b/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.accounts;
+
+import android.annotation.NonNull;
+import android.os.ShellCommand;
+import android.os.UserHandle;
+
+import java.io.PrintWriter;
+
+/**
+ * Shell command implementation for the account manager service
+ */
+final class AccountManagerServiceShellCommand extends ShellCommand {
+    final @NonNull AccountManagerService mService;
+
+    AccountManagerServiceShellCommand(@NonNull AccountManagerService service) {
+        mService = service;
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(cmd);
+        }
+        switch (cmd) {
+            case "get-bind-instant-service-allowed": {
+                return runGetBindInstantServiceAllowed();
+            }
+            case "set-bind-instant-service-allowed": {
+                return runSetBindInstantServiceAllowed();
+            }
+        }
+        return -1;
+    }
+
+    private int runGetBindInstantServiceAllowed() {
+        final Integer userId = parseUserId();
+        if (userId == null) {
+            return -1;
+        }
+        getOutPrintWriter().println(Boolean.toString(
+                mService.getBindInstantServiceAllowed(userId)));
+        return 0;
+    }
+
+    private int runSetBindInstantServiceAllowed() {
+        final Integer userId = parseUserId();
+        if (userId == null) {
+            return -1;
+        }
+        final String allowed = getNextArgRequired();
+        if (allowed == null) {
+            getErrPrintWriter().println("Error: no true/false specified");
+            return -1;
+        }
+        mService.setBindInstantServiceAllowed(userId,
+                Boolean.parseBoolean(allowed));
+        return 0;
+    }
+
+    private Integer parseUserId() {
+        final String option = getNextOption();
+        if (option != null) {
+            if (option.equals("--user")) {
+                return UserHandle.parseUserArg(getNextArgRequired());
+            } else {
+                getErrPrintWriter().println("Unknown option: " + option);
+                return null;
+            }
+        }
+        return UserHandle.USER_SYSTEM;
+    }
+
+    @Override
+    public void onHelp() {
+        PrintWriter pw = getOutPrintWriter();
+        pw.println("Account manager service commands:");
+        pw.println("  help");
+        pw.println("    Print this help text.");
+        pw.println("  set-bind-instant-service-allowed [--user <USER_ID>] true|false ");
+        pw.println("    Set whether binding to services provided by instant apps is allowed.");
+        pw.println("  get-bind-instant-service-allowed [--user <USER_ID>]");
+        pw.println("    Get whether binding to services provided by instant apps is allowed.");
+    }
+}
diff --git a/services/core/java/com/android/server/accounts/IAccountAuthenticatorCache.java b/services/core/java/com/android/server/accounts/IAccountAuthenticatorCache.java
index 2c7d921..b13f66f 100644
--- a/services/core/java/com/android/server/accounts/IAccountAuthenticatorCache.java
+++ b/services/core/java/com/android/server/accounts/IAccountAuthenticatorCache.java
@@ -70,4 +70,7 @@
      * picked up by the cache.
      */
     void updateServices(int userId);
+
+    boolean getBindInstantServiceAllowed(int userId);
+    void setBindInstantServiceAllowed(int userId, boolean allowed);
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e95a932..2458234 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1376,11 +1376,16 @@
     DeviceIdleController.LocalService mLocalDeviceIdleController;
 
     /**
-     * Set of app ids that are whitelisted for device idle and thus background check.
+     * Power-save whitelisted app-ids (not including except-idle-whitelisted ones).
      */
     int[] mDeviceIdleWhitelist = new int[0];
 
     /**
+     * Power-save whitelisted app-ids (including except-idle-whitelisted ones).
+     */
+    int[] mDeviceIdleExceptIdleWhitelist = new int[0];
+
+    /**
      * Set of app ids that are temporarily allowed to escape bg check due to high-pri message
      */
     int[] mDeviceIdleTempWhitelist = new int[0];
@@ -9316,7 +9321,7 @@
                 // If force-background-check is enabled, restrict all apps that aren't whitelisted.
                 if (mForceBackgroundCheck &&
                         !UserHandle.isCore(uid) &&
-                        !isOnDeviceIdleWhitelistLocked(uid)) {
+                        !isOnDeviceIdleWhitelistLocked(uid, /*allowExceptIdleToo=*/ true)) {
                     if (DEBUG_BACKGROUND_CHECK) {
                         Slog.i(TAG, "Force background check: " +
                                 uid + "/" + packageName + " restricted");
@@ -9354,7 +9359,7 @@
         }
 
         // Is this app on the battery whitelist?
-        if (isOnDeviceIdleWhitelistLocked(uid)) {
+        if (isOnDeviceIdleWhitelistLocked(uid, /*allowExceptIdleToo=*/ false)) {
             if (DEBUG_BACKGROUND_CHECK) {
                 Slog.i(TAG, "App " + uid + "/" + packageName
                         + " on idle whitelist; not restricted in background");
@@ -9396,9 +9401,12 @@
                         ? appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk)
                         : appServicesRestrictedInBackgroundLocked(uid, packageName,
                                 packageTargetSdk);
-                if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid
-                        + " pkg=" + packageName + " startMode=" + startMode
-                        + " onwhitelist=" + isOnDeviceIdleWhitelistLocked(uid));
+                if (DEBUG_BACKGROUND_CHECK) {
+                    Slog.d(TAG, "checkAllowBackground: uid=" + uid
+                            + " pkg=" + packageName + " startMode=" + startMode
+                            + " onwhitelist=" + isOnDeviceIdleWhitelistLocked(uid, false)
+                            + " onwhitelist(ei)=" + isOnDeviceIdleWhitelistLocked(uid, true));
+                }
                 if (startMode == ActivityManager.APP_START_MODE_DELAYED) {
                     // This is an old app that has been forced into a "compatible as possible"
                     // mode of background check.  To increase compatibility, we will allow other
@@ -9425,9 +9433,14 @@
     /**
      * @return whether a UID is in the system, user or temp doze whitelist.
      */
-    boolean isOnDeviceIdleWhitelistLocked(int uid) {
+    boolean isOnDeviceIdleWhitelistLocked(int uid, boolean allowExceptIdleToo) {
         final int appId = UserHandle.getAppId(uid);
-        return Arrays.binarySearch(mDeviceIdleWhitelist, appId) >= 0
+
+        final int[] whitelist = allowExceptIdleToo
+                ? mDeviceIdleExceptIdleWhitelist
+                : mDeviceIdleWhitelist;
+
+        return Arrays.binarySearch(whitelist, appId) >= 0
                 || Arrays.binarySearch(mDeviceIdleTempWhitelist, appId) >= 0
                 || mPendingTempWhitelist.indexOfKey(uid) >= 0;
     }
@@ -15305,7 +15318,6 @@
                         public void onLimitReached(int uid) {
                             Slog.wtf(TAG, "Uid " + uid + " sent too many Binders to uid "
                                     + Process.myUid());
-                            Binder.dumpProxyDebugInfo();
                             if (uid == Process.SYSTEM_UID) {
                                 Slog.i(TAG, "Skipping kill (uid is SYSTEM)");
                             } else {
@@ -16969,6 +16981,8 @@
                 }
             }
             pw.println("  mDeviceIdleWhitelist=" + Arrays.toString(mDeviceIdleWhitelist));
+            pw.println("  mDeviceIdleExceptIdleWhitelist="
+                    + Arrays.toString(mDeviceIdleExceptIdleWhitelist));
             pw.println("  mDeviceIdleTempWhitelist=" + Arrays.toString(mDeviceIdleTempWhitelist));
             if (mPendingTempWhitelist.size() > 0) {
                 pw.println("  mPendingTempWhitelist:");
@@ -21021,9 +21035,15 @@
     }
 
     private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,
-            int callingUid, int[] users) {
+            int callingUid, boolean callerInstantApp, int[] users) {
         // TODO: come back and remove this assumption to triage all broadcasts
         int pmFlags = STOCK_PM_FLAGS | MATCH_DEBUG_TRIAGED_MISSING;
+        // Instant apps should be able to send broadcasts to themselves, so we would
+        // match instant receivers and later the broadcast queue would enforce that
+        // the broadcast cannot be sent to a receiver outside the instant UID.
+        if (callerInstantApp) {
+            pmFlags |= PackageManager.MATCH_INSTANT;
+        }
 
         List<ResolveInfo> receivers = null;
         try {
@@ -21652,7 +21672,8 @@
         // Need to resolve the intent to interested receivers...
         if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
                  == 0) {
-            receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
+            receivers = collectReceiverComponents(intent, resolvedType, callingUid,
+                    callerInstantApp, users);
         }
         if (intent.getComponent() == null) {
             if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
@@ -26421,9 +26442,10 @@
         }
 
         @Override
-        public void setDeviceIdleWhitelist(int[] appids) {
+        public void setDeviceIdleWhitelist(int[] allAppids, int[] exceptIdleAppids) {
             synchronized (ActivityManagerService.this) {
-                mDeviceIdleWhitelist = appids;
+                mDeviceIdleWhitelist = allAppids;
+                mDeviceIdleExceptIdleWhitelist = exceptIdleAppids;
             }
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index f157cc4..75f2723 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -313,6 +313,7 @@
                                         // process that it is hidden.
     boolean sleeping;       // have we told the activity to sleep?
     boolean nowVisible;     // is this activity's window visible?
+    boolean mClientVisibilityDeferred;// was the visibility change message to client deferred?
     boolean idle;           // has the activity gone idle?
     boolean hasBeenLaunched;// has this activity ever been launched?
     boolean frozenBeforeDestroy;// has been frozen but not yet destroyed.
@@ -777,6 +778,13 @@
         }
     }
 
+    /**
+     * See {@link AppWindowContainerController#setWillCloseOrEnterPip(boolean)}
+     */
+    void setWillCloseOrEnterPip(boolean willCloseOrEnterPip) {
+        getWindowContainerController().setWillCloseOrEnterPip(willCloseOrEnterPip);
+    }
+
     static class Token extends IApplicationToken.Stub {
         private final WeakReference<ActivityRecord> weakActivity;
         private final String name;
@@ -1716,7 +1724,7 @@
         return !behindFullscreenActivity || mLaunchTaskBehind;
     }
 
-    void makeVisibleIfNeeded(ActivityRecord starting) {
+    void makeVisibleIfNeeded(ActivityRecord starting, boolean reportToClient) {
         // This activity is not currently visible, but is running. Tell it to become visible.
         if (mState == RESUMED || this == starting) {
             if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY,
@@ -1736,15 +1744,28 @@
             setVisible(true);
             sleeping = false;
             app.pendingUiClean = true;
-            service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
-                    WindowVisibilityItem.obtain(true /* showWindow */));
+            if (reportToClient) {
+                makeClientVisible();
+            } else {
+                mClientVisibilityDeferred = true;
+            }
             // The activity may be waiting for stop, but that is no longer appropriate for it.
             mStackSupervisor.mStoppingActivities.remove(this);
             mStackSupervisor.mGoingToSleepActivities.remove(this);
+        } catch (Exception e) {
+            // Just skip on any failure; we'll make it visible when it next restarts.
+            Slog.w(TAG, "Exception thrown making visible: " + intent.getComponent(), e);
+        }
+        handleAlreadyVisible();
+    }
 
+    /** Send visibility change message to the client and pause if needed. */
+    void makeClientVisible() {
+        mClientVisibilityDeferred = false;
+        try {
+            service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
+                    WindowVisibilityItem.obtain(true /* showWindow */));
             if (shouldPauseWhenBecomingVisible()) {
-                // Capture reason before state change
-
                 // An activity must be in the {@link PAUSING} state for the system to validate
                 // the move to {@link PAUSED}.
                 setState(PAUSING, "makeVisibleIfNeeded");
@@ -1753,10 +1774,8 @@
                                 configChangeFlags, false /* dontReport */));
             }
         } catch (Exception e) {
-            // Just skip on any failure; we'll make it visible when it next restarts.
-            Slog.w(TAG, "Exception thrown making visible: " + intent.getComponent(), e);
+            Slog.w(TAG, "Exception thrown sending visibility update: " + intent.getComponent(), e);
         }
-        handleAlreadyVisible();
     }
 
     /** Check if activity should be moved to PAUSED state when it becomes visible. */
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 748eae9..cc7a230 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1360,8 +1360,8 @@
 
     void goToSleep() {
         // Ensure visibility without updating configuration, as activities are about to sleep.
-        ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */, !PRESERVE_WINDOWS,
-                false /* updateConfiguration */);
+        ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */,
+                !PRESERVE_WINDOWS);
 
         // Make sure any paused or stopped but visible activities are now sleeping.
         // This ensures that the activity's onStop() is called.
@@ -1556,6 +1556,7 @@
         if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Complete pause: " + prev);
 
         if (prev != null) {
+            prev.setWillCloseOrEnterPip(false);
             final boolean wasStopping = prev.isState(STOPPING);
             prev.setState(PAUSED, "completePausedLocked");
             if (prev.finishing) {
@@ -1653,6 +1654,13 @@
     void addToStopping(ActivityRecord r, boolean scheduleIdle, boolean idleDelayed) {
         if (!mStackSupervisor.mStoppingActivities.contains(r)) {
             mStackSupervisor.mStoppingActivities.add(r);
+
+            // Some activity is waiting for another activity to become visible before it's being
+            // stopped, which means that we also want to wait with stopping this one to avoid
+            // flickers.
+            if (!mStackSupervisor.mActivitiesWaitingForVisibleActivity.isEmpty()) {
+                mStackSupervisor.mActivitiesWaitingForVisibleActivity.add(r);
+            }
         }
 
         // If we already have a few activities waiting to stop, then give up
@@ -1836,7 +1844,7 @@
     final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
             boolean preserveWindows) {
         ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows,
-                true /* updateConfiguration */);
+                true /* notifyClients */);
     }
 
     /**
@@ -1846,7 +1854,7 @@
      */
     // TODO: Should be re-worked based on the fact that each task as a stack in most cases.
     final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
-            boolean preserveWindows, boolean updateConfiguration) {
+            boolean preserveWindows, boolean notifyClients) {
         mTopActivityOccludesKeyguard = false;
         mTopDismissingKeyguardActivity = null;
         mStackSupervisor.getKeyguardController().beginActivityVisibilityUpdate();
@@ -1898,7 +1906,7 @@
                                 + " finishing=" + r.finishing + " state=" + r.getState());
                         // First: if this is not the current activity being started, make
                         // sure it matches the current configuration.
-                        if (r != starting && updateConfiguration) {
+                        if (r != starting && notifyClients) {
                             r.ensureActivityConfiguration(0 /* globalChanges */, preserveWindows,
                                     true /* ignoreStopState */);
                         }
@@ -1918,11 +1926,15 @@
                             if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
                                     "Skipping: already visible at " + r);
 
+                            if (r.mClientVisibilityDeferred && notifyClients) {
+                                r.makeClientVisible();
+                            }
+
                             if (r.handleAlreadyVisible()) {
                                 resumeNextActivity = false;
                             }
                         } else {
-                            r.makeVisibleIfNeeded(starting);
+                            r.makeVisibleIfNeeded(starting, notifyClients);
                         }
                         // Aggregate current change flags.
                         configChanges |= r.configChangeFlags;
@@ -2410,11 +2422,12 @@
         mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid);
 
         boolean lastResumedCanPip = false;
+        ActivityRecord lastResumed = null;
         final ActivityStack lastFocusedStack = mStackSupervisor.getLastStack();
         if (lastFocusedStack != null && lastFocusedStack != this) {
             // So, why aren't we using prev here??? See the param comment on the method. prev doesn't
             // represent the last resumed activity. However, the last focus stack does if it isn't null.
-            final ActivityRecord lastResumed = lastFocusedStack.mResumedActivity;
+            lastResumed = lastFocusedStack.mResumedActivity;
             if (userLeaving && inMultiWindowMode() && lastFocusedStack.shouldBeVisible(next)) {
                 // The user isn't leaving if this stack is the multi-window mode and the last
                 // focused stack should still be visible.
@@ -2449,6 +2462,9 @@
                 mService.updateLruProcessLocked(next.app, true, null);
             }
             if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
+            if (lastResumed != null) {
+                lastResumed.setWillCloseOrEnterPip(true);
+            }
             return true;
         } else if (mResumedActivity == next && next.isState(RESUMED)
                 && mStackSupervisor.allResumedActivitiesComplete()) {
@@ -3549,8 +3565,8 @@
         int taskNdx = mTaskHistory.indexOf(finishedTask);
         final TaskRecord task = finishedTask;
         int activityNdx = task.mActivities.indexOf(r);
-        mWindowManager.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* TODO */,
-                0, true /* forceOverride */);
+        mWindowManager.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE,
+                false /* alwaysKeepCurrent */);
         finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false);
         finishedTask = task;
         // Also terminate any activities below it that aren't yet
@@ -3835,7 +3851,7 @@
             if (finishingActivityInNonFocusedStack) {
                 // Finishing activity that was in paused state and it was in not currently focused
                 // stack, need to make something visible in its place.
-                mStackSupervisor.ensureVisibilityAndConfig(null, mDisplayId,
+                mStackSupervisor.ensureVisibilityAndConfig(next, mDisplayId,
                         false /* markFrozenIfConfigChanged */, true /* deferResume */);
             }
             if (activityRemoved) {
@@ -5001,7 +5017,7 @@
                     // Force the destroy to skip right to removal.
                     r.app = null;
                     mWindowManager.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE,
-                            false /* TODO */, 0, true /* forceOverride */);
+                            false /* alwaysKeepCurrent */);
                     finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false,
                             "handleAppCrashedLocked");
                 }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 76cc342..e034b82 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1628,27 +1628,36 @@
 
     /**
      * Ensure all activities visibility, update orientation and configuration.
+     *
+     * @param starting The currently starting activity or {@code null} if there is none.
+     * @param displayId The id of the display where operation is executed.
+     * @param markFrozenIfConfigChanged Whether to set {@link ActivityRecord#frozenBeforeDestroy} to
+     *                                  {@code true} if config changed.
+     * @param deferResume Whether to defer resume while updating config.
      */
-    boolean ensureVisibilityAndConfig(ActivityRecord r, int displayId,
+    boolean ensureVisibilityAndConfig(ActivityRecord starting, int displayId,
             boolean markFrozenIfConfigChanged, boolean deferResume) {
         // First ensure visibility without updating the config just yet. We need this to know what
         // activities are affecting configuration now.
+        // Passing null here for 'starting' param value, so that visibility of actual starting
+        // activity will be properly updated.
         ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */,
-                false /* preserveWindows */, false /* updateConfiguration */);
+                false /* preserveWindows */, false /* notifyClients */);
 
         // Force-update the orientation from the WindowManager, since we need the true configuration
         // to send to the client now.
         final Configuration config = mWindowManager.updateOrientationFromAppTokens(
                 getDisplayOverrideConfiguration(displayId),
-                r != null && r.mayFreezeScreenLocked(r.app) ? r.appToken : null,
+                starting != null && starting.mayFreezeScreenLocked(starting.app)
+                        ? starting.appToken : null,
                 displayId, true /* forceUpdate */);
-        if (r != null && markFrozenIfConfigChanged && config != null) {
-            r.frozenBeforeDestroy = true;
+        if (starting != null && markFrozenIfConfigChanged && config != null) {
+            starting.frozenBeforeDestroy = true;
         }
 
         // Update the configuration of the activities on the display.
-        return mService.updateDisplayOverrideConfigurationLocked(config, r,
-                deferResume, displayId);
+        return mService.updateDisplayOverrideConfigurationLocked(config, starting, deferResume,
+                displayId);
     }
 
     private void logIfTransactionTooLarge(Intent intent, Bundle icicle) {
@@ -3681,14 +3690,14 @@
     void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
             boolean preserveWindows) {
         ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows,
-                true /* updateConfiguration */);
+                true /* notifyClients */);
     }
 
     /**
      * @see #ensureActivitiesVisibleLocked(ActivityRecord, int, boolean)
      */
     void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
-            boolean preserveWindows, boolean updateConfiguration) {
+            boolean preserveWindows, boolean notifyClients) {
         getKeyguardController().beginActivityVisibilityUpdate();
         try {
             // First the front stacks. In case any are not fullscreen and are in front of home.
@@ -3697,7 +3706,7 @@
                 for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
                     final ActivityStack stack = display.getChildAt(stackNdx);
                     stack.ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows,
-                            updateConfiguration);
+                            notifyClients);
                 }
             }
         } finally {
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index fceacba..f523d59 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -224,15 +224,14 @@
     }
 
     /**
-     * Copies the stacked clat link in oldLp, if any, to the LinkProperties in mNetwork.
+     * Copies the stacked clat link in oldLp, if any, to the passed LinkProperties.
      * This is necessary because the LinkProperties in mNetwork come from the transport layer, which
      * has no idea that 464xlat is running on top of it.
      */
-    public void fixupLinkProperties(LinkProperties oldLp) {
+    public void fixupLinkProperties(LinkProperties oldLp, LinkProperties lp) {
         if (!isRunning()) {
             return;
         }
-        LinkProperties lp = mNetwork.linkProperties;
         if (lp == null || lp.getAllInterfaceNames().contains(mIface)) {
             return;
         }
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index a9198983..b77c144 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -117,6 +117,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
@@ -895,6 +896,42 @@
                 .compareTo(MOST_IPV6_ADDRESSES_COUNT) >= 0;
     }
 
+    /**
+     * Attempt to perform a seamless handover of VPNs by only updating LinkProperties without
+     * registering a new NetworkAgent. This is not always possible if the new VPN configuration
+     * has certain changes, in which case this method would just return {@code false}.
+     */
+    private boolean updateLinkPropertiesInPlaceIfPossible(NetworkAgent agent, VpnConfig oldConfig) {
+        // NetworkMisc cannot be updated without registering a new NetworkAgent.
+        if (oldConfig.allowBypass != mConfig.allowBypass) {
+            Log.i(TAG, "Handover not possible due to changes to allowBypass");
+            return false;
+        }
+
+        // TODO: we currently do not support seamless handover if the allowed or disallowed
+        // applications have changed. Consider diffing UID ranges and only applying the delta.
+        if (!Objects.equals(oldConfig.allowedApplications, mConfig.allowedApplications) ||
+                !Objects.equals(oldConfig.disallowedApplications, mConfig.disallowedApplications)) {
+            Log.i(TAG, "Handover not possible due to changes to whitelisted/blacklisted apps");
+            return false;
+        }
+
+        LinkProperties lp = makeLinkProperties();
+        final boolean hadInternetCapability = mNetworkCapabilities.hasCapability(
+                NetworkCapabilities.NET_CAPABILITY_INTERNET);
+        final boolean willHaveInternetCapability = providesRoutesToMostDestinations(lp);
+        if (hadInternetCapability != willHaveInternetCapability) {
+            // A seamless handover would have led to a change to INTERNET capability, which
+            // is supposed to be immutable for a given network. In this case bail out and do not
+            // perform handover.
+            Log.i(TAG, "Handover not possible due to changes to INTERNET capability");
+            return false;
+        }
+
+        agent.sendLinkProperties(lp);
+        return true;
+    }
+
     private void agentConnect() {
         LinkProperties lp = makeLinkProperties();
 
@@ -1003,13 +1040,11 @@
         String oldInterface = mInterface;
         Connection oldConnection = mConnection;
         NetworkAgent oldNetworkAgent = mNetworkAgent;
-        mNetworkAgent = null;
         Set<UidRange> oldUsers = mNetworkCapabilities.getUids();
 
         // Configure the interface. Abort if any of these steps fails.
         ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
         try {
-            updateState(DetailedState.CONNECTING, "establish");
             String interfaze = jniGetName(tun.getFd());
 
             // TEMP use the old jni calls until there is support for netd address setting
@@ -1037,15 +1072,26 @@
             mConfig = config;
 
             // Set up forwarding and DNS rules.
-            agentConnect();
+            // First attempt to do a seamless handover that only changes the interface name and
+            // parameters. If that fails, disconnect.
+            if (oldConfig != null
+                    && updateLinkPropertiesInPlaceIfPossible(mNetworkAgent, oldConfig)) {
+                // Keep mNetworkAgent unchanged
+            } else {
+                mNetworkAgent = null;
+                updateState(DetailedState.CONNECTING, "establish");
+                // Set up forwarding and DNS rules.
+                agentConnect();
+                // Remove the old tun's user forwarding rules
+                // The new tun's user rules have already been added above so they will take over
+                // as rules are deleted. This prevents data leakage as the rules are moved over.
+                agentDisconnect(oldNetworkAgent);
+            }
 
             if (oldConnection != null) {
                 mContext.unbindService(oldConnection);
             }
-            // Remove the old tun's user forwarding rules
-            // The new tun's user rules have already been added so they will take over
-            // as rules are deleted. This prevents data leakage as the rules are moved over.
-            agentDisconnect(oldNetworkAgent);
+
             if (oldInterface != null && !oldInterface.equals(interfaze)) {
                 jniReset(oldInterface);
             }
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
index cff216c..a3c2998 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -282,6 +282,7 @@
             return stats;
         }
 
+        @Override
         public void setInterfaceQuota(String iface, long quotaBytes) {
             mHandler.post(() -> {
                 if (quotaBytes == ITetheringStatsProvider.QUOTA_UNLIMITED) {
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
index 76195c4..207f867 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
@@ -355,6 +355,7 @@
         boolean success;
         String errMsg;
 
+        @Override
         public String toString() {
             if (success) {
                 return "ok";
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index 6371d77..fbee86a 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -16,6 +16,8 @@
 
 package com.android.server.connectivity.tethering;
 
+import static android.net.util.NetworkConstants.asByte;
+import static android.net.util.NetworkConstants.FF;
 import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
 
 import android.net.ConnectivityManager;
@@ -64,6 +66,7 @@
  */
 public class TetherInterfaceStateMachine extends StateMachine {
     private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64");
+    private static final byte DOUG_ADAMS = (byte) 42;
 
     private static final String USB_NEAR_IFACE_ADDR = "192.168.42.129";
     private static final int USB_PREFIX_LENGTH = 24;
@@ -204,7 +207,7 @@
             ipAsString = USB_NEAR_IFACE_ADDR;
             prefixLen = USB_PREFIX_LENGTH;
         } else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
-            ipAsString = WIFI_HOST_IFACE_ADDR;
+            ipAsString = getRandomWifiIPv4Address();
             prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH;
         } else {
             // Nothing to do, BT does this elsewhere.
@@ -253,6 +256,16 @@
         return true;
     }
 
+    private String getRandomWifiIPv4Address() {
+        try {
+            byte[] bytes = NetworkUtils.numericToInetAddress(WIFI_HOST_IFACE_ADDR).getAddress();
+            bytes[3] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1), FF);
+            return InetAddress.getByAddress(bytes).getHostAddress();
+        } catch (Exception e) {
+            return WIFI_HOST_IFACE_ADDR;
+        }
+    }
+
     private boolean startIPv6() {
         mInterfaceParams = mDeps.getInterfaceParams(mIfaceName);
         if (mInterfaceParams == null) {
@@ -757,7 +770,7 @@
     // Given a prefix like 2001:db8::/64 return an address like 2001:db8::1.
     private static Inet6Address getLocalDnsIpFor(IpPrefix localPrefix) {
         final byte[] dnsBytes = localPrefix.getRawAddress();
-        dnsBytes[dnsBytes.length - 1] = getRandomNonZeroByte();
+        dnsBytes[dnsBytes.length - 1] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1));
         try {
             return Inet6Address.getByAddress(null, dnsBytes, 0);
         } catch (UnknownHostException e) {
@@ -766,10 +779,11 @@
         }
     }
 
-    private static byte getRandomNonZeroByte() {
+    private static byte getRandomSanitizedByte(byte dflt, byte... excluded) {
         final byte random = (byte) (new Random()).nextInt();
-        // Don't pick the subnet-router anycast address, since that might be
-        // in use on the upstream already.
-        return (random != 0) ? random : 0x1;
+        for (int value : excluded) {
+            if (random == value) return dflt;
+        }
+        return random;
     }
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 8f7fa1b..5ba1e0f 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4443,7 +4443,7 @@
                     if (index < 0) {
                         mNotificationList.add(r);
                         mUsageStats.registerPostedByApp(r);
-                        r.setInterruptive(true);
+                        r.setInterruptive(isVisuallyInterruptive(null, r));
                     } else {
                         old = mNotificationList.get(index);
                         mNotificationList.set(index, r);
@@ -4530,6 +4530,14 @@
             return true;
         }
 
+        if (r == null) {
+            if (DEBUG_INTERRUPTIVENESS) {
+                Log.v(TAG, "INTERRUPTIVENESS: "
+                        +  r.getKey() + " is not interruptive: null");
+            }
+            return false;
+        }
+
         Notification oldN = old.sbn.getNotification();
         Notification newN = r.sbn.getNotification();
 
@@ -4543,7 +4551,7 @@
 
         // Ignore visual interruptions from foreground services because users
         // consider them one 'session'. Count them for everything else.
-        if (r != null && (r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) {
+        if ((r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) {
             if (DEBUG_INTERRUPTIVENESS) {
                 Log.v(TAG, "INTERRUPTIVENESS: "
                         +  r.getKey() + " is not interruptive: foreground service");
@@ -4551,6 +4559,15 @@
             return false;
         }
 
+        // Ignore summary updates because we don't display most of the information.
+        if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) {
+            if (DEBUG_INTERRUPTIVENESS) {
+                Log.v(TAG, "INTERRUPTIVENESS: "
+                        +  r.getKey() + " is not interruptive: summary");
+            }
+            return false;
+        }
+
         final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE));
         final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE));
         if (!Objects.equals(oldTitle, newTitle)) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 605644e..1010ce1 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4789,7 +4789,8 @@
             // require the permission to be held; the calling uid and given user id referring
             // to the same user is not sufficient
             mPermissionManager.enforceCrossUserPermission(
-                    Binder.getCallingUid(), userId, false, false, true,
+                    Binder.getCallingUid(), userId, false, false,
+                    !isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId),
                     "MATCH_ANY_USER flag requires INTERACT_ACROSS_USERS permission at "
                     + Debug.getCallers(5));
         } else if ((flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0 && isCallerSystemUser
@@ -6628,7 +6629,8 @@
                 }
             }
             return applyPostResolutionFilter(
-                    list, instantAppPkgName, allowDynamicSplits, filterCallingUid, userId, intent);
+                    list, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart,
+                    userId, intent);
         }
 
         // reader
@@ -6647,7 +6649,7 @@
                     xpResult.add(xpResolveInfo);
                     return applyPostResolutionFilter(
                             filterIfNotSystemUser(xpResult, userId), instantAppPkgName,
-                            allowDynamicSplits, filterCallingUid, userId, intent);
+                            allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent);
                 }
 
                 // Check for results in the current profile.
@@ -6687,14 +6689,16 @@
                             // result straight away.
                             result.add(xpDomainInfo.resolveInfo);
                             return applyPostResolutionFilter(result, instantAppPkgName,
-                                    allowDynamicSplits, filterCallingUid, userId, intent);
+                                    allowDynamicSplits, filterCallingUid, resolveForStart, userId,
+                                    intent);
                         }
                     } else if (result.size() <= 1 && !addInstant) {
                         // No result in parent user and <= 1 result in current profile, and we
                         // are not going to add emphemeral app, so we can return the result without
                         // further processing.
                         return applyPostResolutionFilter(result, instantAppPkgName,
-                                allowDynamicSplits, filterCallingUid, userId, intent);
+                                allowDynamicSplits, filterCallingUid, resolveForStart, userId,
+                                intent);
                     }
                     // We have more than one candidate (combining results from current and parent
                     // profile), so we need filtering and sorting.
@@ -6730,7 +6734,8 @@
             Collections.sort(result, mResolvePrioritySorter);
         }
         return applyPostResolutionFilter(
-                result, instantAppPkgName, allowDynamicSplits, filterCallingUid, userId, intent);
+                result, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart,
+                userId, intent);
     }
 
     private List<ResolveInfo> maybeAddInstantAppInstaller(List<ResolveInfo> result, Intent intent,
@@ -6940,8 +6945,8 @@
      * @return A filtered list of resolved activities.
      */
     private List<ResolveInfo> applyPostResolutionFilter(List<ResolveInfo> resolveInfos,
-            String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid, int userId,
-            Intent intent) {
+            String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
+            boolean resolveForStart, int userId, Intent intent) {
         final boolean blockInstant = intent.isWebIntent() && areWebInstantAppsDisabled();
         for (int i = resolveInfos.size() - 1; i >= 0; i--) {
             final ResolveInfo info = resolveInfos.get(i);
@@ -7000,6 +7005,13 @@
             } else if (ephemeralPkgName.equals(info.activityInfo.packageName)) {
                 // caller is same app; don't need to apply any other filtering
                 continue;
+            } else if (resolveForStart
+                    && (intent.isWebIntent()
+                            || (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) != 0)
+                    && intent.getPackage() == null
+                    && intent.getComponent() == null) {
+                // ephemeral apps can launch other ephemeral apps indirectly
+                continue;
             }
             // allow activities that have been explicitly exposed to ephemeral apps
             final boolean isEphemeralApp = info.activityInfo.applicationInfo.isInstantApp();
@@ -7578,7 +7590,8 @@
                 }
             }
             return applyPostResolutionFilter(
-                    list, instantAppPkgName, allowDynamicSplits, callingUid, userId, intent);
+                    list, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
+                    intent);
         }
 
         // reader
@@ -7588,14 +7601,16 @@
                 final List<ResolveInfo> result =
                         mReceivers.queryIntent(intent, resolvedType, flags, userId);
                 return applyPostResolutionFilter(
-                        result, instantAppPkgName, allowDynamicSplits, callingUid, userId, intent);
+                        result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
+                        intent);
             }
             final PackageParser.Package pkg = mPackages.get(pkgName);
             if (pkg != null) {
                 final List<ResolveInfo> result = mReceivers.queryIntentForPackage(
                         intent, resolvedType, flags, pkg.receivers, userId);
                 return applyPostResolutionFilter(
-                        result, instantAppPkgName, allowDynamicSplits, callingUid, userId, intent);
+                        result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
+                        intent);
             }
             return Collections.emptyList();
         }
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 1ae59cb..c9aa1ef 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -833,11 +833,11 @@
                     getSystemPackage(textClassifierPackageName);
             if (textClassifierPackage != null
                     && doesPackageSupportRuntimePermissions(textClassifierPackage)) {
-                grantRuntimePermissions(textClassifierPackage, PHONE_PERMISSIONS, false, userId);
-                grantRuntimePermissions(textClassifierPackage, SMS_PERMISSIONS, false, userId);
-                grantRuntimePermissions(textClassifierPackage, CALENDAR_PERMISSIONS, false, userId);
-                grantRuntimePermissions(textClassifierPackage, LOCATION_PERMISSIONS, false, userId);
-                grantRuntimePermissions(textClassifierPackage, CONTACTS_PERMISSIONS, false, userId);
+                grantRuntimePermissions(textClassifierPackage, PHONE_PERMISSIONS, true, userId);
+                grantRuntimePermissions(textClassifierPackage, SMS_PERMISSIONS, true, userId);
+                grantRuntimePermissions(textClassifierPackage, CALENDAR_PERMISSIONS, true, userId);
+                grantRuntimePermissions(textClassifierPackage, LOCATION_PERMISSIONS, true, userId);
+                grantRuntimePermissions(textClassifierPackage, CONTACTS_PERMISSIONS, true, userId);
             }
         }
 
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index 06559df..dd6d71e 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -141,8 +141,14 @@
         if (DEBUG) {
             Slog.d(TAG, "onBootCompleted");
         }
-        // This is called with the power manager lock held. Don't do any
+        // Just booted. We don't want LOW_POWER_MODE to be persisted, so just always clear it.
+        putGlobalSetting(Global.LOW_POWER_MODE, 0);
+
+        // This is called with the power manager lock held. Don't do anything that may call to
+        // upper services. (e.g. don't call into AM directly)
+        // So use a BG thread.
         runOnBgThread(() -> {
+
             final ContentResolver cr = mContext.getContentResolver();
             cr.registerContentObserver(Settings.Global.getUriFor(
                     Settings.Global.LOW_POWER_MODE),
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 2f174c2..d73606f 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -2003,8 +2003,11 @@
             case TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE: {
                 return "TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE";
             }
+            case TRANSIT_CRASHING_ACTIVITY_CLOSE: {
+                return "TRANSIT_CRASHING_ACTIVITY_CLOSE";
+            }
             default: {
-                return "<UNKNOWN>";
+                return "<UNKNOWN: " + transition + ">";
             }
         }
     }
@@ -2133,15 +2136,17 @@
                 + " " + this
                 + " alwaysKeepCurrent=" + alwaysKeepCurrent
                 + " Callers=" + Debug.getCallers(3));
+        final boolean allowSetCrashing = !isKeyguardTransit(mNextAppTransition)
+                && transit == TRANSIT_CRASHING_ACTIVITY_CLOSE;
         if (forceOverride || isKeyguardTransit(transit) || !isTransitionSet()
-                || mNextAppTransition == TRANSIT_NONE) {
+                || mNextAppTransition == TRANSIT_NONE || allowSetCrashing) {
             setAppTransition(transit, flags);
         }
         // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
         // relies on the fact that we always execute a Keyguard transition after preparing one. We
         // also don't want to change away from a crashing transition.
-        else if (!alwaysKeepCurrent && !isKeyguardTransit(transit)
-                && transit != TRANSIT_CRASHING_ACTIVITY_CLOSE) {
+        else if (!alwaysKeepCurrent && !isKeyguardTransit(mNextAppTransition)
+                && mNextAppTransition != TRANSIT_CRASHING_ACTIVITY_CLOSE) {
             if (transit == TRANSIT_TASK_OPEN && isTransitionEqual(TRANSIT_TASK_CLOSE)) {
                 // Opening a new task always supersedes a close for the anim.
                 setAppTransition(transit, flags);
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index 644e3c3..4f15c5d 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -753,6 +753,21 @@
         return mListener != null && mListener.keyDispatchingTimedOut(reason, windowPid);
     }
 
+    /**
+     * Notifies AWT that this app is waiting to pause in order to determine if it will enter PIP.
+     * This information helps AWT know that the app is in the process of pausing before it gets the
+     * signal on the WM side.
+     */
+    public void setWillCloseOrEnterPip(boolean willCloseOrEnterPip) {
+        synchronized (mWindowMap) {
+            if (mContainer == null) {
+                return;
+            }
+
+            mContainer.setWillCloseOrEnterPip(willCloseOrEnterPip);
+        }
+    }
+
     @Override
     public String toString() {
         return "AppWindowContainerController{"
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 0ba5a56..e45de45 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -32,12 +32,11 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 
-import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
 import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static android.view.WindowManager.TRANSIT_UNSET;
-import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
+
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
@@ -257,6 +256,13 @@
     private RemoteAnimationDefinition mRemoteAnimationDefinition;
     private AnimatingAppWindowTokenRegistry mAnimatingAppWindowTokenRegistry;
 
+    /**
+     * A flag to determine if this AWT is in the process of closing or entering PIP. This is needed
+     * to help AWT know that the app is in the process of closing but hasn't yet started closing on
+     * the WM side.
+     */
+    private boolean mWillCloseOrEnterPip;
+
     AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
             DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen,
             boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint,
@@ -2235,4 +2241,21 @@
     boolean isLetterboxOverlappingWith(Rect rect) {
         return mLetterbox != null && mLetterbox.isOverlappingWith(rect);
     }
+
+    /**
+     * Sets if this AWT is in the process of closing or entering PIP.
+     * {@link #mWillCloseOrEnterPip}}
+     */
+    void setWillCloseOrEnterPip(boolean willCloseOrEnterPip) {
+        mWillCloseOrEnterPip = willCloseOrEnterPip;
+    }
+
+    /**
+     * Returns whether this AWT is considered closing. Conditions are either
+     * 1. Is this app animating and was requested to be hidden
+     * 2. App is delayed closing since it might enter PIP.
+     */
+    boolean isClosingOrEnteringPip() {
+        return (isAnimating() && hiddenRequested) || mWillCloseOrEnterPip;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index b59e728..b0e6208 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2510,7 +2510,7 @@
         // since its above other stacks in the ordering list, but layed out below the others.
         if (curTarget != null && curTarget.isDisplayedLw() && curTarget.isClosing()
                 && (target == null || target.isActivityTypeHome())) {
-            if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "New target is home while current target is"
+            if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "New target is home while current target is "
                     + "closing, not changing");
             return curTarget;
         }
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index 7b775f5..c366e4d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -54,7 +54,7 @@
     static final boolean DEBUG_STARTING_WINDOW_VERBOSE = false;
     static final boolean DEBUG_STARTING_WINDOW = DEBUG_STARTING_WINDOW_VERBOSE || false;
     static final boolean DEBUG_WALLPAPER = false;
-    static final boolean DEBUG_WALLPAPER_LIGHT = true || DEBUG_WALLPAPER;
+    static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
     static final boolean DEBUG_DRAG = false;
     static final boolean DEBUG_SCREEN_ON = false;
     static final boolean DEBUG_SCREENSHOT = false;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index febc1a9..bee70a0 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -20,8 +20,6 @@
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.MODE_DEFAULT;
 import static android.app.AppOpsManager.OP_NONE;
-import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
-import static android.app.AppOpsManager.OP_TOAST_WINDOW;
 import static android.os.PowerManager.DRAW_WAKE_LOCK;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
@@ -2737,8 +2735,7 @@
     }
 
     boolean isClosing() {
-        return mAnimatingExit || (mAppToken != null && mAppToken.isAnimating()
-                && mAppToken.hiddenRequested);
+        return mAnimatingExit || (mAppToken != null && mAppToken.isClosingOrEnteringPip());
     }
 
     void addWinAnimatorToList(ArrayList<WindowStateAnimator> animators) {
diff --git a/services/net/java/android/net/util/NetworkConstants.java b/services/net/java/android/net/util/NetworkConstants.java
index 53fd01f..de04fd0 100644
--- a/services/net/java/android/net/util/NetworkConstants.java
+++ b/services/net/java/android/net/util/NetworkConstants.java
@@ -53,7 +53,7 @@
 
     public static final int ETHER_HEADER_LEN = 14;
 
-    private static final byte FF = asByte(0xff);
+    public static final byte FF = asByte(0xff);
     public static final byte[] ETHER_ADDR_BROADCAST = {
         FF, FF, FF, FF, FF, FF
     };
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
index 1ba1788..5ee1c40 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -131,7 +131,7 @@
         mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
 
         // The activity is in the focused stack so it should not move to paused.
-        mActivity.makeVisibleIfNeeded(null /* starting */);
+        mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
         assertTrue(mActivity.isState(STOPPED));
         assertFalse(pauseFound.value);
 
@@ -139,14 +139,14 @@
         mActivity.mStackSupervisor.mFocusedStack = null;
 
         // In the unfocused stack, the activity should move to paused.
-        mActivity.makeVisibleIfNeeded(null /* starting */);
+        mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
         assertTrue(mActivity.isState(PAUSING));
         assertTrue(pauseFound.value);
 
         // Make sure that the state does not change for current non-stopping states.
         mActivity.setState(INITIALIZING, "testPausingWhenVisibleFromStopped");
 
-        mActivity.makeVisibleIfNeeded(null /* starting */);
+        mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
 
         assertTrue(mActivity.isState(INITIALIZING));
 
@@ -156,7 +156,7 @@
         // Make sure that the state does not change when we have an activity becoming translucent
         final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
         mStack.mTranslucentActivityWaiting = topActivity;
-        mActivity.makeVisibleIfNeeded(null /* starting */);
+        mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
 
         assertTrue(mActivity.isState(STOPPED));
     }
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java
index 8e5aec3..be7d781 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
+import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
 import static org.junit.Assert.assertEquals;
@@ -35,7 +36,7 @@
 /**
  * Test class for {@link AppTransition}.
  *
- * runtest frameworks-services -c com.android.server.wm.AppTransitionTests
+ * atest AppTransitionTests
  */
 @SmallTest
 @Presubmit
@@ -60,10 +61,31 @@
     }
 
     @Test
+    public void testKeyguardKeep() throws Exception {
+        mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
+        mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
+        assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mWm.mAppTransition.getAppTransition());
+    }
+
+    @Test
     public void testForceOverride() throws Exception {
         mWm.prepareAppTransition(TRANSIT_KEYGUARD_UNOCCLUDE, false /* alwaysKeepCurrent */);
         mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */,
                 0 /* flags */, true /* forceOverride */);
         assertEquals(TRANSIT_ACTIVITY_OPEN, mWm.mAppTransition.getAppTransition());
     }
+
+    @Test
+    public void testCrashing() throws Exception {
+        mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
+        mWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
+        assertEquals(TRANSIT_CRASHING_ACTIVITY_CLOSE, mWm.mAppTransition.getAppTransition());
+    }
+
+    @Test
+    public void testKeepKeyguard_withCrashing() throws Exception {
+        mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
+        mWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
+        assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mWm.mAppTransition.getAppTransition());
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 41b4718..a408438 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -2919,6 +2919,29 @@
     }
 
     @Test
+    public void testVisualDifference_summary() {
+        Notification.Builder nb1 = new Notification.Builder(mContext, "")
+                .setGroup("bananas")
+                .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
+                .setContentText("foo");
+        StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
+                nb1.build(), new UserHandle(mUid), null, 0);
+        NotificationRecord r1 =
+                new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
+
+        Notification.Builder nb2 = new Notification.Builder(mContext, "")
+                .setGroup("bananas")
+                .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
+                .setContentText("bar");
+        StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
+                nb2.build(), new UserHandle(mUid), null, 0);
+        NotificationRecord r2 =
+                new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
+
+        assertFalse(mService.isVisuallyInterruptive(r1, r2));
+    }
+
+    @Test
     public void testHideAndUnhideNotificationsOnSuspendedPackageBroadcast() {
         // post 2 notification from this package
         final NotificationRecord notif1 = generateNotificationRecord(
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
index 975fbcc..9db823c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
@@ -39,11 +39,15 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Color;
+import android.graphics.Typeface;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Build;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.style.StyleSpan;
 import android.widget.RemoteViews;
 
 import com.android.server.UiServiceTestCase;
@@ -465,6 +469,25 @@
     }
 
     @Test
+    public void testActionsDifferentSpannables() {
+        PendingIntent intent = mock(PendingIntent.class);
+        Icon icon = mock(Icon.class);
+
+        Notification n1 = new Notification.Builder(mContext, "test")
+                .addAction(new Notification.Action.Builder(icon,
+                        new SpannableStringBuilder().append("test1",
+                                new StyleSpan(Typeface.BOLD),
+                                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE),
+                        intent).build())
+                .build();
+        Notification n2 = new Notification.Builder(mContext, "test")
+                .addAction(new Notification.Action.Builder(icon, "test1", intent).build())
+                .build();
+
+        assertFalse(Notification.areActionsVisiblyDifferent(n1, n2));
+    }
+
+    @Test
     public void testActionsDifferentNumber() {
         PendingIntent intent = mock(PendingIntent.class);
         Icon icon = mock(Icon.class);
@@ -497,29 +520,7 @@
     }
 
     @Test
-    public void testActionsMoreOptionsThanChoices() {
-        PendingIntent intent1 = mock(PendingIntent.class);
-        PendingIntent intent2 = mock(PendingIntent.class);
-        Icon icon = mock(Icon.class);
-
-        Notification n1 = new Notification.Builder(mContext, "test")
-                .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent1).build())
-                .addAction(new Notification.Action.Builder(icon, "TEXT 2", intent1)
-                        .addRemoteInput(new RemoteInput.Builder("a")
-                                .setChoices(new CharSequence[] {"i", "m"})
-                                .build())
-                        .build())
-                .build();
-        Notification n2 = new Notification.Builder(mContext, "test")
-                .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent2).build())
-                .addAction(new Notification.Action.Builder(icon, "TEXT 2", intent1).build())
-                .build();
-
-        assertTrue(Notification.areActionsVisiblyDifferent(n1, n2));
-    }
-
-    @Test
-    public void testActionsDifferentRemoteInputs() {
+    public void testActionsIgnoresRemoteInputs() {
         PendingIntent intent = mock(PendingIntent.class);
         Icon icon = mock(Icon.class);
 
@@ -538,7 +539,7 @@
                         .build())
                 .build();
 
-        assertTrue(Notification.areActionsVisiblyDifferent(n1, n2));
+        assertFalse(Notification.areActionsVisiblyDifferent(n1, n2));
     }
 }