Merge "Remove tests already covered by CTS." into qt-dev
diff --git a/api/test-current.txt b/api/test-current.txt
index 0de0d75..b1ffbad 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -3171,6 +3171,7 @@
 
   @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
     method public android.view.View getTooltipView();
+    method public boolean isAutofilled();
     method public static boolean isDefaultFocusHighlightEnabled();
     method public boolean isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
     method protected void resetResolvedDrawables();
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index 07ba2c6..038994f 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -590,6 +590,9 @@
         public @NonNull Builder setServiceSolicitationUuid(
                 @Nullable ParcelUuid serviceSolicitationUuid) {
             mServiceSolicitationUuid = serviceSolicitationUuid;
+            if (serviceSolicitationUuid == null) {
+                mServiceSolicitationUuidMask = null;
+            }
             return this;
         }
 
@@ -600,13 +603,16 @@
          * indicate a match is needed for the bit in {@code serviceSolicitationUuid}, and 0 to
          * ignore that bit.
          *
+         * @param serviceSolicitationUuid can only be null if solicitationUuidMask is null.
+         * @param solicitationUuidMask can be null or a mask with no restriction.
+         *
          * @throws IllegalArgumentException If {@code serviceSolicitationUuid} is {@code null} but
          *             {@code serviceSolicitationUuidMask} is not {@code null}.
          */
         public @NonNull Builder setServiceSolicitationUuid(
                 @Nullable ParcelUuid serviceSolicitationUuid,
                 @Nullable ParcelUuid solicitationUuidMask) {
-            if (mServiceSolicitationUuidMask != null && mServiceSolicitationUuid == null) {
+            if (solicitationUuidMask != null && serviceSolicitationUuid == null) {
                 throw new IllegalArgumentException(
                         "SolicitationUuid is null while SolicitationUuidMask is not null!");
             }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index a69ca99..3bc40a7 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -3612,8 +3612,9 @@
      * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
      *                        the callback must not be shared - it uniquely specifies this request.
      *                        The callback is invoked on the default internal Handler.
-     * @throws IllegalArgumentException if {@code request} specifies any mutable
-     *         {@code NetworkCapabilities}.
+     * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
+     * @throws SecurityException if missing the appropriate permissions.
+     * @throws RuntimeException if request limit per UID is exceeded.
      */
     public void requestNetwork(@NonNull NetworkRequest request,
             @NonNull NetworkCallback networkCallback) {
@@ -3648,8 +3649,9 @@
      * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
      *                        the callback must not be shared - it uniquely specifies this request.
      * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
-     * @throws IllegalArgumentException if {@code request} specifies any mutable
-     *         {@code NetworkCapabilities}.
+     * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
+     * @throws SecurityException if missing the appropriate permissions.
+     * @throws RuntimeException if request limit per UID is exceeded.
      */
     public void requestNetwork(@NonNull NetworkRequest request,
             @NonNull NetworkCallback networkCallback, @NonNull Handler handler) {
@@ -3685,6 +3687,9 @@
      * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
      *                  before {@link NetworkCallback#onUnavailable()} is called. The timeout must
      *                  be a positive value (i.e. >0).
+     * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
+     * @throws SecurityException if missing the appropriate permissions.
+     * @throws RuntimeException if request limit per UID is exceeded.
      */
     public void requestNetwork(@NonNull NetworkRequest request,
             @NonNull NetworkCallback networkCallback, int timeoutMs) {
@@ -3719,6 +3724,9 @@
      * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
      * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
      *                  before {@link NetworkCallback#onUnavailable} is called.
+     * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
+     * @throws SecurityException if missing the appropriate permissions.
+     * @throws RuntimeException if request limit per UID is exceeded.
      */
     public void requestNetwork(@NonNull NetworkRequest request,
             @NonNull NetworkCallback networkCallback, @NonNull Handler handler, int timeoutMs) {
@@ -3789,9 +3797,9 @@
      * @param operation Action to perform when the network is available (corresponds
      *                  to the {@link NetworkCallback#onAvailable} call.  Typically
      *                  comes from {@link PendingIntent#getBroadcast}. Cannot be null.
-     * @throws IllegalArgumentException if {@code request} contains either
-     *         {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or
-     *         {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}.
+     * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
+     * @throws SecurityException if missing the appropriate permissions.
+     * @throws RuntimeException if request limit per UID is exceeded.
      */
     public void requestNetwork(@NonNull NetworkRequest request,
             @NonNull PendingIntent operation) {
diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java
index 87f8739..fe42111 100644
--- a/core/java/android/net/StaticIpConfiguration.java
+++ b/core/java/android/net/StaticIpConfiguration.java
@@ -58,15 +58,15 @@
     @Nullable
     public LinkAddress ipAddress;
     /** @hide */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    @UnsupportedAppUsage
     @Nullable
     public InetAddress gateway;
     /** @hide */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    @UnsupportedAppUsage
     @NonNull
     public final ArrayList<InetAddress> dnsServers;
     /** @hide */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    @UnsupportedAppUsage
     @Nullable
     public String domains;
 
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index 87e369f..66c3e19 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -228,7 +228,7 @@
         } else {
             // TODO(b/123099468): figure out if it's ok to reuse the proxy; add logging
             if (sDebug) Log.d(TAG, "Reusing proxy for session " + sessionId);
-            proxy.update(focusedId, focusedValue, callback);
+            proxy.update(focusedId, focusedValue, callback, cancellationSignal);
         }
 
         try {
@@ -252,6 +252,15 @@
                     Log.w(TAG, "No proxy for session " + sessionId);
                     return;
                 }
+                if (proxy.mCallback != null) {
+                    try {
+                        if (!proxy.mCallback.isCompleted()) {
+                            proxy.mCallback.cancel();
+                        }
+                    } catch (Exception e) {
+                        Log.e(TAG, "failed to check current pending request status", e);
+                    }
+                }
                 proxy.destroy();
             }
             mAutofillProxies.clear();
@@ -442,7 +451,7 @@
         }
 
         private void update(@NonNull AutofillId focusedId, @NonNull AutofillValue focusedValue,
-                @NonNull IFillCallback callback) {
+                @NonNull IFillCallback callback, @NonNull CancellationSignal cancellationSignal) {
             synchronized (mLock) {
                 mFocusedId = focusedId;
                 mFocusedValue = focusedValue;
@@ -457,6 +466,7 @@
                     Log.d(TAG, "mCallback is updated.");
                 }
                 mCallback = callback;
+                mCancellationSignal = cancellationSignal;
             }
         }
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 779c75f..bf6191e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8852,6 +8852,7 @@
     /**
      * @hide
      */
+    @TestApi
     public boolean isAutofilled() {
         return (mPrivateFlags3 & PFLAG3_IS_AUTOFILLED) != 0;
     }
@@ -21508,23 +21509,27 @@
         }
 
         saveCount = canvas.getSaveCount();
+        int topSaveCount = -1;
+        int bottomSaveCount = -1;
+        int leftSaveCount = -1;
+        int rightSaveCount = -1;
 
         int solidColor = getSolidColor();
         if (solidColor == 0) {
             if (drawTop) {
-                canvas.saveUnclippedLayer(left, top, right, top + length);
+                topSaveCount = canvas.saveUnclippedLayer(left, top, right, top + length);
             }
 
             if (drawBottom) {
-                canvas.saveUnclippedLayer(left, bottom - length, right, bottom);
+                bottomSaveCount = canvas.saveUnclippedLayer(left, bottom - length, right, bottom);
             }
 
             if (drawLeft) {
-                canvas.saveUnclippedLayer(left, top, left + length, bottom);
+                leftSaveCount = canvas.saveUnclippedLayer(left, top, left + length, bottom);
             }
 
             if (drawRight) {
-                canvas.saveUnclippedLayer(right - length, top, right, bottom);
+                rightSaveCount = canvas.saveUnclippedLayer(right - length, top, right, bottom);
             }
         } else {
             scrollabilityCache.setFadeColor(solidColor);
@@ -21541,21 +21546,19 @@
         final Matrix matrix = scrollabilityCache.matrix;
         final Shader fade = scrollabilityCache.shader;
 
-        if (drawTop) {
-            matrix.setScale(1, fadeHeight * topFadeStrength);
-            matrix.postTranslate(left, top);
+        // must be restored in the reverse order that they were saved
+        if (drawRight) {
+            matrix.setScale(1, fadeHeight * rightFadeStrength);
+            matrix.postRotate(90);
+            matrix.postTranslate(right, top);
             fade.setLocalMatrix(matrix);
             p.setShader(fade);
-            canvas.drawRect(left, top, right, top + length, p);
-        }
+            if (solidColor == 0) {
+                canvas.restoreUnclippedLayer(rightSaveCount, p);
 
-        if (drawBottom) {
-            matrix.setScale(1, fadeHeight * bottomFadeStrength);
-            matrix.postRotate(180);
-            matrix.postTranslate(left, bottom);
-            fade.setLocalMatrix(matrix);
-            p.setShader(fade);
-            canvas.drawRect(left, bottom - length, right, bottom, p);
+            } else {
+                canvas.drawRect(right - length, top, right, bottom, p);
+            }
         }
 
         if (drawLeft) {
@@ -21564,16 +21567,36 @@
             matrix.postTranslate(left, top);
             fade.setLocalMatrix(matrix);
             p.setShader(fade);
-            canvas.drawRect(left, top, left + length, bottom, p);
+            if (solidColor == 0) {
+                canvas.restoreUnclippedLayer(leftSaveCount, p);
+            } else {
+                canvas.drawRect(left, top, left + length, bottom, p);
+            }
         }
 
-        if (drawRight) {
-            matrix.setScale(1, fadeHeight * rightFadeStrength);
-            matrix.postRotate(90);
-            matrix.postTranslate(right, top);
+        if (drawBottom) {
+            matrix.setScale(1, fadeHeight * bottomFadeStrength);
+            matrix.postRotate(180);
+            matrix.postTranslate(left, bottom);
             fade.setLocalMatrix(matrix);
             p.setShader(fade);
-            canvas.drawRect(right - length, top, right, bottom, p);
+            if (solidColor == 0) {
+                canvas.restoreUnclippedLayer(bottomSaveCount, p);
+            } else {
+                canvas.drawRect(left, bottom - length, right, bottom, p);
+            }
+        }
+
+        if (drawTop) {
+            matrix.setScale(1, fadeHeight * topFadeStrength);
+            matrix.postTranslate(left, top);
+            fade.setLocalMatrix(matrix);
+            p.setShader(fade);
+            if (solidColor == 0) {
+                canvas.restoreUnclippedLayer(topSaveCount, p);
+            } else {
+                canvas.drawRect(left, top, right, top + length, p);
+            }
         }
 
         canvas.restoreToCount(saveCount);
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index c36b894..1f7ae0e 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1204,10 +1204,6 @@
         AutofillValue value = null;
 
         synchronized (mLock) {
-            if (mForAugmentedAutofillOnly) {
-                if (sVerbose) Log.v(TAG,  "notifyValueChanged(): ignoring on augmented only mode");
-                return;
-            }
             // If the session is gone some fields might still be highlighted, hence we have to
             // remove the isAutofilled property even if no sessions are active.
             if (mLastAutofilledData == null) {
@@ -1229,6 +1225,13 @@
                 }
             }
 
+            if (mForAugmentedAutofillOnly) {
+                if (sVerbose) {
+                    Log.v(TAG,  "notifyValueChanged(): not notifying system server on "
+                            + "augmented-only mode");
+                }
+                return;
+            }
             if (!mEnabled || !isActiveLocked()) {
                 if (sVerbose) {
                     Log.v(TAG, "notifyValueChanged(" + view.getAutofillId()
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 4d5c9ad..a88c51a 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -237,7 +237,6 @@
 
     private boolean mListViewDataChanged = false;
 
-
     @Retention(SOURCE)
     @IntDef({CONTENT_PREVIEW_FILE, CONTENT_PREVIEW_IMAGE, CONTENT_PREVIEW_TEXT})
     private @interface ContentPreviewType {
@@ -2036,7 +2035,8 @@
             return;
         }
 
-        if (mChooserRowAdapter.calculateChooserTargetWidth(right - left)
+        int availableWidth = right - left - v.getPaddingLeft() - v.getPaddingRight();
+        if (mChooserRowAdapter.calculateChooserTargetWidth(availableWidth)
                 || mAdapterView.getAdapter() == null) {
             mAdapterView.setAdapter(mChooserRowAdapter);
 
@@ -2045,7 +2045,9 @@
                     return;
                 }
 
-                int offset = 0;
+                final int bottomInset = mSystemWindowInsets != null
+                                            ? mSystemWindowInsets.bottom : 0;
+                int offset = bottomInset;
                 int rowsToShow = mChooserRowAdapter.getContentPreviewRowCount()
                         + mChooserRowAdapter.getProfileRowCount()
                         + mChooserRowAdapter.getServiceTargetRowCount()
@@ -2060,7 +2062,7 @@
                 // still zero? then use a default height and leave, which
                 // can happen when there are no targets to show
                 if (rowsToShow == 0) {
-                    offset = getResources().getDimensionPixelSize(
+                    offset += getResources().getDimensionPixelSize(
                             R.dimen.chooser_max_collapsed_height);
                     mResolverDrawerLayout.setCollapsibleHeightReserved(offset);
                     return;
@@ -2085,8 +2087,9 @@
                     // make sure to leave room for direct share 4->8 expansion
                     int requiredExpansionHeight =
                             (int) (directShareHeight / DIRECT_SHARE_EXPANSION_RATE);
+                    int topInset = mSystemWindowInsets != null ? mSystemWindowInsets.top : 0;
                     int minHeight = bottom - top - mResolverDrawerLayout.getAlwaysShowHeight()
-                                        - requiredExpansionHeight;
+                                        - requiredExpansionHeight - topInset - bottomInset;
 
                     offset = Math.min(offset, minHeight);
                 }
@@ -2656,7 +2659,7 @@
         @Override
         public boolean isEnabled(int position) {
             int viewType = getItemViewType(position);
-            if (viewType == VIEW_TYPE_CONTENT_PREVIEW) {
+            if (viewType == VIEW_TYPE_CONTENT_PREVIEW || viewType == VIEW_TYPE_AZ_LABEL) {
                 return false;
             }
             return true;
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 3ea746d..a5daa0a 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -46,6 +46,7 @@
 import android.graphics.Bitmap;
 import android.graphics.ColorMatrix;
 import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Insets;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
@@ -67,12 +68,15 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.view.WindowInsets;
 import android.widget.AbsListView;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.ListView;
+import android.widget.Space;
 import android.widget.TextView;
 import android.widget.Toast;
 
@@ -136,6 +140,9 @@
 
     private ColorMatrixColorFilter mSuspendedMatrixColorFilter;
 
+    protected Insets mSystemWindowInsets = null;
+    private Space mFooterSpacer = null;
+
     /** See {@link #setRetainInOnStop}. */
     private boolean mRetainInOnStop;
 
@@ -329,6 +336,11 @@
             if (isVoiceInteraction()) {
                 rdl.setCollapsed(false);
             }
+
+            rdl.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+            rdl.setOnApplyWindowInsetsListener(this::onApplyWindowInsets);
+
             mResolverDrawerLayout = rdl;
         }
 
@@ -364,10 +376,38 @@
         finish();
     }
 
+    protected WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
+        mSystemWindowInsets = insets.getSystemWindowInsets();
+
+        mResolverDrawerLayout.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top,
+                mSystemWindowInsets.right, 0);
+
+        View emptyView = findViewById(R.id.empty);
+        emptyView.setPadding(0, 0, 0, mSystemWindowInsets.bottom
+                + getResources().getDimensionPixelSize(
+                        R.dimen.chooser_edge_margin_normal) * 2);
+
+        if (mFooterSpacer == null) {
+            mFooterSpacer = new Space(getApplicationContext());
+        } else {
+            ((ListView) mAdapterView).removeFooterView(mFooterSpacer);
+        }
+        mFooterSpacer.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT,
+                mSystemWindowInsets.bottom));
+        ((ListView) mAdapterView).addFooterView(mFooterSpacer);
+
+        return insets.consumeSystemWindowInsets();
+    }
+
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         mAdapter.handlePackagesChanged();
+
+        if (mSystemWindowInsets != null) {
+            mResolverDrawerLayout.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top,
+                    mSystemWindowInsets.right, 0);
+        }
     }
 
     private void initSuspendedColorMatrix() {
@@ -1277,6 +1317,10 @@
         final ViewGroup buttonLayout = findViewById(R.id.button_bar);
         if (buttonLayout != null) {
             buttonLayout.setVisibility(View.VISIBLE);
+            int inset = mSystemWindowInsets != null ? mSystemWindowInsets.bottom : 0;
+            buttonLayout.setPadding(buttonLayout.getPaddingLeft(), buttonLayout.getPaddingTop(),
+                    buttonLayout.getPaddingRight(), buttonLayout.getPaddingBottom() + inset);
+
             mOnceButton = (Button) buttonLayout.findViewById(R.id.button_once);
             mSettingsButton = (Button) buttonLayout.findViewById(R.id.button_app_settings);
             mAlwaysButton = (Button) buttonLayout.findViewById(R.id.button_always);
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index 3adb36f..c73de8f 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -854,12 +854,11 @@
 
         final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
         final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY);
-        final int widthPadding = getPaddingLeft() + getPaddingRight();
 
         // Currently we allot more height than is really needed so that the entirety of the
         // sheet may be pulled up.
         // TODO: Restrict the height here to be the right value.
-        int heightUsed = getPaddingTop() + getPaddingBottom();
+        int heightUsed = 0;
 
         // Measure always-show children first.
         final int childCount = getChildCount();
@@ -869,11 +868,11 @@
             if (lp.alwaysShow && child.getVisibility() != GONE) {
                 if (lp.maxHeight != -1) {
                     final int remainingHeight = heightSize - heightUsed;
-                    measureChildWithMargins(child, widthSpec, widthPadding,
+                    measureChildWithMargins(child, widthSpec, 0,
                             MeasureSpec.makeMeasureSpec(lp.maxHeight, MeasureSpec.AT_MOST),
                             lp.maxHeight > remainingHeight ? lp.maxHeight - remainingHeight : 0);
                 } else {
-                    measureChildWithMargins(child, widthSpec, widthPadding, heightSpec, heightUsed);
+                    measureChildWithMargins(child, widthSpec, 0, heightSpec, heightUsed);
                 }
                 heightUsed += child.getMeasuredHeight();
             }
@@ -889,11 +888,11 @@
             if (!lp.alwaysShow && child.getVisibility() != GONE) {
                 if (lp.maxHeight != -1) {
                     final int remainingHeight = heightSize - heightUsed;
-                    measureChildWithMargins(child, widthSpec, widthPadding,
+                    measureChildWithMargins(child, widthSpec, 0,
                             MeasureSpec.makeMeasureSpec(lp.maxHeight, MeasureSpec.AT_MOST),
                             lp.maxHeight > remainingHeight ? lp.maxHeight - remainingHeight : 0);
                 } else {
-                    measureChildWithMargins(child, widthSpec, widthPadding, heightSpec, heightUsed);
+                    measureChildWithMargins(child, widthSpec, 0, heightSpec, heightUsed);
                 }
                 heightUsed += child.getMeasuredHeight();
             }
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 7a8c5c8..ebc6cd7 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -106,6 +106,11 @@
     return reinterpret_cast<jint>(get_canvas(canvasHandle)->saveUnclippedLayer(l, t, r, b));
 }
 
+static void restoreUnclippedLayer(jlong canvasHandle, jint saveCount, jlong paintHandle) {
+    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+    get_canvas(canvasHandle)->restoreUnclippedLayer(saveCount, *paint);
+}
+
 static bool restore(jlong canvasHandle) {
     Canvas* canvas = get_canvas(canvasHandle);
     if (canvas->getSaveCount() <= 1) {
@@ -668,6 +673,7 @@
     {"nSaveLayer","(JFFFFJI)I", (void*) CanvasJNI::saveLayer},
     {"nSaveLayerAlpha","(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha},
     {"nSaveUnclippedLayer","(JIIII)I", (void*) CanvasJNI::saveUnclippedLayer},
+    {"nRestoreUnclippedLayer","(JIJ)V", (void*) CanvasJNI::restoreUnclippedLayer},
     {"nGetSaveCount","(J)I", (void*) CanvasJNI::getSaveCount},
     {"nRestore","(J)Z", (void*) CanvasJNI::restore},
     {"nRestoreToCount","(JI)V", (void*) CanvasJNI::restoreToCount},
diff --git a/core/res/res/values-night/themes_device_defaults.xml b/core/res/res/values-night/themes_device_defaults.xml
index f595046..8ba2c60 100644
--- a/core/res/res/values-night/themes_device_defaults.xml
+++ b/core/res/res/values-night/themes_device_defaults.xml
@@ -88,5 +88,4 @@
     <style name="Theme.DeviceDefault.Resolver" parent="Theme.DeviceDefault.ResolverCommon">
         <item name="windowLightNavigationBar">false</item>
     </style>
-
 </resources>
diff --git a/core/res/res/values/colors_device_defaults.xml b/core/res/res/values/colors_device_defaults.xml
index 6225896..7a8f411 100644
--- a/core/res/res/values/colors_device_defaults.xml
+++ b/core/res/res/values/colors_device_defaults.xml
@@ -50,9 +50,10 @@
     <color name="list_divider_color_dark">#85ffffff</color>
     <color name="list_divider_opacity_device_default_light">@android:color/white</color>
     <color name="list_divider_opacity_device_default_dark">@android:color/white</color>
-    <color name="loading_gradient_background_color_dark">#2D3033</color>
-    <color name="loading_gradient_background_color_light">#DADCE0</color>
-    <color name="loading_gradient_highlight_color_dark">#3C4043</color>
+
+    <color name="loading_gradient_background_color_dark">#44484C</color>
+    <color name="loading_gradient_background_color_light">#F8F9FA</color>
+    <color name="loading_gradient_highlight_color_dark">#4D5155</color>
     <color name="loading_gradient_highlight_color_light">#F1F3F4</color>
 
     <color name="edge_effect_device_default_light">@android:color/black</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0daebd7..2de5397 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3457,7 +3457,7 @@
 
     <!-- Flag indicating whether the assist disclosure can be disabled using
          ASSIST_DISCLOSURE_ENABLED. -->
-    <bool name="config_allowDisablingAssistDisclosure">false</bool>
+    <bool name="config_allowDisablingAssistDisclosure">true</bool>
 
     <!-- True if the device supports system navigation keys. -->
     <bool name="config_supportSystemNavigationKeys">false</bool>
diff --git a/core/res/res/values/locale_config.xml b/core/res/res/values/locale_config.xml
index d6c0a10..3c65caf 100644
--- a/core/res/res/values/locale_config.xml
+++ b/core/res/res/values/locale_config.xml
@@ -78,6 +78,7 @@
         <item>ar-YE</item> <!-- Arabic (Yemen) -->
         <item>ar-YE-u-nu-latn</item> <!-- Arabic (Yemen, Western Digits) -->
         <item>as-IN</item> <!-- Assamese (India) -->
+        <item>as-IN-u-nu-latn</item> <!-- Assamese (India, Western Digits) -->
         <item>asa-TZ</item> <!-- Asu (Tanzania) -->
         <item>ast-ES</item> <!-- Asturian (Spain) -->
         <item>az-Cyrl-AZ</item> <!-- Azerbaijani (Cyrillic, Azerbaijan) -->
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index f4ebbad..6289262 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -1678,8 +1678,11 @@
         <item name="colorControlActivated">?attr/colorControlHighlight</item>
         <item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item>
         <item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item>
-        <item name="navigationBarColor">?attr/colorBackgroundFloating</item>
-        <item name="navigationBarDividerColor">@color/chooser_row_divider</item>
+        <item name="navigationBarColor">@android:color/transparent</item>
+    </style>
+
+    <style name="Theme.DeviceDefault.Resolver" parent="Theme.DeviceDefault.ResolverCommon">
+        <item name="windowLightNavigationBar">true</item>
     </style>
 
     <style name="Animation.DeviceDefault.Activity.Resolver" parent="Animation.DeviceDefault.Activity">
@@ -1690,10 +1693,6 @@
         <item name="taskOpenExitAnimation">@anim/resolver_close_anim</item>
     </style>
 
-    <style name="Theme.DeviceDefault.Resolver" parent="Theme.DeviceDefault.ResolverCommon">
-        <item name="windowLightNavigationBar">true</item>
-    </style>
-
     <!-- @hide DeviceDefault themes for the autofill FillUi -->
     <style name="Theme.DeviceDefault.Autofill" />
     <style name="Theme.DeviceDefault.Light.Autofill" />
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index d4d5ae7..5648b85 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -559,6 +559,16 @@
     }
 
     /**
+     * @hide
+     * @param saveCount The save level to restore to.
+     * @param paint     This is copied and is applied to the area within the unclipped layer's
+     *                  bounds (i.e. equivalent to a drawPaint()) before restore() is called.
+     */
+    public void restoreUnclippedLayer(int saveCount, Paint paint) {
+        nRestoreUnclippedLayer(mNativeCanvasWrapper, saveCount, paint.getNativeInstance());
+    }
+
+    /**
      * Helper version of saveLayer() that takes 4 values rather than a RectF.
      *
      * As of API Level API level {@value Build.VERSION_CODES#P} the only valid
@@ -1398,6 +1408,9 @@
     @CriticalNative
     private static native int nSaveUnclippedLayer(long nativeCanvas, int l, int t, int r, int b);
     @CriticalNative
+    private static native void nRestoreUnclippedLayer(long nativeCanvas, int saveCount,
+            long nativePaint);
+    @CriticalNative
     private static native boolean nRestore(long canvasHandle);
     @CriticalNative
     private static native void nRestoreToCount(long canvasHandle, int saveCount);
diff --git a/libs/hwui/DisplayListOps.in b/libs/hwui/DisplayListOps.in
index 14e3a32..2deb565 100644
--- a/libs/hwui/DisplayListOps.in
+++ b/libs/hwui/DisplayListOps.in
@@ -26,7 +26,8 @@
 X(ClipRect) 
 X(ClipRRect) 
 X(ClipRegion)
-X(DrawPaint) 
+X(DrawPaint)
+X(DrawBehind)
 X(DrawPath) 
 X(DrawRect) 
 X(DrawRegion) 
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 8594766..e58fbbe 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -20,6 +20,7 @@
 
 #include "SkAndroidFrameworkUtils.h"
 #include "SkCanvas.h"
+#include "SkCanvasPriv.h"
 #include "SkData.h"
 #include "SkDrawShadowInfo.h"
 #include "SkImage.h"
@@ -187,6 +188,12 @@
     SkPaint paint;
     void draw(SkCanvas* c, const SkMatrix&) const { c->drawPaint(paint); }
 };
+struct DrawBehind final : Op {
+    static const auto kType = Type::DrawBehind;
+    DrawBehind(const SkPaint& paint) : paint(paint) {}
+    SkPaint paint;
+    void draw(SkCanvas* c, const SkMatrix&) const { SkCanvasPriv::DrawBehind(c, paint); }
+};
 struct DrawPath final : Op {
     static const auto kType = Type::DrawPath;
     DrawPath(const SkPath& path, const SkPaint& paint) : path(path), paint(paint) {}
@@ -565,6 +572,9 @@
 void DisplayListData::drawPaint(const SkPaint& paint) {
     this->push<DrawPaint>(0, paint);
 }
+void DisplayListData::drawBehind(const SkPaint& paint) {
+    this->push<DrawBehind>(0, paint);
+}
 void DisplayListData::drawPath(const SkPath& path, const SkPaint& paint) {
     this->push<DrawPath>(0, path, paint);
 }
@@ -834,6 +844,9 @@
 void RecordingCanvas::onDrawPaint(const SkPaint& paint) {
     fDL->drawPaint(paint);
 }
+void RecordingCanvas::onDrawBehind(const SkPaint& paint) {
+    fDL->drawBehind(paint);
+}
 void RecordingCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
     fDL->drawPath(path, paint);
 }
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 3a76ca1..7269bca 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -89,6 +89,7 @@
     void clipRegion(const SkRegion&, SkClipOp);
 
     void drawPaint(const SkPaint&);
+    void drawBehind(const SkPaint&);
     void drawPath(const SkPath&, const SkPaint&);
     void drawRect(const SkRect&, const SkPaint&);
     void drawRegion(const SkRegion&, const SkPaint&);
@@ -157,6 +158,7 @@
     void onClipRegion(const SkRegion&, SkClipOp) override;
 
     void onDrawPaint(const SkPaint&) override;
+    void onDrawBehind(const SkPaint&) override;
     void onDrawPath(const SkPath&, const SkPaint&) override;
     void onDrawRect(const SkRect&, const SkPaint&) override;
     void onDrawRegion(const SkRegion&, const SkPaint&) override;
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index f328a53..bebda85 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -26,6 +26,7 @@
 
 #include <SkAndroidFrameworkUtils.h>
 #include <SkAnimatedImage.h>
+#include <SkCanvasPriv.h>
 #include <SkCanvasStateUtils.h>
 #include <SkColorFilter.h>
 #include <SkDeque.h>
@@ -191,6 +192,18 @@
     return SkAndroidFrameworkUtils::SaveBehind(mCanvas, &bounds);
 }
 
+void SkiaCanvas::restoreUnclippedLayer(int restoreCount, const SkPaint& paint) {
+
+    while (mCanvas->getSaveCount() > restoreCount + 1) {
+        this->restore();
+    }
+
+    if (mCanvas->getSaveCount() == restoreCount + 1) {
+        SkCanvasPriv::DrawBehind(mCanvas, *filterPaint(paint));
+        this->restore();
+    }
+}
+
 class SkiaCanvas::Clip {
 public:
     Clip(const SkRect& rect, SkClipOp op, const SkMatrix& m)
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 3fe2bce..bbe91eb 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -69,6 +69,7 @@
     virtual int save(SaveFlags::Flags flags) override;
     virtual void restore() override;
     virtual void restoreToCount(int saveCount) override;
+    virtual void restoreUnclippedLayer(int saveCount, const SkPaint& paint) override;
 
     virtual int saveLayer(float left, float top, float right, float bottom, const SkPaint* paint,
                           SaveFlags::Flags flags) override;
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 11e8579..ac8db21 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -191,6 +191,7 @@
     virtual int save(SaveFlags::Flags flags) = 0;
     virtual void restore() = 0;
     virtual void restoreToCount(int saveCount) = 0;
+    virtual void restoreUnclippedLayer(int saveCount, const SkPaint& paint) = 0;
 
     virtual int saveLayer(float left, float top, float right, float bottom, const SkPaint* paint,
                           SaveFlags::Flags flags) = 0;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index ccc1701..1f9ab5a 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -176,7 +176,7 @@
             // position
             Matrix4 windowTransform;
             damageAccumulator.computeCurrentTransform(&windowTransform);
-            node->getSkiaLayer()->inverseTransformInWindow = windowTransform;
+            node->getSkiaLayer()->inverseTransformInWindow.loadInverse(windowTransform);
         } else {
             String8 cachesOutput;
             mRenderThread.cacheManager().dumpMemoryUsage(cachesOutput,
diff --git a/packages/CtsShim/apk/arm/CtsShim.apk b/packages/CtsShim/apk/arm/CtsShim.apk
index a911603..7d9f8e3 100644
--- a/packages/CtsShim/apk/arm/CtsShim.apk
+++ b/packages/CtsShim/apk/arm/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/arm/CtsShimPriv.apk b/packages/CtsShim/apk/arm/CtsShimPriv.apk
index 845d781..dcccada 100644
--- a/packages/CtsShim/apk/arm/CtsShimPriv.apk
+++ b/packages/CtsShim/apk/arm/CtsShimPriv.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShim.apk b/packages/CtsShim/apk/x86/CtsShim.apk
index a911603..7d9f8e3 100644
--- a/packages/CtsShim/apk/x86/CtsShim.apk
+++ b/packages/CtsShim/apk/x86/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShimPriv.apk b/packages/CtsShim/apk/x86/CtsShimPriv.apk
index 2fc9a94..3501fa4 100644
--- a/packages/CtsShim/apk/x86/CtsShimPriv.apk
+++ b/packages/CtsShim/apk/x86/CtsShimPriv.apk
Binary files differ
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index aefa882..c013b8c 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -42,8 +42,8 @@
     static_libs: [
         "androidx.annotation_annotation",
         "ipmemorystore-client",
-        "netd_aidl_interface-java",
-        "networkstack-aidl-interfaces-java",
+        "netd_aidl_interface-V2-java",
+        "networkstack-aidl-interfaces-V3-java",
         "datastallprotosnano",
         "networkstackprotosnano",
         "captiveportal-lib",
diff --git a/packages/NetworkStack/src/com/android/server/NetworkStackService.java b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
index c394d4c..2fae0c7 100644
--- a/packages/NetworkStack/src/com/android/server/NetworkStackService.java
+++ b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
@@ -49,6 +49,7 @@
 import android.net.util.SharedLog;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.util.ArraySet;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
@@ -62,7 +63,6 @@
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Iterator;
-import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Android service used to start the network stack when bound to via an intent.
@@ -118,14 +118,12 @@
         @GuardedBy("mValidationLogs")
         private final ArrayDeque<SharedLog> mValidationLogs = new ArrayDeque<>(MAX_VALIDATION_LOGS);
 
-        private static final int VERSION_UNKNOWN = 0;
         private static final String DUMPSYS_ARG_VERSION = "version";
 
-        /** Version of the AIDL interfaces observed on the system */
-        private final AtomicInteger mSystemAidlVersion = new AtomicInteger(VERSION_UNKNOWN);
-
-        /** Whether different versions have been observed on interfaces provided by the system */
-        private volatile boolean mConflictingSystemAidlVersions = false;
+        /** Version of the framework AIDL interfaces observed. Should hold only one value. */
+        @GuardedBy("mFrameworkAidlVersions")
+        private final ArraySet<Integer> mFrameworkAidlVersions = new ArraySet<>(1);
+        private final int mNetdAidlVersion;
 
         private SharedLog addValidationLogs(Network network, String name) {
             final SharedLog log = new SharedLog(NUM_VALIDATION_LOG_LINES, network + " - " + name);
@@ -146,6 +144,15 @@
             mCm = context.getSystemService(ConnectivityManager.class);
             mIpMemoryStoreService = new IpMemoryStoreService(context);
 
+            int netdVersion;
+            try {
+                netdVersion = mNetd.getInterfaceVersion();
+            } catch (RemoteException e) {
+                mLog.e("Error obtaining INetd version", e);
+                netdVersion = -1;
+            }
+            mNetdAidlVersion = netdVersion;
+
             try {
                 mObserverRegistry.register(mNetd);
             } catch (RemoteException e) {
@@ -154,9 +161,8 @@
         }
 
         private void updateSystemAidlVersion(final int version) {
-            final int previousVersion = mSystemAidlVersion.getAndSet(version);
-            if (previousVersion != VERSION_UNKNOWN && previousVersion != version) {
-                mConflictingSystemAidlVersions = true;
+            synchronized (mFrameworkAidlVersions) {
+                mFrameworkAidlVersions.add(version);
             }
         }
 
@@ -230,12 +236,16 @@
         protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
                 @Nullable String[] args) {
             checkDumpPermission();
+
+            final IndentingPrintWriter pw = new IndentingPrintWriter(fout, "  ");
+            pw.println("NetworkStack version:");
+            dumpVersion(pw);
+            pw.println();
+
             if (args != null && args.length >= 1 && DUMPSYS_ARG_VERSION.equals(args[0])) {
-                dumpVersion(fout);
                 return;
             }
 
-            final IndentingPrintWriter pw = new IndentingPrintWriter(fout, "  ");
             pw.println("NetworkStack logs:");
             mLog.dump(fd, pw, args);
 
@@ -283,8 +293,10 @@
          */
         private void dumpVersion(@NonNull PrintWriter fout) {
             fout.println("NetworkStackConnector: " + this.VERSION);
-            fout.println("SystemServer: " + mSystemAidlVersion);
-            fout.println("SystemServerConflicts: " + mConflictingSystemAidlVersions);
+            synchronized (mFrameworkAidlVersions) {
+                fout.println("SystemServer: " + mFrameworkAidlVersions);
+            }
+            fout.println("Netd: " + mNetdAidlVersion);
         }
 
         @Override
diff --git a/packages/NetworkStack/tests/Android.bp b/packages/NetworkStack/tests/unit/Android.bp
similarity index 96%
rename from packages/NetworkStack/tests/Android.bp
rename to packages/NetworkStack/tests/unit/Android.bp
index 039f6bf..6cc8054 100644
--- a/packages/NetworkStack/tests/Android.bp
+++ b/packages/NetworkStack/tests/unit/Android.bp
@@ -72,7 +72,7 @@
         "libutilscallstack",
         "libziparchive",
         "libz",
-        "netd_aidl_interface-cpp",
+        "netd_aidl_interface-V2-cpp",
     ],
 }
 
@@ -94,7 +94,7 @@
         "liblog",
         "libcutils",
         "libnativehelper",
-        "netd_aidl_interface-cpp",
+        "netd_aidl_interface-V2-cpp",
     ],
     static_libs: [
         "libapf",
diff --git a/packages/NetworkStack/tests/AndroidManifest.xml b/packages/NetworkStack/tests/unit/AndroidManifest.xml
similarity index 100%
rename from packages/NetworkStack/tests/AndroidManifest.xml
rename to packages/NetworkStack/tests/unit/AndroidManifest.xml
diff --git a/packages/NetworkStack/tests/AndroidTest.xml b/packages/NetworkStack/tests/unit/AndroidTest.xml
similarity index 100%
rename from packages/NetworkStack/tests/AndroidTest.xml
rename to packages/NetworkStack/tests/unit/AndroidTest.xml
diff --git a/packages/NetworkStack/tests/jni/apf_jni.cpp b/packages/NetworkStack/tests/unit/jni/apf_jni.cpp
similarity index 100%
rename from packages/NetworkStack/tests/jni/apf_jni.cpp
rename to packages/NetworkStack/tests/unit/jni/apf_jni.cpp
diff --git a/packages/NetworkStack/tests/res/raw/apf.pcap b/packages/NetworkStack/tests/unit/res/raw/apf.pcap
similarity index 100%
rename from packages/NetworkStack/tests/res/raw/apf.pcap
rename to packages/NetworkStack/tests/unit/res/raw/apf.pcap
Binary files differ
diff --git a/packages/NetworkStack/tests/res/raw/apfPcap.pcap b/packages/NetworkStack/tests/unit/res/raw/apfPcap.pcap
similarity index 100%
rename from packages/NetworkStack/tests/res/raw/apfPcap.pcap
rename to packages/NetworkStack/tests/unit/res/raw/apfPcap.pcap
Binary files differ
diff --git a/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java b/packages/NetworkStack/tests/unit/src/android/net/apf/ApfTest.java
similarity index 100%
rename from packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
rename to packages/NetworkStack/tests/unit/src/android/net/apf/ApfTest.java
diff --git a/packages/NetworkStack/tests/src/android/net/apf/Bpf2Apf.java b/packages/NetworkStack/tests/unit/src/android/net/apf/Bpf2Apf.java
similarity index 100%
rename from packages/NetworkStack/tests/src/android/net/apf/Bpf2Apf.java
rename to packages/NetworkStack/tests/unit/src/android/net/apf/Bpf2Apf.java
diff --git a/packages/NetworkStack/tests/src/android/net/captiveportal/CaptivePortalProbeSpecTest.java b/packages/NetworkStack/tests/unit/src/android/net/captiveportal/CaptivePortalProbeSpecTest.java
similarity index 100%
rename from packages/NetworkStack/tests/src/android/net/captiveportal/CaptivePortalProbeSpecTest.java
rename to packages/NetworkStack/tests/unit/src/android/net/captiveportal/CaptivePortalProbeSpecTest.java
diff --git a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java b/packages/NetworkStack/tests/unit/src/android/net/dhcp/DhcpLeaseRepositoryTest.java
similarity index 100%
rename from packages/NetworkStack/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java
rename to packages/NetworkStack/tests/unit/src/android/net/dhcp/DhcpLeaseRepositoryTest.java
diff --git a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java b/packages/NetworkStack/tests/unit/src/android/net/dhcp/DhcpPacketTest.java
similarity index 100%
rename from packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java
rename to packages/NetworkStack/tests/unit/src/android/net/dhcp/DhcpPacketTest.java
diff --git a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServerTest.java b/packages/NetworkStack/tests/unit/src/android/net/dhcp/DhcpServerTest.java
similarity index 100%
rename from packages/NetworkStack/tests/src/android/net/dhcp/DhcpServerTest.java
rename to packages/NetworkStack/tests/unit/src/android/net/dhcp/DhcpServerTest.java
diff --git a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServingParamsTest.java b/packages/NetworkStack/tests/unit/src/android/net/dhcp/DhcpServingParamsTest.java
similarity index 100%
rename from packages/NetworkStack/tests/src/android/net/dhcp/DhcpServingParamsTest.java
rename to packages/NetworkStack/tests/unit/src/android/net/dhcp/DhcpServingParamsTest.java
diff --git a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java b/packages/NetworkStack/tests/unit/src/android/net/ip/IpClientTest.java
similarity index 100%
rename from packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
rename to packages/NetworkStack/tests/unit/src/android/net/ip/IpClientTest.java
diff --git a/packages/NetworkStack/tests/src/android/net/ip/IpReachabilityMonitorTest.java b/packages/NetworkStack/tests/unit/src/android/net/ip/IpReachabilityMonitorTest.java
similarity index 100%
rename from packages/NetworkStack/tests/src/android/net/ip/IpReachabilityMonitorTest.java
rename to packages/NetworkStack/tests/unit/src/android/net/ip/IpReachabilityMonitorTest.java
diff --git a/packages/NetworkStack/tests/src/android/net/util/ConnectivityPacketSummaryTest.java b/packages/NetworkStack/tests/unit/src/android/net/util/ConnectivityPacketSummaryTest.java
similarity index 100%
rename from packages/NetworkStack/tests/src/android/net/util/ConnectivityPacketSummaryTest.java
rename to packages/NetworkStack/tests/unit/src/android/net/util/ConnectivityPacketSummaryTest.java
diff --git a/packages/NetworkStack/tests/src/android/net/util/PacketReaderTest.java b/packages/NetworkStack/tests/unit/src/android/net/util/PacketReaderTest.java
similarity index 100%
rename from packages/NetworkStack/tests/src/android/net/util/PacketReaderTest.java
rename to packages/NetworkStack/tests/unit/src/android/net/util/PacketReaderTest.java
diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
similarity index 99%
rename from packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
rename to packages/NetworkStack/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
index 2618675..832b712 100644
--- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/packages/NetworkStack/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -297,6 +297,7 @@
         setOtherFallbackUrls(TEST_OTHER_FALLBACK_URL);
         setFallbackSpecs(null); // Test with no fallback spec by default
         when(mRandom.nextInt()).thenReturn(0);
+
         // DNS probe timeout should not be defined more than half of HANDLER_TIMEOUT_MS. Otherwise,
         // it will fail the test because of timeout expired for querying AAAA and A sequentially.
         when(mResources.getInteger(eq(R.integer.config_captive_portal_dns_probe_timeout)))
diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java b/packages/NetworkStack/tests/unit/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
similarity index 100%
rename from packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
rename to packages/NetworkStack/tests/unit/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java b/packages/NetworkStack/tests/unit/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java
similarity index 100%
rename from packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java
rename to packages/NetworkStack/tests/unit/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java
diff --git a/packages/NetworkStack/tests/src/com/android/server/util/SharedLogTest.java b/packages/NetworkStack/tests/unit/src/com/android/server/util/SharedLogTest.java
similarity index 100%
rename from packages/NetworkStack/tests/src/com/android/server/util/SharedLogTest.java
rename to packages/NetworkStack/tests/unit/src/com/android/server/util/SharedLogTest.java
diff --git a/packages/SystemUI/res/drawable/corner_gesture_hint.xml b/packages/SystemUI/res/drawable/corner_gesture_hint.xml
new file mode 100644
index 0000000..3f4abb0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/corner_gesture_hint.xml
@@ -0,0 +1,25 @@
+<!--
+    Copyright (C) 2019 The Android Open Source Project
+
+    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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="12dp"
+    android:width="12dp"
+    android:viewportWidth="12"
+    android:viewportHeight="12">
+
+    <path android:fillColor="#00000000"
+          android:pathData="M 1.18 10.65 C 1.18 5.58 5.41 1.18 10.65 1.18"
+          android:strokeColor="#000"
+          android:strokeLineCap="round"
+          android:strokeWidth="1.3" />
+</vector>
diff --git a/packages/SystemUI/res/layout/rounded_corners.xml b/packages/SystemUI/res/layout/rounded_corners.xml
index 26cf792..02651a2 100644
--- a/packages/SystemUI/res/layout/rounded_corners.xml
+++ b/packages/SystemUI/res/layout/rounded_corners.xml
@@ -32,4 +32,22 @@
         android:tint="#ff000000"
         android:layout_gravity="right|bottom"
         android:src="@drawable/rounded" />
+    <ImageView
+        android:id="@+id/assist_hint_left"
+        android:layout_width="32dp"
+        android:layout_height="32dp"
+        android:padding="6dp"
+        android:layout_gravity="left|top"
+        android:src="@drawable/corner_gesture_hint"
+        android:tint="#ffffffff"
+        android:visibility="gone" />
+    <ImageView
+        android:id="@+id/assist_hint_right"
+        android:layout_width="32dp"
+        android:layout_height="32dp"
+        android:padding="6dp"
+        android:layout_gravity="right|bottom"
+        android:src="@drawable/corner_gesture_hint"
+        android:tint="#ffffffff"
+        android:visibility="gone" />
 </com.android.systemui.RegionInterceptingFrameLayout>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 417cc68..6a4dbc8d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1187,7 +1187,7 @@
                 throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED");
             }
             String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
-            int slotId = intent.getIntExtra(PhoneConstants.SLOT_KEY, 0);
+            int slotId = intent.getIntExtra(PhoneConstants.PHONE_KEY, 0);
             int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
                     SubscriptionManager.INVALID_SUBSCRIPTION_ID);
             if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index c0f03a6..69d3af8 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -105,6 +105,7 @@
     private float mDensity;
     private WindowManager mWindowManager;
     private int mRotation;
+    private boolean mAssistHintVisible;
     private DisplayCutoutView mCutoutTop;
     private DisplayCutoutView mCutoutBottom;
     private SecureSetting mColorInversionSetting;
@@ -133,6 +134,55 @@
         mHandler = startHandlerThread();
         mHandler.post(this::startOnScreenDecorationsThread);
         setupStatusBarPaddingIfNeeded();
+        putComponent(ScreenDecorations.class, this);
+    }
+
+    private void fade(View view, boolean fadeIn) {
+        if (fadeIn) {
+            view.animate().cancel();
+            view.setAlpha(0f);
+            view.setVisibility(View.VISIBLE);
+            view.animate().alpha(1f);
+        } else {
+            view.animate().cancel();
+            view.animate().alpha(0f).withEndAction(() -> view.setVisibility(View.INVISIBLE));
+        }
+
+    }
+
+    /**
+     * Controls the visibility of the assist gesture handles.
+     *
+     * @param visible whether the handles should be shown
+     */
+    public void setAssistHintVisible(boolean visible) {
+        if (mAssistHintVisible != visible) {
+            mAssistHintVisible = visible;
+
+            View assistHintTopLeft = mOverlay.findViewById(R.id.assist_hint_left);
+            View assistHintTopRight = mOverlay.findViewById(R.id.assist_hint_right);
+            View assistHintBottomLeft = mBottomOverlay.findViewById(R.id.assist_hint_left);
+            View assistHintBottomRight = mBottomOverlay.findViewById(R.id.assist_hint_right);
+
+            switch (mRotation) {
+                case RotationUtils.ROTATION_NONE:
+                    fade(assistHintBottomLeft, mAssistHintVisible);
+                    fade(assistHintBottomRight, mAssistHintVisible);
+                    break;
+                case RotationUtils.ROTATION_LANDSCAPE:
+                    fade(assistHintTopRight, mAssistHintVisible);
+                    fade(assistHintBottomRight, mAssistHintVisible);
+                    break;
+                case RotationUtils.ROTATION_SEASCAPE:
+                    fade(assistHintTopLeft, mAssistHintVisible);
+                    fade(assistHintBottomLeft, mAssistHintVisible);
+                    break;
+                case RotationUtils.ROTATION_UPSIDE_DOWN:
+                    fade(assistHintTopLeft, mAssistHintVisible);
+                    fade(assistHintTopRight, mAssistHintVisible);
+                    break;
+            }
+        }
     }
 
     @VisibleForTesting
@@ -375,12 +425,52 @@
             updateView(bottomRight, Gravity.TOP | Gravity.LEFT, 0);
         }
 
+        updateAssistantHandleViews();
         mCutoutTop.setRotation(mRotation);
         mCutoutBottom.setRotation(mRotation);
 
         updateWindowVisibilities();
     }
 
+    private void updateAssistantHandleViews() {
+        View assistHintTopLeft = mOverlay.findViewById(R.id.assist_hint_left);
+        View assistHintTopRight = mOverlay.findViewById(R.id.assist_hint_right);
+        View assistHintBottomLeft = mBottomOverlay.findViewById(R.id.assist_hint_left);
+        View assistHintBottomRight = mBottomOverlay.findViewById(R.id.assist_hint_right);
+
+        final int assistHintVisibility = mAssistHintVisible ? View.VISIBLE : View.INVISIBLE;
+
+        if (mRotation == RotationUtils.ROTATION_NONE) {
+            assistHintTopLeft.setVisibility(View.GONE);
+            assistHintTopRight.setVisibility(View.GONE);
+            assistHintBottomLeft.setVisibility(assistHintVisibility);
+            assistHintBottomRight.setVisibility(assistHintVisibility);
+            updateView(assistHintBottomLeft, Gravity.BOTTOM | Gravity.LEFT, 270);
+            updateView(assistHintBottomRight, Gravity.BOTTOM | Gravity.RIGHT, 180);
+        } else if (mRotation == RotationUtils.ROTATION_LANDSCAPE) {
+            assistHintTopLeft.setVisibility(View.GONE);
+            assistHintTopRight.setVisibility(assistHintVisibility);
+            assistHintBottomLeft.setVisibility(View.GONE);
+            assistHintBottomRight.setVisibility(assistHintVisibility);
+            updateView(assistHintTopRight, Gravity.BOTTOM | Gravity.LEFT, 270);
+            updateView(assistHintBottomRight, Gravity.BOTTOM | Gravity.RIGHT, 180);
+        } else if (mRotation == RotationUtils.ROTATION_UPSIDE_DOWN) {
+            assistHintTopLeft.setVisibility(assistHintVisibility);
+            assistHintTopRight.setVisibility(assistHintVisibility);
+            assistHintBottomLeft.setVisibility(View.GONE);
+            assistHintBottomRight.setVisibility(View.GONE);
+            updateView(assistHintTopLeft, Gravity.BOTTOM | Gravity.LEFT, 270);
+            updateView(assistHintTopRight, Gravity.BOTTOM | Gravity.RIGHT, 180);
+        } else if (mRotation == RotationUtils.ROTATION_SEASCAPE) {
+            assistHintTopLeft.setVisibility(assistHintVisibility);
+            assistHintTopRight.setVisibility(View.GONE);
+            assistHintBottomLeft.setVisibility(assistHintVisibility);
+            assistHintBottomRight.setVisibility(View.GONE);
+            updateView(assistHintTopLeft, Gravity.BOTTOM | Gravity.RIGHT, 180);
+            updateView(assistHintBottomLeft, Gravity.BOTTOM | Gravity.LEFT, 270);
+        }
+    }
+
     private void updateView(View v, int gravity, int rotation) {
         ((FrameLayout.LayoutParams)v.getLayoutParams()).gravity = gravity;
         v.setRotation(rotation);
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 51bd9f8..f0c38fb 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -169,7 +169,7 @@
     }
 
     protected boolean shouldShowOrb() {
-        return true;
+        return false;
     }
 
     public void startAssist(Bundle args) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index dcc0419..7e016bb 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.bubbles;
 
+import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
@@ -41,7 +42,9 @@
 import android.app.IActivityTaskManager;
 import android.app.Notification;
 import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.content.Context;
+import android.content.pm.ActivityInfo;
 import android.content.pm.ParceledListSlice;
 import android.content.res.Configuration;
 import android.graphics.Rect;
@@ -112,7 +115,7 @@
     public static final int MAX_BUBBLES = 5; // TODO: actually enforce this
 
     // Enables some subset of notifs to automatically become bubbles
-    private static final boolean DEBUG_ENABLE_AUTO_BUBBLE = false;
+    public static final boolean DEBUG_ENABLE_AUTO_BUBBLE = false;
 
     /** Flag to enable or disable the entire feature */
     private static final String ENABLE_BUBBLES = "experiment_enable_bubbles";
@@ -450,7 +453,8 @@
             if (!areBubblesEnabled(mContext)) {
                 return;
             }
-            if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)) {
+            if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
+                    && canLaunchInActivityView(mContext, entry)) {
                 updateShowInShadeForSuppressNotification(entry);
             }
         }
@@ -460,7 +464,8 @@
             if (!areBubblesEnabled(mContext)) {
                 return;
             }
-            if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)) {
+            if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
+                    && canLaunchInActivityView(mContext, entry)) {
                 updateBubble(entry);
             }
         }
@@ -470,7 +475,8 @@
             if (!areBubblesEnabled(mContext)) {
                 return;
             }
-            boolean shouldBubble = mNotificationInterruptionStateProvider.shouldBubbleUp(entry);
+            boolean shouldBubble = mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
+                    && canLaunchInActivityView(mContext, entry);
             if (!shouldBubble && mBubbleData.hasBubbleWithKey(entry.key)) {
                 // It was previously a bubble but no longer a bubble -- lets remove it
                 removeBubble(entry.key, DISMISS_NO_LONGER_BUBBLE);
@@ -657,12 +663,6 @@
                 || autoBubbleAll;
     }
 
-    private boolean shouldAutoExpand(NotificationEntry entry) {
-        Notification.BubbleMetadata metadata = entry.getBubbleMetadata();
-        return metadata != null && metadata.getAutoExpandBubble()
-                && isForegroundApp(mContext, entry.notification.getPackageName());
-    }
-
     private void updateShowInShadeForSuppressNotification(NotificationEntry entry) {
         boolean suppressNotification = entry.getBubbleMetadata() != null
                 && entry.getBubbleMetadata().isNotificationSuppressed()
@@ -771,6 +771,48 @@
                 (int) (defaultBounciness * 100)) / 100f;
     }
 
+    /**
+     * Whether an intent is properly configured to display in an {@link android.app.ActivityView}.
+     *
+     * Keep checks in sync with NotificationManagerService#canLaunchInActivityView. Typically
+     * that should filter out any invalid bubbles, but should protect SysUI side just in case.
+     *
+     * @param context the context to use.
+     * @param entry the entry to bubble.
+     */
+    static boolean canLaunchInActivityView(Context context, NotificationEntry entry) {
+        PendingIntent intent = entry.getBubbleMetadata() != null
+                ? entry.getBubbleMetadata().getIntent()
+                : null;
+        if (intent == null) {
+            Log.w(TAG, "Unable to create bubble -- no intent");
+            return false;
+        }
+        ActivityInfo info =
+                intent.getIntent().resolveActivityInfo(context.getPackageManager(), 0);
+        if (info == null) {
+            Log.w(TAG, "Unable to send as bubble -- couldn't find activity info for intent: "
+                    + intent);
+            return false;
+        }
+        if (!ActivityInfo.isResizeableMode(info.resizeMode)) {
+            Log.w(TAG, "Unable to send as bubble -- activity is not resizable for intent: "
+                    + intent);
+            return false;
+        }
+        if (info.documentLaunchMode != DOCUMENT_LAUNCH_ALWAYS) {
+            Log.w(TAG, "Unable to send as bubble -- activity is not documentLaunchMode=always "
+                    + "for intent: " + intent);
+            return false;
+        }
+        if ((info.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
+            Log.w(TAG, "Unable to send as bubble -- activity is not embeddable for intent: "
+                    + intent);
+            return false;
+        }
+        return true;
+    }
+
     /** PinnedStackListener that dispatches IME visibility updates to the stack. */
     private class BubblesImeListener extends IPinnedStackListener.Stub {
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index e7948b5..6add4a4 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -16,12 +16,10 @@
 
 package com.android.systemui.bubbles;
 
-import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
-import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING;
-import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE;
-import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS;
 import static android.view.Display.INVALID_DISPLAY;
 
+import static com.android.systemui.bubbles.BubbleController.DEBUG_ENABLE_AUTO_BUBBLE;
+
 import android.annotation.Nullable;
 import android.app.ActivityOptions;
 import android.app.ActivityView;
@@ -30,7 +28,6 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
@@ -337,11 +334,10 @@
                 mNotifRow = null;
             }
             mActivityView.setVisibility(VISIBLE);
-        } else {
+        } else if (DEBUG_ENABLE_AUTO_BUBBLE) {
             // Hide activity view if we had it previously
             mActivityView.setVisibility(GONE);
             mNotifRow = mEntry.getRow();
-
         }
         updateView();
     }
@@ -532,59 +528,14 @@
     @Nullable
     private PendingIntent getBubbleIntent(NotificationEntry entry) {
         Notification notif = entry.notification.getNotification();
-        String packageName = entry.notification.getPackageName();
         Notification.BubbleMetadata data = notif.getBubbleMetadata();
-        if (data != null && canLaunchInActivityView(data.getIntent(), true /* enableLogging */,
-                packageName)) {
+        if (BubbleController.canLaunchInActivityView(mContext, entry) && data != null) {
             return data.getIntent();
-        } else if (BubbleController.shouldUseContentIntent(mContext)
-                && canLaunchInActivityView(notif.contentIntent, false /* enableLogging */,
-                packageName)) {
-            return notif.contentIntent;
         }
         return null;
     }
 
     /**
-     * Whether an intent is properly configured to display in an {@link android.app.ActivityView}.
-     *
-     * @param intent the pending intent of the bubble.
-     * @param enableLogging whether bubble developer error should be logged.
-     * @param packageName the notification package name for this bubble.
-     * @return
-     */
-    private boolean canLaunchInActivityView(PendingIntent intent, boolean enableLogging,
-            String packageName) {
-        if (intent == null) {
-            return false;
-        }
-        ActivityInfo info =
-                intent.getIntent().resolveActivityInfo(mContext.getPackageManager(), 0);
-        if (info == null) {
-            if (enableLogging) {
-                StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
-                        BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING);
-            }
-            return false;
-        }
-        if (!ActivityInfo.isResizeableMode(info.resizeMode)) {
-            if (enableLogging) {
-                StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
-                        BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE);
-            }
-            return false;
-        }
-        if (info.documentLaunchMode != DOCUMENT_LAUNCH_ALWAYS) {
-            if (enableLogging) {
-                StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
-                        BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS);
-            }
-            return false;
-        }
-        return (info.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) != 0;
-    }
-
-    /**
      * Listener that is notified when a bubble is blocked.
      */
     public interface OnBubbleBlockedListener {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index 812c9a7..689d161 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -212,7 +212,7 @@
             return;
         }
         mMobileDrawable.setTintList(
-                ColorStateList.valueOf(mDualToneHandler.getFillColor(darkIntensity)));
+                ColorStateList.valueOf(mDualToneHandler.getSingleColor(darkIntensity)));
         ColorStateList color = ColorStateList.valueOf(getTint(area, this, tint));
         mIn.setImageTintList(color);
         mOut.setImageTintList(color);
@@ -238,7 +238,7 @@
         // We want the ability to change the theme from the one set by SignalDrawable in certain
         // surfaces. In this way, we can pass a theme to the view.
         mMobileDrawable.setTintList(
-                ColorStateList.valueOf(mDualToneHandler.getFillColor(intensity)));
+                ColorStateList.valueOf(mDualToneHandler.getSingleColor(intensity)));
         mIn.setImageTintList(list);
         mOut.setImageTintList(list);
         mMobileType.setImageTintList(list);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index ce8463e..4d4818d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -433,7 +433,8 @@
     public void onBiometricError(int msgId, String errString,
             BiometricSourceType biometricSourceType) {
         mMetricsLogger.write(new LogMaker(MetricsEvent.BIOMETRIC_AUTH)
-                .setType(MetricsEvent.TYPE_ERROR).setSubtype(toSubtype(biometricSourceType)));
+                .setType(MetricsEvent.TYPE_ERROR).setSubtype(toSubtype(biometricSourceType))
+                .addTaggedData(MetricsEvent.FIELD_BIOMETRIC_AUTH_ERROR, msgId));
         cleanup();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
index aba64bdf..f221865 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
@@ -121,8 +121,8 @@
     private final int mEdgeWidth;
     // The slop to distinguish between horizontal and vertical motion
     private final float mTouchSlop;
-    // Minimum distance to move so that is can be considerd as a back swipe
-    private final float mSwipeThreshold;
+    // Duration after which we consider the event as longpress.
+    private final int mLongPressTimeout;
     // The threshold where the touch needs to be at most, such that the arrow is displayed above the
     // finger, otherwise it will be below
     private final int mMinArrowPosition;
@@ -164,8 +164,9 @@
         // TODO: Get this for the current user
         mEdgeWidth = res.getDimensionPixelSize(
                 com.android.internal.R.dimen.config_backGestureInset);
+
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
-        mSwipeThreshold = res.getDimension(R.dimen.navigation_edge_action_drag_threshold);
+        mLongPressTimeout = ViewConfiguration.getLongPressTimeout();
 
         mNavBarHeight = res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height);
         mMinArrowPosition = res.getDimensionPixelSize(
@@ -308,8 +309,18 @@
         return !isInExcludedRegion;
     }
 
+    private void cancelGesture(MotionEvent ev) {
+        // Send action cancel to reset all the touch events
+        mAllowGesture = false;
+        MotionEvent cancelEv = MotionEvent.obtain(ev);
+        cancelEv.setAction(MotionEvent.ACTION_CANCEL);
+        mEdgePanel.handleTouch(cancelEv);
+        cancelEv.recycle();
+    }
+
     private void onMotionEvent(MotionEvent ev) {
-        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+        int action = ev.getActionMasked();
+        if (action == MotionEvent.ACTION_DOWN) {
             // Verify if this is in within the touch region and we aren't in immersive mode, and
             // either the bouncer is showing or the notification panel is hidden
             int stateFlags = mOverviewProxyService.getSystemUiStateFlags();
@@ -330,29 +341,35 @@
                 mThresholdCrossed = false;
             }
         } else if (mAllowGesture) {
-            if (!mThresholdCrossed && ev.getAction() == MotionEvent.ACTION_MOVE) {
-                float dx = Math.abs(ev.getX() - mDownPoint.x);
-                float dy = Math.abs(ev.getY() - mDownPoint.y);
-                if (dy > dx && dy > mTouchSlop) {
-                    // Send action cancel to reset all the touch events
-                    mAllowGesture = false;
-                    MotionEvent cancelEv = MotionEvent.obtain(ev);
-                    cancelEv.setAction(MotionEvent.ACTION_CANCEL);
-                    mEdgePanel.handleTouch(cancelEv);
-                    cancelEv.recycle();
+            if (!mThresholdCrossed) {
+                if (action == MotionEvent.ACTION_POINTER_DOWN) {
+                    // We do not support multi touch for back gesture
+                    cancelGesture(ev);
                     return;
+                } else if (action == MotionEvent.ACTION_MOVE) {
+                    if ((ev.getEventTime() - ev.getDownTime()) > mLongPressTimeout) {
+                        cancelGesture(ev);
+                        return;
+                    }
+                    float dx = Math.abs(ev.getX() - mDownPoint.x);
+                    float dy = Math.abs(ev.getY() - mDownPoint.y);
+                    if (dy > dx && dy > mTouchSlop) {
+                        cancelGesture(ev);
+                        return;
 
-                } else if (dx > dy && dx > mTouchSlop) {
-                    mThresholdCrossed = true;
-                    // Capture inputs
-                    mInputMonitor.pilferPointers();
+                    } else if (dx > dy && dx > mTouchSlop) {
+                        mThresholdCrossed = true;
+                        // Capture inputs
+                        mInputMonitor.pilferPointers();
+                    }
                 }
+
             }
 
             // forward touch
             mEdgePanel.handleTouch(ev);
 
-            boolean isUp = ev.getAction() == MotionEvent.ACTION_UP;
+            boolean isUp = action == MotionEvent.ACTION_UP;
             if (isUp) {
                 boolean performAction = mEdgePanel.shouldTriggerBack();
                 if (performAction) {
@@ -363,7 +380,7 @@
                 mOverviewProxyService.notifyBackAction(performAction, (int) mDownPoint.x,
                         (int) mDownPoint.y, false /* isButton */, !mIsOnLeftEdge);
             }
-            if (isUp || ev.getAction() == MotionEvent.ACTION_CANCEL) {
+            if (isUp || action == MotionEvent.ACTION_CANCEL) {
                 mRegionSamplingHelper.stop();
             } else {
                 updateSamplingRect();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index b8887c4..61a3940 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -95,6 +95,7 @@
     private boolean mWasPulsingOnThisFrame;
     private boolean mWakeAndUnlockRunning;
     private boolean mKeyguardShowing;
+    private boolean mShowingLaunchAffordance;
 
     private final KeyguardMonitor.Callback mKeyguardMonitorCallback =
             new KeyguardMonitor.Callback() {
@@ -299,7 +300,8 @@
         }
 
         boolean onAodNotPulsingOrDocked = mDozing && (!mPulsing || mDocked);
-        boolean invisible = onAodNotPulsingOrDocked || mWakeAndUnlockRunning;
+        boolean invisible = onAodNotPulsingOrDocked || mWakeAndUnlockRunning
+                || mShowingLaunchAffordance;
         setVisibility(invisible ? INVISIBLE : VISIBLE);
         updateClickability();
     }
@@ -485,6 +487,14 @@
     }
 
     /**
+     * When we're launching an affordance, like double pressing power to open camera.
+     */
+    public void onShowingLaunchAffordanceChanged(boolean showing) {
+        mShowingLaunchAffordance = showing;
+        update();
+    }
+
+    /**
      * Called whenever the scrims become opaque, transparent or semi-transparent.
      */
     public void onScrimVisibilityChanged(@ScrimVisibility int scrimsVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
index 6e56854..36050ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
@@ -17,12 +17,15 @@
 package com.android.systemui.statusbar.phone;
 
 import static android.content.Intent.ACTION_OVERLAY_CHANGED;
+import static android.content.Intent.ACTION_PREFERRED_ACTIVITY_CHANGED;
 import static android.os.UserHandle.USER_CURRENT;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
 
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -56,7 +59,7 @@
 public class NavigationModeController implements Dumpable {
 
     private static final String TAG = NavigationModeController.class.getSimpleName();
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
 
     public interface ModeChangedListener {
         void onNavigationModeChanged(int mode);
@@ -76,11 +79,19 @@
     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (intent.getAction().equals(ACTION_OVERLAY_CHANGED)) {
-                if (DEBUG) {
-                    Log.d(TAG, "ACTION_OVERLAY_CHANGED");
-                }
-                updateCurrentInteractionMode(true /* notify */);
+            switch (intent.getAction()) {
+                case ACTION_OVERLAY_CHANGED:
+                    if (DEBUG) {
+                        Log.d(TAG, "ACTION_OVERLAY_CHANGED");
+                    }
+                    updateCurrentInteractionMode(true /* notify */);
+                    break;
+                case ACTION_PREFERRED_ACTIVITY_CHANGED:
+                    if (DEBUG) {
+                        Log.d(TAG, "ACTION_PREFERRED_ACTIVITY_CHANGED");
+                    }
+                    switchFromGestureNavModeIfNotSupportedByDefaultLauncher();
+                    break;
             }
         }
     };
@@ -116,6 +127,7 @@
 
                     // Update the nav mode for the current user
                     updateCurrentInteractionMode(true /* notify */);
+                    switchFromGestureNavModeIfNotSupportedByDefaultLauncher();
 
                     // When switching users, defer enabling the gestural nav overlay until the user
                     // is all set up
@@ -140,7 +152,12 @@
         overlayFilter.addDataSchemeSpecificPart("android", PatternMatcher.PATTERN_LITERAL);
         mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, overlayFilter, null, null);
 
+        IntentFilter preferredActivityFilter = new IntentFilter(ACTION_PREFERRED_ACTIVITY_CHANGED);
+        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, preferredActivityFilter, null,
+                null);
+
         updateCurrentInteractionMode(false /* notify */);
+        switchFromGestureNavModeIfNotSupportedByDefaultLauncher();
 
         // Check if we need to defer enabling gestural nav
         deferGesturalNavOverlayIfNecessary();
@@ -175,6 +192,10 @@
     private int getCurrentInteractionMode(Context context) {
         int mode = context.getResources().getInteger(
                 com.android.internal.R.integer.config_navBarInteractionMode);
+        if (DEBUG) {
+            Log.d(TAG, "getCurrentInteractionMode: mode=" + mMode
+                    + " contextUser=" + context.getUserId());
+        }
         return mode;
     }
 
@@ -250,6 +271,10 @@
         mUiOffloadThread.submit(() -> {
             try {
                 mOverlayManager.setEnabledExclusiveInCategory(overlayPkg, userId);
+                if (DEBUG) {
+                    Log.d(TAG, "setModeOverlay: overlayPackage=" + overlayPkg
+                            + " userId=" + userId);
+                }
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to enable overlay " + overlayPkg + " for user " + userId);
             }
@@ -277,4 +302,27 @@
             Log.d(TAG, "    " + a.getAssetPath());
         }
     }
+
+    private void switchFromGestureNavModeIfNotSupportedByDefaultLauncher() {
+        if (getCurrentInteractionMode(mCurrentUserContext) == NAV_BAR_MODE_GESTURAL
+                && !isGestureNavSupportedByDefaultLauncher(mCurrentUserContext)) {
+            setModeOverlay(NAV_BAR_MODE_3BUTTON_OVERLAY, USER_CURRENT);
+        }
+    }
+
+    private boolean isGestureNavSupportedByDefaultLauncher(Context context) {
+        final ComponentName cn = context.getPackageManager().getHomeActivities(new ArrayList<>());
+        if (cn == null) {
+            // There is no default home app set for the current user, don't make any changes yet.
+            return true;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "isGestureNavSupportedByDefaultLauncher: launcher=" + cn.getPackageName()
+                    + " contextUser=" + context.getUserId());
+        }
+
+        ComponentName recentsComponentName = ComponentName.unflattenFromString(context.getString(
+                com.android.internal.R.string.config_recentsComponentName));
+        return recentsComponentName.getPackageName().equals(cn.getPackageName());
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 3fe7f36..9da75b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -151,7 +151,8 @@
     private final NotificationWakeUpCoordinator mWakeUpCoordinator;
     private final PulseExpansionHandler mPulseExpansionHandler;
 
-    private KeyguardAffordanceHelper mAffordanceHelper;
+    @VisibleForTesting
+    protected KeyguardAffordanceHelper mAffordanceHelper;
     private KeyguardUserSwitcher mKeyguardUserSwitcher;
     @VisibleForTesting
     protected KeyguardStatusBarView mKeyguardStatusBar;
@@ -340,6 +341,7 @@
      */
     private int mThemeResId;
     private KeyguardIndicationController mKeyguardIndicationController;
+    private Consumer<Boolean> mAffordanceLaunchListener;
 
     @Inject
     public NotificationPanelView(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
@@ -447,6 +449,14 @@
                 R.dimen.qs_notification_padding);
     }
 
+    /**
+     * @see #launchCamera(boolean, int)
+     * @see #setLaunchingAffordance(boolean)
+     */
+    public void setLaunchAffordanceListener(Consumer<Boolean> listener) {
+        mAffordanceLaunchListener = listener;
+    }
+
     public void updateResources() {
         Resources res = getResources();
         int qsWidth = res.getDimensionPixelSize(R.dimen.qs_panel_width);
@@ -2743,6 +2753,9 @@
     private void setLaunchingAffordance(boolean launchingAffordance) {
         getLeftIcon().setLaunchingAffordance(launchingAffordance);
         getRightIcon().setLaunchingAffordance(launchingAffordance);
+        if (mAffordanceLaunchListener != null) {
+            mAffordanceLaunchListener.accept(launchingAffordance);
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 72726b3..4e8f584 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -951,6 +951,9 @@
             createUserSwitcher();
         }
 
+        mNotificationPanel.setLaunchAffordanceListener(
+                mStatusBarWindow::onShowingLaunchAffordanceChanged);
+
         // Set up the quick settings tile panel
         View container = mStatusBarWindow.findViewById(R.id.qs_frame);
         if (container != null) {
@@ -3636,6 +3639,7 @@
 
         @Override
         public void onStartedGoingToSleep() {
+            updateNotificationPanelTouchState();
             notifyHeadsUpGoingToSleep();
             dismissVolumeDialog();
         }
@@ -3668,7 +3672,10 @@
      * Keyguard.
      */
     private void updateNotificationPanelTouchState() {
-        mNotificationPanel.setTouchAndAnimationDisabled(!mDeviceInteractive && !mPulsing);
+        boolean goingToSleepWithoutAnimation = isGoingToSleep()
+                && !DozeParameters.getInstance(mContext).shouldControlScreenOff();
+        mNotificationPanel.setTouchAndAnimationDisabled((!mDeviceInteractive && !mPulsing)
+                || goingToSleepWithoutAnimation);
     }
 
     final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 049972e..7d5f23b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -510,6 +510,15 @@
         }
     }
 
+    /**
+     * When we're launching an affordance, like double pressing power to open camera.
+     */
+    public void onShowingLaunchAffordanceChanged(boolean showing) {
+        if (mLockIcon != null) {
+            mLockIcon.onShowingLaunchAffordanceChanged(showing);
+        }
+    }
+
     public class LayoutParams extends FrameLayout.LayoutParams {
 
         public boolean ignoreRightInset;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
index 22006db..d061649 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -378,8 +378,18 @@
         public int visibleState = STATE_ICON;
         public boolean justAdded = true;
 
+        // How far we are from the end of the view actually is the most relevant for animation
+        float distanceToViewEnd = -1;
+
         @Override
         public void applyToView(View view) {
+            float parentWidth = 0;
+            if (view.getParent() instanceof View) {
+                parentWidth = ((View) view.getParent()).getWidth();
+            }
+
+            float currentDistanceToEnd = parentWidth - xTranslation;
+
             if (!(view instanceof StatusIconDisplayable)) {
                 return;
             }
@@ -403,7 +413,7 @@
                     // all other transitions (to/from dot, etc)
                     animationProperties = ANIMATE_ALL_PROPERTIES;
                 }
-            } else if (visibleState != STATE_HIDDEN && xTranslation != view.getTranslationX()) {
+            } else if (visibleState != STATE_HIDDEN && distanceToViewEnd != currentDistanceToEnd) {
                 // Visibility isn't changing, just animate position
                 animationProperties = X_ANIMATION_PROPERTIES;
             }
@@ -416,6 +426,8 @@
             }
 
             justAdded = false;
+            distanceToViewEnd = currentDistanceToEnd;
+
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
index a1c5707..74b15fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
@@ -145,6 +145,7 @@
     }
 
     @Test
+    @Ignore("Flaky")
     public void testMagnetToDismiss_dismiss() throws InterruptedException {
         expand();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
index 9b894c3..9218a8b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
@@ -234,6 +234,7 @@
     }
 
     @Test
+    @Ignore("Flaky")
     public void testMagnetToDismiss_dismiss() throws InterruptedException {
         final Runnable after = Mockito.mock(Runnable.class);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 2f9d892..1b7ca95 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -21,9 +21,11 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.StatusBarManager;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.MotionEvent;
@@ -36,6 +38,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.AmbientPulseManager;
+import com.android.systemui.statusbar.KeyguardAffordanceView;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.PulseExpansionHandler;
@@ -55,6 +58,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.function.Consumer;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
@@ -90,6 +95,8 @@
     private HeadsUpTouchHelper.Callback mHeadsUpCallback;
     @Mock
     private PanelBar mPanelBar;
+    @Mock
+    private KeyguardAffordanceHelper mAffordanceHelper;
     private NotificationPanelView mNotificationPanelView;
 
     @Before
@@ -112,6 +119,9 @@
         mNotificationPanelView = new TestableNotificationPanelView(coordinator, expansionHandler);
         mNotificationPanelView.setHeadsUpManager(mHeadsUpManager);
         mNotificationPanelView.setBar(mPanelBar);
+
+        when(mKeyguardBottomArea.getLeftView()).thenReturn(mock(KeyguardAffordanceView.class));
+        when(mKeyguardBottomArea.getRightView()).thenReturn(mock(KeyguardAffordanceView.class));
     }
 
     @Test
@@ -129,6 +139,19 @@
     }
 
     @Test
+    public void testAffordanceLaunchingListener() {
+        Consumer<Boolean> listener = spy((showing) -> { });
+        mNotificationPanelView.setExpandedFraction(1f);
+        mNotificationPanelView.setLaunchAffordanceListener(listener);
+        mNotificationPanelView.launchCamera(false /* animate */,
+                StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
+        verify(listener).accept(eq(true));
+
+        mNotificationPanelView.onAffordanceLaunchEnded();
+        verify(listener).accept(eq(false));
+    }
+
+    @Test
     public void testOnTouchEvent_expansionCanBeBlocked() {
         mNotificationPanelView.onTouchEvent(MotionEvent.obtain(0L /* downTime */,
                 0L /* eventTime */, MotionEvent.ACTION_DOWN, 0f /* x */, 0f /* y */,
@@ -166,6 +189,7 @@
             mKeyguardBottomArea = NotificationPanelViewTest.this.mKeyguardBottomArea;
             mBigClockContainer = NotificationPanelViewTest.this.mBigClockContainer;
             mQsFrame = NotificationPanelViewTest.this.mQsFrame;
+            mAffordanceHelper = NotificationPanelViewTest.this.mAffordanceHelper;
             initDependencies(NotificationPanelViewTest.this.mStatusBar,
                     NotificationPanelViewTest.this.mGroupManager,
                     NotificationPanelViewTest.this.mNotificationShelf,
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 2616466..71d03a8 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -7371,6 +7371,11 @@
     // Note: Only shows up on first time toggle
     DIALOG_DARK_UI_INFO = 1740;
 
+    // FIELD - Detailed reason in biometric authentication error.
+    // One of the constant value in BiometricConstants.java file.
+    // OS: Q
+    FIELD_BIOMETRIC_AUTH_ERROR = 1741;
+
     // ---- End Q Constants, all Q constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index d2b71e5..d42943c 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -225,17 +225,7 @@
 
                 @Override
                 public void cancel() {
-                    synchronized (mLock) {
-                        final boolean cancelled = isCancelledLocked();
-                        final ICancellationSignal cancellation = mCancellation;
-                        if (!cancelled) {
-                            try {
-                                cancellation.cancel();
-                            } catch (RemoteException e) {
-                                Slog.e(mTag, "Error requesting a cancellation", e);
-                            }
-                        }
-                    }
+                    PendingAutofillRequest.this.cancel();
                 }
             };
         }
@@ -304,7 +294,7 @@
                 try {
                     cancellation.cancel();
                 } catch (RemoteException e) {
-                    Slog.e(mTag, "Error cancelling a fill request", e);
+                    Slog.e(mTag, "Error cancelling an augmented fill request", e);
                 }
             }
             return true;
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 9e1b3b8..9855e4e 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -51,8 +51,8 @@
         "android.hardware.configstore-V1.0-java",
         "android.hardware.contexthub-V1.0-java",
         "android.hidl.manager-V1.2-java",
-        "dnsresolver_aidl_interface-java",
-        "netd_aidl_interface-java",
+        "dnsresolver_aidl_interface-V2-java",
+        "netd_aidl_interface-V2-java",
         "netd_event_listener_interface-java",
     ],
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 0da39e7..104cadc 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -120,7 +120,7 @@
     /**
      * Default value for mFlagBackgroundActivityStartsEnabled if not explicitly set in
      * Settings.Global. This allows it to be set experimentally unless it has been
-     * enabled/disabled in developer options. Defaults to true.
+     * enabled/disabled in developer options. Defaults to false.
      */
     private static final String KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED =
             "default_background_activity_starts_enabled";
@@ -497,7 +497,7 @@
             boolean enabledInDeviceConfig = DeviceConfig.getBoolean(
                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                     KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED,
-                    /*defaultValue*/ true);
+                    /*defaultValue*/ false);
             mFlagBackgroundActivityStartsEnabled = enabledInDeviceConfig;
             if (!enabledInDeviceConfig) {
                 whitelistedPackageNames = DeviceConfig.getProperty(
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index d8b7c2e..fa8c48b 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -1170,7 +1170,7 @@
     }
 
     private void removeSyncsForAuthority(EndPoint info, String why) {
-        mLogger.log("removeSyncsForAuthority: ", info);
+        mLogger.log("removeSyncsForAuthority: ", info, why);
         verifyJobScheduler();
         List<SyncOperation> ops = getAllPendingSyncs();
         for (SyncOperation op: ops) {
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index c7a3f4b..e09c661 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -1027,7 +1027,7 @@
      * Called when the set of account has changed, given the new array of
      * active accounts.
      */
-    public void removeStaleAccounts(@Nullable Account[] accounts, int userId) {
+    public void removeStaleAccounts(@Nullable Account[] currentAccounts, int userId) {
         synchronized (mAuthorities) {
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
                 Slog.v(TAG, "Updating for new accounts...");
@@ -1036,9 +1036,11 @@
             Iterator<AccountInfo> accIt = mAccounts.values().iterator();
             while (accIt.hasNext()) {
                 AccountInfo acc = accIt.next();
-                if ((accounts == null) || (
-                        (acc.accountAndUser.userId == userId)
-                        && !ArrayUtils.contains(accounts, acc.accountAndUser.account))) {
+                if (acc.accountAndUser.userId != userId) {
+                    continue; // Irrelevant user.
+                }
+                if ((currentAccounts == null)
+                        || !ArrayUtils.contains(currentAccounts, acc.accountAndUser.account)) {
                     // This account no longer exists...
                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
                         Slog.v(TAG, "Account removed: " + acc.accountAndUser);
diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java
index b7e0a0f..8d4ad7f 100644
--- a/services/core/java/com/android/server/location/GnssVisibilityControl.java
+++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java
@@ -16,6 +16,7 @@
 
 package com.android.server.location;
 
+import android.annotation.Nullable;
 import android.annotation.SuppressLint;
 import android.app.AppOpsManager;
 import android.app.Notification;
@@ -27,6 +28,7 @@
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.location.LocationManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.PowerManager;
@@ -62,6 +64,9 @@
     // Max wait time for synchronous method onGpsEnabledChanged() to run.
     private static final long ON_GPS_ENABLED_CHANGED_TIMEOUT_MILLIS = 3 * 1000;
 
+    // How long to display location icon for each non-framework non-emergency location request.
+    private static final long LOCATION_ICON_DISPLAY_DURATION_MILLIS = 5 * 1000;
+
     // Wakelocks
     private static final String WAKELOCK_KEY = TAG;
     private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
@@ -77,10 +82,19 @@
 
     private boolean mIsGpsEnabled;
 
+    private static final class ProxyAppState {
+        private boolean mHasLocationPermission;
+        private boolean mIsLocationIconOn;
+
+        private ProxyAppState(boolean hasLocationPermission) {
+            mHasLocationPermission = hasLocationPermission;
+        }
+    }
+
     // Number of non-framework location access proxy apps is expected to be small (< 5).
-    private static final int ARRAY_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS = 7;
-    private ArrayMap<String, Boolean> mProxyAppToLocationPermissions = new ArrayMap<>(
-            ARRAY_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS);
+    private static final int ARRAY_MAP_INITIAL_CAPACITY_PROXY_APPS_STATE = 5;
+    private ArrayMap<String, ProxyAppState> mProxyAppsState = new ArrayMap<>(
+            ARRAY_MAP_INITIAL_CAPACITY_PROXY_APPS_STATE);
 
     private PackageManager.OnPermissionsChangedListener mOnPermissionsChangedListener =
             uid -> runOnHandler(() -> handlePermissionsChanged(uid));
@@ -173,18 +187,18 @@
     }
 
     private void handleProxyAppPackageUpdate(String pkgName, String action) {
-        final Boolean locationPermission = mProxyAppToLocationPermissions.get(pkgName);
-        if (locationPermission == null) {
+        final ProxyAppState proxyAppState = mProxyAppsState.get(pkgName);
+        if (proxyAppState == null) {
             return; // ignore, pkgName is not one of the proxy apps in our list.
         }
 
         if (DEBUG) Log.d(TAG, "Proxy app " + pkgName + " package changed: " + action);
         final boolean updatedLocationPermission = shouldEnableLocationPermissionInGnssHal(pkgName);
-        if (locationPermission != updatedLocationPermission) {
+        if (proxyAppState.mHasLocationPermission != updatedLocationPermission) {
             // Permission changed. So, update the GNSS HAL with the updated list.
             Log.i(TAG, "Proxy app " + pkgName + " location permission changed."
                     + " IsLocationPermissionEnabled: " + updatedLocationPermission);
-            mProxyAppToLocationPermissions.put(pkgName, updatedLocationPermission);
+            proxyAppState.mHasLocationPermission = updatedLocationPermission;
             updateNfwLocationAccessProxyAppsInGnssHal();
         }
     }
@@ -196,35 +210,53 @@
 
         if (nfwLocationAccessProxyApps.isEmpty()) {
             // Stop listening for app permission changes. Clear the app list in GNSS HAL.
-            if (!mProxyAppToLocationPermissions.isEmpty()) {
+            if (!mProxyAppsState.isEmpty()) {
                 mPackageManager.removeOnPermissionsChangeListener(mOnPermissionsChangedListener);
-                mProxyAppToLocationPermissions.clear();
+                resetProxyAppsState();
                 updateNfwLocationAccessProxyAppsInGnssHal();
             }
             return;
         }
 
-        if (mProxyAppToLocationPermissions.isEmpty()) {
+        if (mProxyAppsState.isEmpty()) {
             mPackageManager.addOnPermissionsChangeListener(mOnPermissionsChangedListener);
         } else {
-            mProxyAppToLocationPermissions.clear();
+            resetProxyAppsState();
         }
 
         for (String proxyAppPkgName : nfwLocationAccessProxyApps) {
-            mProxyAppToLocationPermissions.put(proxyAppPkgName,
-                    shouldEnableLocationPermissionInGnssHal(proxyAppPkgName));
+            ProxyAppState proxyAppState = new ProxyAppState(shouldEnableLocationPermissionInGnssHal(
+                    proxyAppPkgName));
+            mProxyAppsState.put(proxyAppPkgName, proxyAppState);
         }
 
         updateNfwLocationAccessProxyAppsInGnssHal();
     }
 
+    private void resetProxyAppsState() {
+        // Clear location icons displayed.
+        for (Map.Entry<String, ProxyAppState> entry : mProxyAppsState.entrySet()) {
+            ProxyAppState proxyAppState = entry.getValue();
+            if (!proxyAppState.mIsLocationIconOn) {
+                continue;
+            }
+
+            mHandler.removeCallbacksAndMessages(proxyAppState);
+            final ApplicationInfo proxyAppInfo = getProxyAppInfo(entry.getKey());
+            if (proxyAppInfo != null) {
+                clearLocationIcon(proxyAppState, proxyAppInfo.uid, entry.getKey());
+            }
+        }
+        mProxyAppsState.clear();
+    }
+
     private boolean isProxyAppListUpdated(List<String> nfwLocationAccessProxyApps) {
-        if (nfwLocationAccessProxyApps.size() != mProxyAppToLocationPermissions.size()) {
+        if (nfwLocationAccessProxyApps.size() != mProxyAppsState.size()) {
             return true;
         }
 
         for (String nfwLocationAccessProxyApp : nfwLocationAccessProxyApps) {
-            if (!mProxyAppToLocationPermissions.containsKey(nfwLocationAccessProxyApp)) {
+            if (!mProxyAppsState.containsKey(nfwLocationAccessProxyApp)) {
                 return true;
             }
         }
@@ -326,11 +358,11 @@
     }
 
     private void handlePermissionsChanged(int uid) {
-        if (mProxyAppToLocationPermissions.isEmpty()) {
+        if (mProxyAppsState.isEmpty()) {
             return;
         }
 
-        for (Map.Entry<String, Boolean> entry : mProxyAppToLocationPermissions.entrySet()) {
+        for (Map.Entry<String, ProxyAppState> entry : mProxyAppsState.entrySet()) {
             final String proxyAppPkgName = entry.getKey();
             final ApplicationInfo proxyAppInfo = getProxyAppInfo(proxyAppPkgName);
             if (proxyAppInfo == null || proxyAppInfo.uid != uid) {
@@ -339,10 +371,11 @@
 
             final boolean isLocationPermissionEnabled = shouldEnableLocationPermissionInGnssHal(
                     proxyAppPkgName);
-            if (isLocationPermissionEnabled != entry.getValue()) {
+            ProxyAppState proxyAppState = entry.getValue();
+            if (isLocationPermissionEnabled != proxyAppState.mHasLocationPermission) {
                 Log.i(TAG, "Proxy app " + proxyAppPkgName + " location permission changed."
                         + " IsLocationPermissionEnabled: " + isLocationPermissionEnabled);
-                entry.setValue(isLocationPermissionEnabled);
+                proxyAppState.mHasLocationPermission = isLocationPermissionEnabled;
                 updateNfwLocationAccessProxyAppsInGnssHal();
             }
             return;
@@ -394,8 +427,8 @@
     private String[] getLocationPermissionEnabledProxyApps() {
         // Get a count of proxy apps with location permission enabled for array creation size.
         int countLocationPermissionEnabledProxyApps = 0;
-        for (Boolean hasLocationPermissionEnabled : mProxyAppToLocationPermissions.values()) {
-            if (hasLocationPermissionEnabled) {
+        for (ProxyAppState proxyAppState : mProxyAppsState.values()) {
+            if (proxyAppState.mHasLocationPermission) {
                 ++countLocationPermissionEnabledProxyApps;
             }
         }
@@ -403,10 +436,9 @@
         int i = 0;
         String[] locationPermissionEnabledProxyApps =
                 new String[countLocationPermissionEnabledProxyApps];
-        for (Map.Entry<String, Boolean> entry : mProxyAppToLocationPermissions.entrySet()) {
+        for (Map.Entry<String, ProxyAppState> entry : mProxyAppsState.entrySet()) {
             final String proxyApp = entry.getKey();
-            final boolean hasLocationPermissionEnabled = entry.getValue();
-            if (hasLocationPermissionEnabled) {
+            if (entry.getValue().mHasLocationPermission) {
                 locationPermissionEnabledProxyApps[i++] = proxyApp;
             }
         }
@@ -422,12 +454,11 @@
         }
 
         final String proxyAppPkgName = nfwNotification.mProxyAppPackageName;
-        final Boolean isLocationPermissionEnabled = mProxyAppToLocationPermissions.get(
-                proxyAppPkgName);
+        final ProxyAppState proxyAppState = mProxyAppsState.get(proxyAppPkgName);
         final boolean isLocationRequestAccepted = nfwNotification.isRequestAccepted();
         final boolean isPermissionMismatched =
-                (isLocationPermissionEnabled == null) ? isLocationRequestAccepted
-                        : (isLocationPermissionEnabled != isLocationRequestAccepted);
+                (proxyAppState == null) ? isLocationRequestAccepted
+                        : (proxyAppState.mHasLocationPermission != isLocationRequestAccepted);
         logEvent(nfwNotification, isPermissionMismatched);
 
         if (!nfwNotification.isRequestAttributedToProxyApp()) {
@@ -442,7 +473,7 @@
                 if (DEBUG) {
                     Log.d(TAG, "Non-framework location request rejected. ProxyAppPackageName field"
                             + " is not set in the notification: " + nfwNotification + ". Number of"
-                            + " configured proxy apps: " + mProxyAppToLocationPermissions.size());
+                            + " configured proxy apps: " + mProxyAppsState.size());
                 }
                 return;
             }
@@ -452,7 +483,7 @@
             return;
         }
 
-        if (isLocationPermissionEnabled == null) {
+        if (proxyAppState == null) {
             Log.w(TAG, "Could not find proxy app " + proxyAppPkgName + " in the value specified for"
                     + " config parameter: " + GnssConfiguration.CONFIG_NFW_PROXY_APPS
                     + ". AppOps service not notified for notification: " + nfwNotification);
@@ -467,18 +498,99 @@
             return;
         }
 
-        mAppOps.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, proxyAppInfo.uid, proxyAppPkgName);
+        if (nfwNotification.isLocationProvided()) {
+            showLocationIcon(proxyAppState, nfwNotification, proxyAppInfo.uid, proxyAppPkgName);
+            mAppOps.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, proxyAppInfo.uid,
+                    proxyAppPkgName);
+        }
 
         // Log proxy app permission mismatch between framework and GNSS HAL.
         if (isPermissionMismatched) {
             Log.w(TAG, "Permission mismatch. Framework proxy app " + proxyAppPkgName
-                    + " location permission is set to " + isLocationPermissionEnabled
+                    + " location permission is set to " + proxyAppState.mHasLocationPermission
                     + " but GNSS non-framework location access response type is "
                     + nfwNotification.getResponseTypeAsString() + " for notification: "
                     + nfwNotification);
         }
     }
 
+    private void showLocationIcon(ProxyAppState proxyAppState, NfwNotification nfwNotification,
+            int uid, String proxyAppPkgName) {
+        // If we receive a new NfwNotification before the location icon is turned off for the
+        // previous notification, update the timer to extend the location icon display duration.
+        final boolean isLocationIconOn = proxyAppState.mIsLocationIconOn;
+        if (!isLocationIconOn) {
+            if (!updateLocationIcon(/* displayLocationIcon = */ true, uid, proxyAppPkgName)) {
+                Log.w(TAG, "Failed to show Location icon for notification: " + nfwNotification);
+                return;
+            }
+            proxyAppState.mIsLocationIconOn = true;
+        } else {
+            // Extend timer by canceling the current one and starting a new one.
+            mHandler.removeCallbacksAndMessages(proxyAppState);
+        }
+
+        // Start timer to turn off location icon. proxyAppState is used as a token to cancel timer.
+        if (DEBUG) {
+            Log.d(TAG, "Location icon on. " + (isLocationIconOn ? "Extending" : "Setting")
+                    + " icon display timer. Uid: " + uid + ", proxyAppPkgName: " + proxyAppPkgName);
+        }
+        if (!mHandler.postDelayed(() -> handleLocationIconTimeout(proxyAppPkgName),
+                /* token = */ proxyAppState, LOCATION_ICON_DISPLAY_DURATION_MILLIS)) {
+            clearLocationIcon(proxyAppState, uid, proxyAppPkgName);
+            Log.w(TAG, "Failed to show location icon for the full duration for notification: "
+                    + nfwNotification);
+        }
+    }
+
+    private void handleLocationIconTimeout(String proxyAppPkgName) {
+        // Get uid again instead of using the one provided in startOp() call as the app could have
+        // been uninstalled and reinstalled during the timeout duration (unlikely in real world).
+        final ApplicationInfo proxyAppInfo = getProxyAppInfo(proxyAppPkgName);
+        if (proxyAppInfo != null) {
+            clearLocationIcon(mProxyAppsState.get(proxyAppPkgName), proxyAppInfo.uid,
+                    proxyAppPkgName);
+        }
+    }
+
+    private void clearLocationIcon(@Nullable ProxyAppState proxyAppState, int uid,
+            String proxyAppPkgName) {
+        updateLocationIcon(/* displayLocationIcon = */ false, uid, proxyAppPkgName);
+        if (proxyAppState != null) proxyAppState.mIsLocationIconOn = false;
+        if (DEBUG) {
+            Log.d(TAG, "Location icon off. Uid: " + uid + ", proxyAppPkgName: " + proxyAppPkgName);
+        }
+    }
+
+    private boolean updateLocationIcon(boolean displayLocationIcon, int uid,
+            String proxyAppPkgName) {
+        if (displayLocationIcon) {
+            // Need two calls to startOp() here with different op code so that the proxy app shows
+            // up in the recent location requests page and also the location icon gets displayed.
+            if (mAppOps.startOpNoThrow(AppOpsManager.OP_MONITOR_LOCATION, uid,
+                    proxyAppPkgName) != AppOpsManager.MODE_ALLOWED) {
+                return false;
+            }
+            if (mAppOps.startOpNoThrow(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, uid,
+                    proxyAppPkgName) != AppOpsManager.MODE_ALLOWED) {
+                mAppOps.finishOp(AppOpsManager.OP_MONITOR_LOCATION, uid, proxyAppPkgName);
+                return false;
+            }
+        } else {
+            mAppOps.finishOp(AppOpsManager.OP_MONITOR_LOCATION, uid, proxyAppPkgName);
+            mAppOps.finishOp(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, uid, proxyAppPkgName);
+        }
+        sendHighPowerMonitoringBroadcast();
+        return true;
+    }
+
+    private void sendHighPowerMonitoringBroadcast() {
+        // Send an intent to notify that a high power request has been added/removed so that
+        // the SystemUi checks the state of AppOps and updates the location icon accordingly.
+        Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
+        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+    }
+
     private void handleEmergencyNfwNotification(NfwNotification nfwNotification) {
         boolean isPermissionMismatched = false;
         if (!nfwNotification.isRequestAccepted()) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 46d6886..8c58247 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -46,6 +46,7 @@
 import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT;
 import static android.content.Context.BIND_AUTO_CREATE;
 import static android.content.Context.BIND_FOREGROUND_SERVICE;
+import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
 import static android.content.pm.PackageManager.MATCH_ALL;
@@ -82,6 +83,9 @@
 import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
 import static android.service.notification.NotificationListenerService.TRIM_FULL;
 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
+import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING;
+import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE;
+import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 
 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
@@ -131,6 +135,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
@@ -197,6 +202,7 @@
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.StatsLog;
 import android.util.Xml;
 import android.util.proto.ProtoOutputStream;
 import android.view.accessibility.AccessibilityEvent;
@@ -4821,9 +4827,12 @@
     private boolean isNotificationAppropriateToBubble(NotificationRecord r, String pkg, int userId,
             NotificationRecord oldRecord) {
         Notification notification = r.getNotification();
+        Notification.BubbleMetadata metadata = notification.getBubbleMetadata();
+        boolean intentCanBubble = metadata != null
+                && canLaunchInActivityView(getContext(), metadata.getIntent(), pkg);
 
         // Does the app want to bubble & is able to bubble
-        boolean canBubble = notification.getBubbleMetadata() != null
+        boolean canBubble = intentCanBubble
                 && mPreferencesHelper.areBubblesAllowed(pkg, userId)
                 && mPreferencesHelper.bubblesEnabled(r.sbn.getUser())
                 && r.getChannel().canBubble()
@@ -4869,6 +4878,63 @@
         return false;
     }
 
+    /**
+     * Whether an intent is properly configured to display in an {@link android.app.ActivityView}.
+     *
+     * @param context       the context to use.
+     * @param pendingIntent the pending intent of the bubble.
+     * @param packageName   the notification package name for this bubble.
+     */
+    // Keep checks in sync with BubbleController#canLaunchInActivityView.
+    @VisibleForTesting
+    protected boolean canLaunchInActivityView(Context context, PendingIntent pendingIntent,
+            String packageName) {
+        if (pendingIntent == null) {
+            Log.w(TAG, "Unable to create bubble -- no intent");
+            return false;
+        }
+
+        // Need escalated privileges to get the intent.
+        final long token = Binder.clearCallingIdentity();
+        Intent intent;
+        try {
+            intent = pendingIntent.getIntent();
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+
+        ActivityInfo info = intent != null
+                ? intent.resolveActivityInfo(context.getPackageManager(), 0)
+                : null;
+        if (info == null) {
+            StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
+                    BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING);
+            Log.w(TAG, "Unable to send as bubble -- couldn't find activity info for intent: "
+                    + intent);
+            return false;
+        }
+        if (!ActivityInfo.isResizeableMode(info.resizeMode)) {
+            StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
+                    BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE);
+            Log.w(TAG, "Unable to send as bubble -- activity is not resizable for intent: "
+                    + intent);
+            return false;
+        }
+        if (info.documentLaunchMode != DOCUMENT_LAUNCH_ALWAYS) {
+            StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
+                    BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS);
+            Log.w(TAG, "Unable to send as bubble -- activity is not documentLaunchMode=always "
+                    + "for intent: " + intent);
+            return false;
+        }
+        if ((info.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
+            Log.w(TAG, "Unable to send as bubble -- activity is not embeddable for intent: "
+                    + intent);
+            return false;
+        }
+        return true;
+    }
+
     private void doChannelWarningToast(CharSequence toastText) {
         Binder.withCleanCallingIdentity(() -> {
             final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
diff --git a/services/core/java/com/android/server/pm/ModuleInfoProvider.java b/services/core/java/com/android/server/pm/ModuleInfoProvider.java
index 6499530..69510d9 100644
--- a/services/core/java/com/android/server/pm/ModuleInfoProvider.java
+++ b/services/core/java/com/android/server/pm/ModuleInfoProvider.java
@@ -64,6 +64,7 @@
 
     // TODO: Move this to an earlier boot phase if anybody requires it then.
     private volatile boolean mMetadataLoaded;
+    private volatile String mPackageName;
 
     ModuleInfoProvider(Context context, IPackageManager packageManager) {
         mContext = context;
@@ -81,9 +82,9 @@
 
     /** Called by the {@code PackageManager} when it has completed its boot sequence */
     public void systemReady() {
-        final String packageName = mContext.getResources().getString(
+        mPackageName = mContext.getResources().getString(
                 R.string.config_defaultModuleMetadataProvider);
-        if (TextUtils.isEmpty(packageName)) {
+        if (TextUtils.isEmpty(mPackageName)) {
             Slog.w(TAG, "No configured module metadata provider.");
             return;
         }
@@ -91,13 +92,13 @@
         final Resources packageResources;
         final PackageInfo pi;
         try {
-            pi = mPackageManager.getPackageInfo(packageName,
+            pi = mPackageManager.getPackageInfo(mPackageName,
                 PackageManager.GET_META_DATA, UserHandle.USER_SYSTEM);
 
-            Context packageContext = mContext.createPackageContext(packageName, 0);
+            Context packageContext = mContext.createPackageContext(mPackageName, 0);
             packageResources = packageContext.getResources();
         } catch (RemoteException | NameNotFoundException e) {
-            Slog.w(TAG, "Unable to discover metadata package: " + packageName, e);
+            Slog.w(TAG, "Unable to discover metadata package: " + mPackageName, e);
             return;
         }
 
@@ -201,4 +202,11 @@
 
         return mModuleInfo.get(packageName);
     }
+
+    String getPackageName() {
+        if (!mMetadataLoaded) {
+            throw new IllegalStateException("Call to getVersion before metadata loaded");
+        }
+        return mPackageName;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e07a132..e86f56f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -5646,9 +5646,11 @@
     private int checkUidPermissionImpl(String permName, int uid) {
         synchronized (mPackages) {
             final String[] packageNames = getPackagesForUid(uid);
-            final PackageParser.Package pkg = (packageNames != null && packageNames.length > 0)
-                    ? mPackages.get(packageNames[0])
-                    : null;
+            PackageParser.Package pkg = null;
+            final int N = packageNames == null ? 0 : packageNames.length;
+            for (int i = 0; pkg == null && i < N; i++) {
+                pkg = mPackages.get(packageNames[i]);
+            }
             // Additional logs for b/111075456; ignore system UIDs
             if (pkg == null && UserHandle.getAppId(uid) >= Process.FIRST_APPLICATION_UID) {
                 if (packageNames == null || packageNames.length < 2) {
@@ -6385,6 +6387,16 @@
         }
     }
 
+    /**
+     * <em>IMPORTANT:</em> Not all packages returned by this method may be known
+     * to the system. There are two conditions in which this may occur:
+     * <ol>
+     *   <li>The package is on adoptable storage and the device has been removed</li>
+     *   <li>The package is being removed and the internal structures are partially updated</li>
+     * </ol>
+     * The second is an artifact of the current data structures and should be fixed. See
+     * b/111075456 for one such instance.
+     */
     @Override
     public String[] getPackagesForUid(int uid) {
         return getPackagesForUid_debug(uid, false);
@@ -24074,6 +24086,11 @@
                     | (appInfo.isVendor() ? IPackageManagerNative.LOCATION_VENDOR : 0)
                     | (appInfo.isProduct() ? IPackageManagerNative.LOCATION_PRODUCT : 0));
         }
+
+        @Override
+        public String getModuleMetadataPackageName() throws RemoteException {
+            return PackageManagerService.this.mModuleInfoProvider.getPackageName();
+        }
     }
 
     private class PackageManagerInternalImpl extends PackageManagerInternal {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 2b7691b8..2a1aee8 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1347,6 +1347,7 @@
                     updatedUserIds);
             updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions,
                     permissionsState, pkg, newImplicitPermissions, updatedUserIds);
+            updatedUserIds = checkIfLegacyStorageOpsNeedToBeUpdated(pkg, replace, updatedUserIds);
         }
 
         // Persist the runtime permissions state for users with changes. If permissions
@@ -1473,6 +1474,28 @@
     }
 
     /**
+     * When the app has requested legacy storage we might need to update
+     * {@link android.app.AppOpsManager#OP_LEGACY_STORAGE}. Hence force an update in
+     * {@link com.android.server.policy.PermissionPolicyService#synchronizePackagePermissionsAndAppOpsForUser(Context, String, int)}
+     *
+     * @param pkg The package for which the permissions are updated
+     * @param replace If the app is being replaced
+     * @param updatedUserIds The ids of the users that already changed.
+     *
+     * @return The ids of the users that are changed
+     */
+    private @NonNull int[] checkIfLegacyStorageOpsNeedToBeUpdated(
+            @NonNull PackageParser.Package pkg, boolean replace, @NonNull int[] updatedUserIds) {
+        if (replace && pkg.applicationInfo.hasRequestedLegacyExternalStorage() && (
+                pkg.requestedPermissions.contains(READ_EXTERNAL_STORAGE)
+                        || pkg.requestedPermissions.contains(WRITE_EXTERNAL_STORAGE))) {
+            return UserManagerService.getInstance().getUserIds();
+        }
+
+        return updatedUserIds;
+    }
+
+    /**
      * Set the state of a implicit permission that is seen for the first time.
      *
      * @param origPs The permission state of the package before the split
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyInternal.java b/services/core/java/com/android/server/policy/PermissionPolicyInternal.java
index ea8616c..7760c1e 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyInternal.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyInternal.java
@@ -17,6 +17,7 @@
 package com.android.server.policy;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Intent;
 
 /**
@@ -34,5 +35,5 @@
      * @return whether the activity should be started
      */
     public abstract boolean checkStartActivity(@NonNull Intent intent, int callingUid,
-            @NonNull String callingPackage);
+            @Nullable String callingPackage);
 }
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 570a153..02911e2 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -229,6 +229,15 @@
          *
          * @see #syncRestrictedOps
          */
+        private final @NonNull ArrayList<OpToUnrestrict> mOpsToAllowIfDefault = new ArrayList<>();
+
+        /**
+         * All ops that need to be flipped to allow.
+         *
+         * Currently, only used by the restricted permissions logic.
+         *
+         * @see #syncRestrictedOps
+         */
         private final @NonNull ArrayList<OpToUnrestrict> mOpsToAllow = new ArrayList<>();
 
         /**
@@ -238,7 +247,7 @@
          *
          * @see #syncRestrictedOps
          */
-        private final @NonNull ArrayList<OpToUnrestrict> mOpsToIgnore = new ArrayList<>();
+        private final @NonNull ArrayList<OpToUnrestrict> mOpsToIgnoreIfDefault = new ArrayList<>();
 
         /**
          * All foreground permissions
@@ -262,11 +271,16 @@
             final int allowCount = mOpsToAllow.size();
             for (int i = 0; i < allowCount; i++) {
                 final OpToUnrestrict op = mOpsToAllow.get(i);
+                setUidModeAllowed(op.code, op.uid);
+            }
+            final int allowIfDefaultCount = mOpsToAllowIfDefault.size();
+            for (int i = 0; i < allowIfDefaultCount; i++) {
+                final OpToUnrestrict op = mOpsToAllowIfDefault.get(i);
                 setUidModeAllowedIfDefault(op.code, op.uid, op.packageName);
             }
-            final int ignoreCount = mOpsToIgnore.size();
-            for (int i = 0; i < ignoreCount; i++) {
-                final OpToUnrestrict op = mOpsToIgnore.get(i);
+            final int ignoreIfDefaultCount = mOpsToIgnoreIfDefault.size();
+            for (int i = 0; i < ignoreIfDefaultCount; i++) {
+                final OpToUnrestrict op = mOpsToIgnoreIfDefault.get(i);
                 setUidModeIgnoredIfDefault(op.code, op.uid, op.packageName);
             }
             final int defaultCount = mOpsToDefault.size();
@@ -341,7 +355,7 @@
                 if (applyRestriction) {
                     mOpsToDefault.add(new OpToRestrict(uid, opCode));
                 } else {
-                    mOpsToAllow.add(new OpToUnrestrict(uid, pkg.packageName, opCode));
+                    mOpsToAllowIfDefault.add(new OpToUnrestrict(uid, pkg.packageName, opCode));
                 }
             } else if (permissionInfo.isSoftRestricted()) {
                 // Storage uses a special app op to decide the mount state and
@@ -356,7 +370,7 @@
                         mOpsToAllow.add(new OpToUnrestrict(uid, pkg.packageName,
                                 AppOpsManager.OP_LEGACY_STORAGE));
                     } else {
-                        mOpsToIgnore.add(new OpToUnrestrict(uid, pkg.packageName,
+                        mOpsToIgnoreIfDefault.add(new OpToUnrestrict(uid, pkg.packageName,
                                 AppOpsManager.OP_LEGACY_STORAGE));
                     }
                 }
@@ -421,6 +435,10 @@
             setUidModeIfDefault(opCode, uid, AppOpsManager.MODE_ALLOWED, packageName);
         }
 
+        private void setUidModeAllowed(int opCode, int uid) {
+            mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_ALLOWED);
+        }
+
         private void setUidModeIgnoredIfDefault(int opCode, int uid, @NonNull String packageName) {
             setUidModeIfDefault(opCode, uid, AppOpsManager.MODE_IGNORED, packageName);
         }
@@ -480,8 +498,9 @@
 
         @Override
         public boolean checkStartActivity(@NonNull Intent intent, int callingUid,
-                @NonNull String callingPackage) {
-            if (isActionRemovedForCallingPackage(intent.getAction(), callingPackage)) {
+                @Nullable String callingPackage) {
+            if (callingPackage != null && isActionRemovedForCallingPackage(intent.getAction(),
+                    callingPackage)) {
                 Slog.w(LOG_TAG, "Action Removed: starting " + intent.toString() + " from "
                         + callingPackage + " (uid=" + callingUid + ")");
                 return false;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index f60a672..c3a769b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2637,17 +2637,25 @@
         final WindowState imeWin = mInputMethodWindow;
         final boolean imeVisible = imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw()
                 && !mDividerControllerLocked.isImeHideRequested();
-        final boolean dockVisible = isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+        final TaskStack dockedStack = getSplitScreenPrimaryStack();
+        final boolean dockVisible = dockedStack != null;
+        final Task topDockedTask = dockVisible ? dockedStack.getTopChild() : null;
         final TaskStack imeTargetStack = mWmService.getImeFocusStackLocked();
         final int imeDockSide = (dockVisible && imeTargetStack != null) ?
                 imeTargetStack.getDockSide() : DOCKED_INVALID;
         final boolean imeOnTop = (imeDockSide == DOCKED_TOP);
         final boolean imeOnBottom = (imeDockSide == DOCKED_BOTTOM);
-        final boolean dockMinimized = mDividerControllerLocked.isMinimizedDock();
         final int imeHeight = mDisplayFrames.getInputMethodWindowVisibleHeight();
         final boolean imeHeightChanged = imeVisible &&
                 imeHeight != mDividerControllerLocked.getImeHeightAdjustedFor();
 
+        // This includes a case where the docked stack is unminimizing and IME is visible for the
+        // bottom side stack. The condition prevents adjusting the override task bounds for IME to
+        // the minimized docked stack bounds.
+        final boolean dockMinimized = mDividerControllerLocked.isMinimizedDock()
+                || (topDockedTask != null && imeOnBottom && !dockedStack.isAdjustedForIme()
+                        && dockedStack.getBounds().height() < topDockedTask.getBounds().height());
+
         // The divider could be adjusted for IME position, or be thinner than usual,
         // or both. There are three possible cases:
         // - If IME is visible, and focus is on top, divider is not moved for IME but thinner.
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 4b0a27b..fb548f9 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -65,10 +65,10 @@
     name: "services.net",
     srcs: ["java/**/*.java"],
     static_libs: [
-        "dnsresolver_aidl_interface-java",
+        "dnsresolver_aidl_interface-V2-java",
         "ipmemorystore-client",
-        "netd_aidl_interface-java",
-        "networkstack-aidl-interfaces-java",
+        "netd_aidl_interface-V2-java",
+        "networkstack-aidl-interfaces-V3-java",
     ],
 }
 
@@ -81,7 +81,7 @@
         "java/android/net/ipmemorystore/**/*.java",
     ],
     static_libs: [
-        "ipmemorystore-aidl-interfaces-java",
+        "ipmemorystore-aidl-interfaces-V3-java",
     ],
 }
 
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 1522a60..869913d 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -73,7 +73,7 @@
         "libui",
         "libunwindstack",
         "libutils",
-        "netd_aidl_interface-cpp",
+        "netd_aidl_interface-V2-cpp",
     ],
 
     dxflags: ["--multi-dex"],
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 92198fa..4a9cef1 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -55,6 +55,6 @@
         "libui",
         "libunwindstack",
         "libutils",
-        "netd_aidl_interface-cpp",
+        "netd_aidl_interface-V2-cpp",
     ],
 }
diff --git a/services/tests/uiservicestests/AndroidManifest.xml b/services/tests/uiservicestests/AndroidManifest.xml
index 3ff85c8..7453c48 100644
--- a/services/tests/uiservicestests/AndroidManifest.xml
+++ b/services/tests/uiservicestests/AndroidManifest.xml
@@ -30,12 +30,14 @@
     <uses-permission android:name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS" />
+    <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT"/>
 
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
 
         <provider android:name=".DummyProvider"
             android:authorities="com.android.services.uitests" />
+
     </application>
 
     <instrumentation
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 9db8753..87f221a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -304,6 +304,12 @@
             void onGranted(ComponentName assistant, int userId, boolean granted);
         }
 
+        @Override
+        protected boolean canLaunchInActivityView(Context context, PendingIntent pendingIntent,
+                String packageName) {
+            // Tests for this not being true are in CTS NotificationManagerTest
+            return true;
+        }
     }
 
     private class TestableToastCallback extends ITransientNotification.Stub {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 55159c3..d77ea6e 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -51,8 +51,6 @@
 import android.os.RemoteCallback;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.os.ShellCallback;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -106,7 +104,6 @@
     final ArraySet<Integer> mLoadedKeyphraseIds = new ArraySet<>();
     ShortcutServiceInternal mShortcutServiceInternal;
     SoundTriggerInternal mSoundTriggerInternal;
-    private boolean mAllowInstantService;
 
     private final RemoteCallbackList<IVoiceInteractionSessionListener>
             mVoiceInteractionSessionListeners = new RemoteCallbackList<>();
@@ -173,14 +170,6 @@
         mServiceStub.switchUser(userHandle);
     }
 
-    // Called by Shell cmd
-    void setAllowInstantService(boolean allowed) {
-        Log.i(TAG, "setAllowInstantService(): " + allowed);
-        mContext.enforceCallingPermission(Manifest.permission.MANAGE_BIND_INSTANT_SERVICE,
-                "setAllowInstantService");
-        mAllowInstantService = allowed;
-    }
-
     class LocalService extends VoiceInteractionManagerInternal {
         @Override
         public void startLocalVoiceInteraction(IBinder callingActivity, Bundle options) {
@@ -234,7 +223,6 @@
                         new IVoiceInteractionSessionShowCallback.Stub() {
                             @Override
                             public void onFailed() {
-                                Slog.w(TAG, "startLocalVoiceInteraction() failed");
                             }
 
                             @Override
@@ -283,10 +271,7 @@
         }
 
         public void initForUser(int userHandle) {
-            if (DEBUG) {
-                Slog.d(TAG, "**************** initForUser user=" + userHandle
-                        + ", allowInstantService=" + mAllowInstantService);
-            }
+            if (DEBUG) Slog.d(TAG, "**************** initForUser user=" + userHandle);
             String curInteractorStr = Settings.Secure.getStringForUser(
                     mContext.getContentResolver(),
                     Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle);
@@ -445,7 +430,6 @@
             if (!mSafeMode) {
                 String curService = Settings.Secure.getStringForUser(
                         mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser);
-                if (DEBUG) Log.d(TAG, "Service for user " + mCurUser + ": " + curService);
                 ComponentName serviceComponent = null;
                 ServiceInfo serviceInfo = null;
                 if (curService != null && !curService.isEmpty()) {
@@ -482,8 +466,7 @@
                     }
                     if (hasComponent) {
                         setImplLocked(new VoiceInteractionManagerServiceImpl(mContext,
-                                UiThread.getHandler(), this, mCurUser, serviceComponent,
-                                mAllowInstantService));
+                                UiThread.getHandler(), this, mCurUser, serviceComponent));
                         mImpl.startLocked();
                     } else {
                         setImplLocked(null);
@@ -1244,26 +1227,16 @@
             synchronized (this) {
                 pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)");
                 pw.println("  mEnableService: " + mEnableService);
-                pw.println("  mAllowInstantService: " + mAllowInstantService);
                 if (mImpl == null) {
                     pw.println("  (No active implementation)");
                     return;
                 }
                 mImpl.dumpLocked(fd, pw, args);
             }
-
             mSoundTriggerInternal.dump(fd, pw, args);
         }
 
         @Override
-        public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
-                String[] args, ShellCallback callback, ResultReceiver resultReceiver)
-                throws RemoteException {
-            new VoiceInteractionManagerServiceShellCommand(VoiceInteractionManagerService.this)
-                    .exec(this, in, out, err, args, callback, resultReceiver);
-        }
-
-        @Override
         public void setUiHints(IVoiceInteractionService service, Bundle hints) {
             synchronized (this) {
                 enforceIsCurrentVoiceInteractionService(service);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 4881ade..a1210cf 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -80,7 +80,6 @@
     final VoiceInteractionServiceInfo mInfo;
     final ComponentName mSessionComponentName;
     final IWindowManager mIWindowManager;
-    final boolean mAllowInstant;
     boolean mBound = false;
     IVoiceInteractionService mService;
 
@@ -126,7 +125,7 @@
 
     VoiceInteractionManagerServiceImpl(Context context, Handler handler,
             VoiceInteractionManagerService.VoiceInteractionManagerServiceStub stub,
-            int userHandle, ComponentName service, boolean allowInstant) {
+            int userHandle, ComponentName service) {
         mContext = context;
         mHandler = handler;
         mServiceStub = stub;
@@ -134,7 +133,6 @@
         mComponent = service;
         mAm = ActivityManager.getService();
         mAtm = ActivityTaskManager.getService();
-        mAllowInstant = allowInstant;
         VoiceInteractionServiceInfo info;
         try {
             info = new VoiceInteractionServiceInfo(context.getPackageManager(), service, mUser);
@@ -169,7 +167,7 @@
         if (mActiveSession == null) {
             mActiveSession = new VoiceInteractionSessionConnection(mServiceStub,
                     mSessionComponentName, mUser, mContext, this,
-                    mInfo.getServiceInfo().applicationInfo.uid, mHandler, mAllowInstant);
+                    mInfo.getServiceInfo().applicationInfo.uid, mHandler);
         }
         List<IBinder> activityTokens = null;
         if (activityToken != null) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java
deleted file mode 100644
index de1191f..0000000
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2019 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.voiceinteraction;
-
-import android.annotation.NonNull;
-import android.os.ShellCommand;
-
-import java.io.PrintWriter;
-
-final class VoiceInteractionManagerServiceShellCommand extends ShellCommand {
-
-    private final VoiceInteractionManagerService mService;
-
-    VoiceInteractionManagerServiceShellCommand(@NonNull VoiceInteractionManagerService service) {
-        this.mService = service;
-    }
-
-    @Override
-    public int onCommand(String cmd) {
-        if (cmd == null) {
-            return handleDefaultCommands(cmd);
-        }
-        final PrintWriter pw = getOutPrintWriter();
-        switch (cmd) {
-            case "set bind-instant-service-allowed":
-            case "set":
-                return requestSet(pw);
-            default:
-                return handleDefaultCommands(cmd);
-        }
-    }
-
-    @Override
-    public void onHelp() {
-        try (PrintWriter pw = getOutPrintWriter();) {
-            pw.println("VoiceInteraction Service (voiceinteraction) commands:");
-            pw.println("  help");
-            pw.println("    Prints this help text.");
-            pw.println("");
-            pw.println("  set bind-instant-service-allowed [true | false]");
-            pw.println("    Sets whether binding to services provided by instant apps is allowed");
-            pw.println("");
-        }
-    }
-
-    private int requestSet(@NonNull PrintWriter pw) {
-        final String what = getNextArgRequired();
-
-        switch(what) {
-            case "bind-instant-service-allowed":
-                return setBindInstantService(pw);
-            default:
-                pw.println("Invalid set: " + what);
-                return -1;
-        }
-    }
-
-    private int setBindInstantService(@NonNull PrintWriter pw) {
-        final String mode = getNextArgRequired();
-        switch (mode.toLowerCase()) {
-            case "true":
-                mService.setAllowInstantService(true);
-                return 0;
-            case "false":
-                mService.setAllowInstantService(false);
-                return 0;
-            default:
-                pw.println("Invalid mode: " + mode);
-                return -1;
-        }
-    }
-}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 3c47044..f16dec6 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -138,8 +138,7 @@
     };
 
     public VoiceInteractionSessionConnection(Object lock, ComponentName component, int user,
-            Context context, Callback callback, int callingUid, Handler handler,
-            boolean allowInstant) {
+            Context context, Callback callback, int callingUid, Handler handler) {
         mLock = lock;
         mSessionComponentName = component;
         mUser = user;
@@ -160,13 +159,10 @@
         mPermissionOwner = permOwner;
         mBindIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
         mBindIntent.setComponent(mSessionComponentName);
-        int flags = Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY
-                | Context.BIND_ALLOW_OOM_MANAGEMENT
-                | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS;
-        if (allowInstant) {
-            flags |= Context.BIND_ALLOW_INSTANT;
-        }
-        mBound = mContext.bindServiceAsUser(mBindIntent, this, flags, new UserHandle(mUser));
+        mBound = mContext.bindServiceAsUser(mBindIntent, this,
+                Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY
+                        | Context.BIND_ALLOW_OOM_MANAGEMENT
+                        | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS, new UserHandle(mUser));
         if (mBound) {
             try {
                 mIWindowManager.addWindowToken(mToken, TYPE_VOICE_INTERACTION, DEFAULT_DISPLAY);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index dab1e6f..4a58d94 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2246,7 +2246,7 @@
     @UnsupportedAppUsage
     public String getNetworkOperatorForPhone(int phoneId) {
         return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, "");
-     }
+    }
 
 
     /**
@@ -2446,21 +2446,7 @@
      * @return the NETWORK_TYPE_xxxx for current data connection.
      */
     public @NetworkType int getNetworkType() {
-       try {
-           ITelephony telephony = getITelephony();
-           if (telephony != null) {
-               return telephony.getNetworkType();
-            } else {
-                // This can happen when the ITelephony interface is not up yet.
-                return NETWORK_TYPE_UNKNOWN;
-            }
-        } catch(RemoteException ex) {
-            // This shouldn't happen in the normal case
-            return NETWORK_TYPE_UNKNOWN;
-        } catch (NullPointerException ex) {
-            // This could happen before phone restarts due to crashing
-            return NETWORK_TYPE_UNKNOWN;
-        }
+        return getNetworkType(getSubId(SubscriptionManager.getDefaultDataSubscriptionId()));
     }
 
     /**
@@ -2491,7 +2477,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getNetworkType(int subId) {
         try {
             ITelephony telephony = getITelephony();
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 68fd9ac..63aded1 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -460,13 +460,6 @@
     void sendDialerSpecialCode(String callingPackageName, String inputCode);
 
     /**
-     * Returns the network type for data transmission
-     * Legacy call, permission-free
-     */
-    @UnsupportedAppUsage
-    int getNetworkType();
-
-    /**
      * Returns the network type of a subId.
      * @param subId user preferred subId.
      * @param callingPackage package making the call.
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 2552f04..e8e2a3d 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -102,6 +102,16 @@
                 callingPackage, message);
     }
 
+    /** Identical to checkCallingOrSelfReadPhoneState but never throws SecurityException */
+    public static boolean checkCallingOrSelfReadPhoneStateNoThrow(
+            Context context, int subId, String callingPackage, String message) {
+        try {
+            return checkCallingOrSelfReadPhoneState(context, subId, callingPackage, message);
+        } catch (SecurityException se) {
+            return false;
+        }
+    }
+
     /**
      * Check whether the app with the given pid/uid can read phone state.
      *
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 1fbb658..306cc51 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -56,7 +56,7 @@
         "libutilscallstack",
         "libziparchive",
         "libz",
-        "netd_aidl_interface-cpp",
+        "netd_aidl_interface-V2-cpp",
         "libnetworkstatsfactorytestjni",
     ],
 }