Merge "SystemMediaRoute2Provider: Set callback after instantiation is done" into rvc-dev
diff --git a/core/java/android/net/DnsPacket.java b/core/java/android/net/DnsPacket.java
deleted file mode 100644
index 83e57e0..0000000
--- a/core/java/android/net/DnsPacket.java
+++ /dev/null
@@ -1,235 +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 android.net;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.text.TextUtils;
-
-import com.android.internal.util.BitUtils;
-
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.text.DecimalFormat;
-import java.text.FieldPosition;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Defines basic data for DNS protocol based on RFC 1035.
- * Subclasses create the specific format used in DNS packet.
- *
- * @hide
- */
-public abstract class DnsPacket {
-    public class DnsHeader {
-        private static final String TAG = "DnsHeader";
-        public final int id;
-        public final int flags;
-        public final int rcode;
-        private final int[] mRecordCount;
-
-        /**
-         * Create a new DnsHeader from a positioned ByteBuffer.
-         *
-         * The ByteBuffer must be in network byte order (which is the default).
-         * Reads the passed ByteBuffer from its current position and decodes a DNS header.
-         * When this constructor returns, the reading position of the ByteBuffer has been
-         * advanced to the end of the DNS header record.
-         * This is meant to chain with other methods reading a DNS response in sequence.
-         */
-        DnsHeader(@NonNull ByteBuffer buf) throws BufferUnderflowException {
-            id = BitUtils.uint16(buf.getShort());
-            flags = BitUtils.uint16(buf.getShort());
-            rcode = flags & 0xF;
-            mRecordCount = new int[NUM_SECTIONS];
-            for (int i = 0; i < NUM_SECTIONS; ++i) {
-                mRecordCount[i] = BitUtils.uint16(buf.getShort());
-            }
-        }
-
-        /**
-         * Get record count by type.
-         */
-        public int getRecordCount(int type) {
-            return mRecordCount[type];
-        }
-    }
-
-    /**
-     * Superclass for DNS questions and DNS resource records.
-     *
-     * DNS questions (No TTL/RDATA)
-     * DNS resource records (With TTL/RDATA)
-     */
-    public class DnsRecord {
-        private static final int MAXNAMESIZE = 255;
-        private static final int MAXLABELSIZE = 63;
-        private static final int MAXLABELCOUNT = 128;
-        private static final int NAME_NORMAL = 0;
-        private static final int NAME_COMPRESSION = 0xC0;
-        private final DecimalFormat byteFormat = new DecimalFormat();
-        private final FieldPosition pos = new FieldPosition(0);
-
-        private static final String TAG = "DnsRecord";
-
-        public final String dName;
-        public final int nsType;
-        public final int nsClass;
-        public final long ttl;
-        private final byte[] mRdata;
-
-        /**
-         * Create a new DnsRecord from a positioned ByteBuffer.
-         *
-         * Reads the passed ByteBuffer from its current position and decodes a DNS record.
-         * When this constructor returns, the reading position of the ByteBuffer has been
-         * advanced to the end of the DNS header record.
-         * This is meant to chain with other methods reading a DNS response in sequence.
-         *
-         * @param ByteBuffer input of record, must be in network byte order
-         *         (which is the default).
-         */
-        DnsRecord(int recordType, @NonNull ByteBuffer buf)
-                throws BufferUnderflowException, ParseException {
-            dName = parseName(buf, 0 /* Parse depth */);
-            if (dName.length() > MAXNAMESIZE) {
-                throw new ParseException(
-                        "Parse name fail, name size is too long: " + dName.length());
-            }
-            nsType = BitUtils.uint16(buf.getShort());
-            nsClass = BitUtils.uint16(buf.getShort());
-
-            if (recordType != QDSECTION) {
-                ttl = BitUtils.uint32(buf.getInt());
-                final int length = BitUtils.uint16(buf.getShort());
-                mRdata = new byte[length];
-                buf.get(mRdata);
-            } else {
-                ttl = 0;
-                mRdata = null;
-            }
-        }
-
-        /**
-         * Get a copy of rdata.
-         */
-        @Nullable
-        public byte[] getRR() {
-            return (mRdata == null) ? null : mRdata.clone();
-        }
-
-        /**
-         * Convert label from {@code byte[]} to {@code String}
-         *
-         * Follows the same conversion rules of the native code (ns_name.c in libc)
-         */
-        private String labelToString(@NonNull byte[] label) {
-            final StringBuffer sb = new StringBuffer();
-            for (int i = 0; i < label.length; ++i) {
-                int b = BitUtils.uint8(label[i]);
-                // Control characters and non-ASCII characters.
-                if (b <= 0x20 || b >= 0x7f) {
-                    // Append the byte as an escaped decimal number, e.g., "\19" for 0x13.
-                    sb.append('\\');
-                    byteFormat.format(b, sb, pos);
-                } else if (b == '"' || b == '.' || b == ';' || b == '\\'
-                        || b == '(' || b == ')' || b == '@' || b == '$') {
-                    // Append the byte as an escaped character, e.g., "\:" for 0x3a.
-                    sb.append('\\');
-                    sb.append((char) b);
-                } else {
-                    // Append the byte as a character, e.g., "a" for 0x61.
-                    sb.append((char) b);
-                }
-            }
-            return sb.toString();
-        }
-
-        private String parseName(@NonNull ByteBuffer buf, int depth) throws
-                BufferUnderflowException, ParseException {
-            if (depth > MAXLABELCOUNT) {
-                throw new ParseException("Failed to parse name, too many labels");
-            }
-            final int len = BitUtils.uint8(buf.get());
-            final int mask = len & NAME_COMPRESSION;
-            if (0 == len) {
-                return "";
-            } else if (mask != NAME_NORMAL && mask != NAME_COMPRESSION) {
-                throw new ParseException("Parse name fail, bad label type");
-            } else if (mask == NAME_COMPRESSION) {
-                // Name compression based on RFC 1035 - 4.1.4 Message compression
-                final int offset = ((len & ~NAME_COMPRESSION) << 8) + BitUtils.uint8(buf.get());
-                final int oldPos = buf.position();
-                if (offset >= oldPos - 2) {
-                    throw new ParseException("Parse compression name fail, invalid compression");
-                }
-                buf.position(offset);
-                final String pointed = parseName(buf, depth + 1);
-                buf.position(oldPos);
-                return pointed;
-            } else {
-                final byte[] label = new byte[len];
-                buf.get(label);
-                final String head = labelToString(label);
-                if (head.length() > MAXLABELSIZE) {
-                    throw new ParseException("Parse name fail, invalid label length");
-                }
-                final String tail = parseName(buf, depth + 1);
-                return TextUtils.isEmpty(tail) ? head : head + "." + tail;
-            }
-        }
-    }
-
-    public static final int QDSECTION = 0;
-    public static final int ANSECTION = 1;
-    public static final int NSSECTION = 2;
-    public static final int ARSECTION = 3;
-    private static final int NUM_SECTIONS = ARSECTION + 1;
-
-    private static final String TAG = DnsPacket.class.getSimpleName();
-
-    protected final DnsHeader mHeader;
-    protected final List<DnsRecord>[] mRecords;
-
-    protected DnsPacket(@NonNull byte[] data) throws ParseException {
-        if (null == data) throw new ParseException("Parse header failed, null input data");
-        final ByteBuffer buffer;
-        try {
-            buffer = ByteBuffer.wrap(data);
-            mHeader = new DnsHeader(buffer);
-        } catch (BufferUnderflowException e) {
-            throw new ParseException("Parse Header fail, bad input data", e);
-        }
-
-        mRecords = new ArrayList[NUM_SECTIONS];
-
-        for (int i = 0; i < NUM_SECTIONS; ++i) {
-            final int count = mHeader.getRecordCount(i);
-            if (count > 0) {
-                mRecords[i] = new ArrayList(count);
-            }
-            for (int j = 0; j < count; ++j) {
-                try {
-                    mRecords[i].add(new DnsRecord(i, buffer));
-                } catch (BufferUnderflowException e) {
-                    throw new ParseException("Parse record fail", e);
-                }
-            }
-        }
-    }
-}
diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java
index 0b1a845..3f7660f 100644
--- a/core/java/android/net/DnsResolver.java
+++ b/core/java/android/net/DnsResolver.java
@@ -38,6 +38,8 @@
 import android.system.ErrnoException;
 import android.util.Log;
 
+import com.android.net.module.util.DnsPacket;
+
 import java.io.FileDescriptor;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -97,7 +99,7 @@
     @interface DnsError {}
     /**
      * Indicates that there was an error parsing the response the query.
-     * The cause of this error is available via getCause() and is a ParseException.
+     * The cause of this error is available via getCause() and is a {@link ParseException}.
      */
     public static final int ERROR_PARSE = 0;
     /**
@@ -290,8 +292,15 @@
             }
             try {
                 mAllAnswers.addAll(new DnsAddressAnswer(answer).getAddresses());
-            } catch (ParseException e) {
-                mDnsException = new DnsException(ERROR_PARSE, e);
+            } catch (DnsPacket.ParseException e) {
+                // Convert the com.android.net.module.util.DnsPacket.ParseException to an
+                // android.net.ParseException. This is the type that was used in Q and is implied
+                // by the public documentation of ERROR_PARSE.
+                //
+                // DnsPacket cannot throw android.net.ParseException directly because it's @hide.
+                ParseException pe = new ParseException(e.reason, e.getCause());
+                pe.setStackTrace(e.getStackTrace());
+                mDnsException = new DnsException(ERROR_PARSE, pe);
             }
             maybeReportAnswer();
         }
diff --git a/core/java/android/service/autofill/InlineSuggestionRenderService.java b/core/java/android/service/autofill/InlineSuggestionRenderService.java
index 3ea443b..8790fb2 100644
--- a/core/java/android/service/autofill/InlineSuggestionRenderService.java
+++ b/core/java/android/service/autofill/InlineSuggestionRenderService.java
@@ -64,7 +64,7 @@
     public static final String SERVICE_INTERFACE =
             "android.service.autofill.InlineSuggestionRenderService";
 
-    private final Handler mHandler = new Handler(Looper.getMainLooper(), null, true);
+    private final Handler mMainHandler = new Handler(Looper.getMainLooper(), null, true);
 
     private IInlineSuggestionUiCallback mCallback;
 
@@ -192,15 +192,22 @@
                 }
                 return true;
             });
+            final InlineSuggestionUiImpl uiImpl = new InlineSuggestionUiImpl(host, mMainHandler);
+            mActiveInlineSuggestions.put(uiImpl, true);
 
-            try {
-                InlineSuggestionUiImpl uiImpl = new InlineSuggestionUiImpl(host, mHandler);
-                mActiveInlineSuggestions.put(uiImpl, true);
-                callback.onContent(new InlineSuggestionUiWrapper(uiImpl), host.getSurfacePackage(),
-                        measuredSize.getWidth(), measuredSize.getHeight());
-            } catch (RemoteException e) {
-                Log.w(TAG, "RemoteException calling onContent()");
-            }
+            // We post the callback invocation to the end of the main thread handler queue, to make
+            // sure the callback happens after the views are drawn. This is needed because calling
+            // {@link SurfaceControlViewHost#setView()} will post a task to the main thread
+            // to draw the view asynchronously.
+            mMainHandler.post(() -> {
+                try {
+                    callback.onContent(new InlineSuggestionUiWrapper(uiImpl),
+                            host.getSurfacePackage(),
+                            measuredSize.getWidth(), measuredSize.getHeight());
+                } catch (RemoteException e) {
+                    Log.w(TAG, "RemoteException calling onContent()");
+                }
+            });
         } finally {
             updateDisplay(Display.DEFAULT_DISPLAY);
         }
@@ -305,7 +312,7 @@
                 public void renderSuggestion(@NonNull IInlineSuggestionUiCallback callback,
                         @NonNull InlinePresentation presentation, int width, int height,
                         @Nullable IBinder hostInputToken, int displayId) {
-                    mHandler.sendMessage(
+                    mMainHandler.sendMessage(
                             obtainMessage(InlineSuggestionRenderService::handleRenderSuggestion,
                                     InlineSuggestionRenderService.this, callback, presentation,
                                     width, height, hostInputToken, displayId));
@@ -313,7 +320,7 @@
 
                 @Override
                 public void getInlineSuggestionsRendererInfo(@NonNull RemoteCallback callback) {
-                    mHandler.sendMessage(obtainMessage(
+                    mMainHandler.sendMessage(obtainMessage(
                             InlineSuggestionRenderService::handleGetInlineSuggestionsRendererInfo,
                             InlineSuggestionRenderService.this, callback));
                 }
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index f944dd7..0d420c5 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -1184,7 +1184,8 @@
                         // may have been destroyed so now we need to make
                         // sure it is re-created.
                         doOffsetsChanged(false);
-                        updateSurface(false, false, false);
+                        // force relayout to get new surface
+                        updateSurface(true, false, false);
                     }
                     onVisibilityChanged(visible);
                 }
diff --git a/core/java/com/android/internal/os/FuseAppLoop.java b/core/java/com/android/internal/os/FuseAppLoop.java
index ab0cc30..2393036 100644
--- a/core/java/com/android/internal/os/FuseAppLoop.java
+++ b/core/java/com/android/internal/os/FuseAppLoop.java
@@ -210,7 +210,7 @@
                         if (mInstance != 0) {
                             native_replySimple(mInstance, unique, FUSE_OK);
                         }
-                        mBytesMap.stopUsing(entry.getThreadId());
+                        mBytesMap.stopUsing(inode);
                         recycleLocked(args);
                     }
                     break;
@@ -270,7 +270,7 @@
                 if (mInstance != 0) {
                     native_replyOpen(mInstance, unique, /* fh */ inode);
                     entry.opened = true;
-                    return mBytesMap.startUsing(entry.getThreadId());
+                    return mBytesMap.startUsing(inode);
                 }
             } catch (ErrnoException error) {
                 replySimpleLocked(unique, getError(error));
@@ -354,27 +354,27 @@
     }
 
     /**
-     * Map between Thread ID and byte buffer.
+     * Map between inode and byte buffer.
      */
     private static class BytesMap {
         final Map<Long, BytesMapEntry> mEntries = new HashMap<>();
 
-        byte[] startUsing(long threadId) {
-            BytesMapEntry entry = mEntries.get(threadId);
+        byte[] startUsing(long inode) {
+            BytesMapEntry entry = mEntries.get(inode);
             if (entry == null) {
                 entry = new BytesMapEntry();
-                mEntries.put(threadId, entry);
+                mEntries.put(inode, entry);
             }
             entry.counter++;
             return entry.bytes;
         }
 
-        void stopUsing(long threadId) {
-            final BytesMapEntry entry = mEntries.get(threadId);
+        void stopUsing(long inode) {
+            final BytesMapEntry entry = mEntries.get(inode);
             Objects.requireNonNull(entry);
             entry.counter--;
             if (entry.counter <= 0) {
-                mEntries.remove(threadId);
+                mEntries.remove(inode);
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 297d92e..640475e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -51,6 +51,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
 import android.util.Log;
 import android.view.Choreographer;
 import android.view.DisplayCutout;
@@ -1065,10 +1066,8 @@
                     if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
                         final Intent intent = bubble.getSettingsIntent(mContext);
                         collapseStack(() -> {
-
                             mContext.startActivityAsUser(intent, bubble.getUser());
-                            logBubbleClickEvent(
-                                    bubble,
+                            logBubbleEvent(bubble,
                                     SysUiStatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_SETTINGS);
                         });
                     }
@@ -2757,16 +2756,28 @@
     /**
      * Logs the bubble UI event.
      *
-     * @param bubble the bubble that is being interacted on. Null value indicates that
-     *               the user interaction is not specific to one bubble.
+     * @param provider the bubble view provider that is being interacted on. Null value indicates
+     *               that the user interaction is not specific to one bubble.
      * @param action the user interaction enum.
      */
-    private void logBubbleEvent(@Nullable BubbleViewProvider bubble, int action) {
-        if (bubble == null) {
+    private void logBubbleEvent(@Nullable BubbleViewProvider provider, int action) {
+        if (provider == null || provider.getKey().equals(BubbleOverflow.KEY)) {
+            SysUiStatsLog.write(SysUiStatsLog.BUBBLE_UI_CHANGED,
+                    mContext.getApplicationInfo().packageName,
+                    provider == null ? null : BubbleOverflow.KEY /* notification channel */,
+                    0 /* notification ID */,
+                    0 /* bubble position */,
+                    getBubbleCount(),
+                    action,
+                    getNormalizedXPosition(),
+                    getNormalizedYPosition(),
+                    false /* unread bubble */,
+                    false /* on-going bubble */,
+                    false /* isAppForeground (unused) */);
             return;
         }
-        bubble.logUIEvent(getBubbleCount(), action, getNormalizedXPosition(),
-                getNormalizedYPosition(), getBubbleIndex(bubble));
+        provider.logUIEvent(getBubbleCount(), action, getNormalizedXPosition(),
+                getNormalizedYPosition(), getBubbleIndex(provider));
     }
 
     /**
@@ -2805,20 +2816,4 @@
         }
         return bubbles;
     }
-
-    /**
-     * Logs bubble UI click event.
-     *
-     * @param bubble the bubble notification entry that user is interacting with.
-     * @param action the user interaction enum.
-     */
-    private void logBubbleClickEvent(Bubble bubble, int action) {
-        bubble.logUIEvent(
-                getBubbleCount(),
-                action,
-                getNormalizedXPosition(),
-                getNormalizedYPosition(),
-                getBubbleIndex(getExpandedBubble())
-        );
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 4821d8c..e83b159 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -822,7 +822,7 @@
      */
     public void updateSlippery() {
         setSlippery(!isQuickStepSwipeUpEnabled() ||
-                (mPanelView.isFullyExpanded() && !mPanelView.isCollapsing()));
+                (mPanelView != null && mPanelView.isFullyExpanded() && !mPanelView.isCollapsing()));
     }
 
     private void setSlippery(boolean slippery) {
diff --git a/packages/Tethering/jarjar-rules.txt b/packages/Tethering/jarjar-rules.txt
index e90a2cc..8f072e4 100644
--- a/packages/Tethering/jarjar-rules.txt
+++ b/packages/Tethering/jarjar-rules.txt
@@ -15,3 +15,6 @@
 rule android.net.LocalLog* com.android.networkstack.tethering.LocalLog@1
 
 rule android.net.shared.Inet4AddressUtils* com.android.networkstack.tethering.shared.Inet4AddressUtils@1
+
+# Classes from net-utils-framework-common
+rule com.android.net.module.util.** com.android.networkstack.tethering.util.@1
\ No newline at end of file
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
index 398ece4..19248ca 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
@@ -45,6 +45,8 @@
     private final Object mLock;
     @NonNull
     private final Handler mHandler;
+    @NonNull
+    private final InlineFillUi.InlineUiEventCallback mUiCallback;
 
     @Nullable
     @GuardedBy("mLock")
@@ -54,12 +56,14 @@
     private InlineFillUi mInlineFillUi;
 
     AutofillInlineSessionController(InputMethodManagerInternal inputMethodManagerInternal,
-            int userId, ComponentName componentName, Handler handler, Object lock) {
+            int userId, ComponentName componentName, Handler handler, Object lock,
+            InlineFillUi.InlineUiEventCallback callback) {
         mInputMethodManagerInternal = inputMethodManagerInternal;
         mUserId = userId;
         mComponentName = componentName;
         mHandler = handler;
         mLock = lock;
+        mUiCallback = callback;
     }
 
 
@@ -82,7 +86,8 @@
         // TODO(b/151123764): consider reusing the same AutofillInlineSession object for the
         // same field.
         mSession = new AutofillInlineSuggestionsRequestSession(mInputMethodManagerInternal, mUserId,
-                mComponentName, mHandler, mLock, autofillId, requestConsumer, uiExtras);
+                mComponentName, mHandler, mLock, autofillId, requestConsumer, uiExtras,
+                mUiCallback);
         mSession.onCreateInlineSuggestionsRequestLocked();
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
index 48895ad..68eeb0a 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
@@ -29,6 +29,7 @@
 import android.os.RemoteException;
 import android.util.Slog;
 import android.view.autofill.AutofillId;
+import android.view.inputmethod.InlineSuggestion;
 import android.view.inputmethod.InlineSuggestionsRequest;
 import android.view.inputmethod.InlineSuggestionsResponse;
 
@@ -40,6 +41,7 @@
 import com.android.server.inputmethod.InputMethodManagerInternal;
 
 import java.lang.ref.WeakReference;
+import java.util.List;
 import java.util.Optional;
 import java.util.function.Consumer;
 
@@ -65,6 +67,8 @@
     private final Handler mHandler;
     @NonNull
     private final Bundle mUiExtras;
+    @NonNull
+    private final InlineFillUi.InlineUiEventCallback mUiCallback;
 
     @GuardedBy("mLock")
     @NonNull
@@ -97,18 +101,22 @@
 
     @GuardedBy("mLock")
     private boolean mDestroyed = false;
+    @GuardedBy("mLock")
+    private boolean mPreviousHasNonPinSuggestionShow;
 
     AutofillInlineSuggestionsRequestSession(
             @NonNull InputMethodManagerInternal inputMethodManagerInternal, int userId,
             @NonNull ComponentName componentName, @NonNull Handler handler, @NonNull Object lock,
             @NonNull AutofillId autofillId,
-            @NonNull Consumer<InlineSuggestionsRequest> requestConsumer, @NonNull Bundle uiExtras) {
+            @NonNull Consumer<InlineSuggestionsRequest> requestConsumer, @NonNull Bundle uiExtras,
+            @NonNull InlineFillUi.InlineUiEventCallback callback) {
         mInputMethodManagerInternal = inputMethodManagerInternal;
         mUserId = userId;
         mComponentName = componentName;
         mHandler = handler;
         mLock = lock;
         mUiExtras = uiExtras;
+        mUiCallback = callback;
 
         mAutofillId = autofillId;
         mImeRequestConsumer = requestConsumer;
@@ -217,6 +225,7 @@
                 // No-op if both the previous response and current response are empty.
                 return;
             }
+            maybeNotifyFillUiEventLocked(response.getInlineSuggestions());
             updateResponseToImeUncheckLocked(response);
             mPreviousResponseIsNotEmpty = !isEmptyResponse;
         }
@@ -238,6 +247,38 @@
         }
     }
 
+    @GuardedBy("mLock")
+    private void maybeNotifyFillUiEventLocked(@NonNull List<InlineSuggestion> suggestions) {
+        if (mDestroyed) {
+            return;
+        }
+        boolean hasSuggestionToShow = false;
+        for (int i = 0; i < suggestions.size(); i++) {
+            InlineSuggestion suggestion = suggestions.get(i);
+            // It is possible we don't have any match result but we still have pinned
+            // suggestions. Only notify we have non-pinned suggestions to show
+            if (!suggestion.getInfo().isPinned()) {
+                hasSuggestionToShow = true;
+                break;
+            }
+        }
+        if (sDebug) {
+            Slog.d(TAG, "maybeNotifyFillUiEventLoked(): hasSuggestionToShow=" + hasSuggestionToShow
+                    + ", mPreviousHasNonPinSuggestionShow=" + mPreviousHasNonPinSuggestionShow);
+        }
+        // Use mPreviousHasNonPinSuggestionShow to save previous status, if the display status
+        // change, we can notify the event.
+        if (hasSuggestionToShow && !mPreviousHasNonPinSuggestionShow) {
+            // From no suggestion to has suggestions to show
+            mUiCallback.notifyInlineUiShown(mAutofillId);
+        } else if (!hasSuggestionToShow && mPreviousHasNonPinSuggestionShow) {
+            // From has suggestions to no suggestions to show
+            mUiCallback.notifyInlineUiHidden(mAutofillId);
+        }
+        // Update the latest status
+        mPreviousHasNonPinSuggestionShow = hasSuggestionToShow;
+    }
+
     /**
      * Handles the {@code request} and {@code callback} received from the IME.
      *
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 712b413..3114a6a 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -843,7 +843,18 @@
         setClientLocked(client);
 
         mInlineSessionController = new AutofillInlineSessionController(inputMethodManagerInternal,
-                userId, componentName, handler, mLock);
+                userId, componentName, handler, mLock,
+                new InlineFillUi.InlineUiEventCallback() {
+                    @Override
+                    public void notifyInlineUiShown(AutofillId autofillId) {
+                        notifyFillUiShown(autofillId);
+                    }
+
+                    @Override
+                    public void notifyInlineUiHidden(AutofillId autofillId) {
+                        notifyFillUiHidden(autofillId);
+                    }
+                });
 
         mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
                 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags));
@@ -1329,6 +1340,26 @@
                 this, intentSender, intent));
     }
 
+    private void notifyFillUiHidden(@NonNull AutofillId autofillId) {
+        synchronized (mLock) {
+            try {
+                mClient.notifyFillUiHidden(this.id, autofillId);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Error sending fill UI hidden notification", e);
+            }
+        }
+    }
+
+    private void notifyFillUiShown(@NonNull AutofillId autofillId) {
+        synchronized (mLock) {
+            try {
+                mClient.notifyFillUiShown(this.id, autofillId);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Error sending fill UI shown notification", e);
+            }
+        }
+    }
+
     private void doStartIntentSender(IntentSender intentSender, Intent intent) {
         try {
             synchronized (mLock) {
@@ -2769,11 +2800,6 @@
                 // TODO(b/156099633): remove this once framework gets out of business of resending
                 // inline suggestions when IME visibility changes.
                 mInlineSessionController.hideInlineSuggestionsUiLocked(viewState.id);
-                try {
-                    mClient.notifyFillUiHidden(this.id, viewState.id);
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Error requesting to hide fill UI", e);
-                }
                 viewState.resetState(ViewState.STATE_CHANGED);
                 return;
             } else if ((viewState.id.equals(this.mCurrentViewId))
@@ -2800,11 +2826,6 @@
                 // TODO: we should be able to replace this with controller#filterInlineFillUiLocked
                 // to accomplish filtering for augmented autofill.
                 mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId);
-                try {
-                    mClient.notifyFillUiHidden(this.id, mCurrentViewId);
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Error sending fill UI hidden notification", e);
-                }
             }
         }
 
@@ -2890,11 +2911,6 @@
                 if (requestShowInlineSuggestionsLocked(response, filterText)) {
                     final ViewState currentView = mViewStates.get(mCurrentViewId);
                     currentView.setState(ViewState.STATE_INLINE_SHOWN);
-                    try {
-                        mClient.notifyFillUiShown(this.id, mCurrentViewId);
-                    } catch (RemoteException e) {
-                        Slog.e(TAG, "Error sending fill UI shown notification", e);
-                    }
                     //TODO(b/137800469): Fix it to log showed only when IME asks for inflation,
                     // rather than here where framework sends back the response.
                     mService.logDatasetShown(id, mClientState);
@@ -2965,11 +2981,6 @@
                     synchronized (mLock) {
                         mInlineSessionController.hideInlineSuggestionsUiLocked(
                                 focusedId);
-                        try {
-                            mClient.notifyFillUiHidden(this.id, focusedId);
-                        } catch (RemoteException e) {
-                            Slog.e(TAG, "Error sending fill UI hidden notification", e);
-                        }
                     }
                 }, remoteRenderService);
         return mInlineSessionController.setInlineFillUiLocked(inlineFillUi);
@@ -3484,11 +3495,6 @@
                 }
                 if (mCurrentViewId != null) {
                     mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId);
-                    try {
-                        mClient.notifyFillUiHidden(this.id, mCurrentViewId);
-                    } catch (RemoteException e) {
-                        Slog.e(TAG, "Error sending fill UI hidden notification", e);
-                    }
                 }
                 autoFillApp(dataset);
                 return;
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java
index 1c430b3..627c073 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java
@@ -297,4 +297,19 @@
          */
         void startIntentSender(@NonNull IntentSender intentSender, @NonNull Intent intent);
     }
+
+    /**
+     * Callback for inline suggestion Ui related events.
+     */
+    public interface InlineUiEventCallback {
+        /**
+         * Callback to notify inline ui is shown.
+         */
+        void notifyInlineUiShown(@NonNull AutofillId autofillId);
+
+        /**
+         * Callback to notify inline ui is hidden.
+         */
+        void notifyInlineUiHidden(@NonNull AutofillId autofillId);
+    }
 }
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngineThread.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngineThread.java
index 7075608..71f1dbf 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngineThread.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngineThread.java
@@ -1,10 +1,10 @@
 package com.android.server.backup.restore;
 
 import android.os.ParcelFileDescriptor;
+import android.os.ParcelFileDescriptor.AutoCloseInputStream;
 
 import libcore.io.IoUtils;
 
-import java.io.FileInputStream;
 import java.io.InputStream;
 
 class FullRestoreEngineThread implements Runnable {
@@ -19,7 +19,7 @@
         // We *do* want this FileInputStream to own the underlying fd, so that
         // when we are finished with it, it closes this end of the pipe in a way
         // that signals its other end.
-        mEngineStream = new FileInputStream(engineSocket.getFileDescriptor(), true);
+        mEngineStream = new AutoCloseInputStream(engineSocket);
         // Tell it to be sure to leave the agent instance up after finishing
         mMustKillAgent = false;
     }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 63a984c..d479f23 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -52,7 +52,6 @@
 import static com.android.internal.util.XmlUtils.writeIntAttribute;
 import static com.android.internal.util.XmlUtils.writeLongAttribute;
 import static com.android.internal.util.XmlUtils.writeStringAttribute;
-import static com.android.server.storage.StorageUserConnection.REMOTE_TIMEOUT_SECONDS;
 
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -224,6 +223,9 @@
     private static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
             "persist.sys.vold_app_data_isolation_enabled";
 
+    // How long we wait to reset storage, if we failed to call onMount on the
+    // external storage service.
+    public static final int FAILED_MOUNT_RESET_TIMEOUT_SECONDS = 10;
     /**
      * If {@code 1}, enables the isolated storage feature. If {@code -1},
      * disables the isolated storage feature. If {@code 0}, uses the default
@@ -2202,7 +2204,7 @@
                     } catch (ExternalStorageServiceException e) {
                         Slog.e(TAG, "Failed to mount volume " + vol, e);
 
-                        int nextResetSeconds = REMOTE_TIMEOUT_SECONDS * 2;
+                        int nextResetSeconds = FAILED_MOUNT_RESET_TIMEOUT_SECONDS;
                         Slog.i(TAG, "Scheduling reset in " + nextResetSeconds + "s");
                         mHandler.removeMessages(H_RESET);
                         mHandler.sendMessageDelayed(mHandler.obtainMessage(H_RESET),
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index cd6b98d..9203122 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -655,7 +655,7 @@
             final int appxUidCount = userCount * allSettings.size();
             for (int su = 0; su < userCount; su++) {
                 int subjectUser = allUsers[su].id;
-                for (int ou = su; ou < userCount; ou++) {
+                for (int ou = 0; ou < userCount; ou++) {
                     int otherUser = allUsers[ou].id;
                     int subjectUid = UserHandle.getUid(subjectUser, subjectSetting.appId);
                     if (!mShouldFilterCache.contains(subjectUid)) {
diff --git a/services/core/java/com/android/server/storage/AppFuseBridge.java b/services/core/java/com/android/server/storage/AppFuseBridge.java
index 9d6a647..b00540f 100644
--- a/services/core/java/com/android/server/storage/AppFuseBridge.java
+++ b/services/core/java/com/android/server/storage/AppFuseBridge.java
@@ -56,6 +56,15 @@
 
     public ParcelFileDescriptor addBridge(MountScope mountScope)
             throws FuseUnavailableMountException, NativeDaemonConnectorException {
+        /*
+        ** Dead Lock between Java lock (AppFuseBridge.java) and Native lock (FuseBridgeLoop.cc)
+        **
+        **  (Thread A) Got Java lock (addBrdige) -> Try to get Native lock (native_add_brdige)
+        **  (Thread B)        Got Native lock (FuseBrdigeLoop.start) -> Try to get Java lock (onClosed)
+        **
+        ** Guarantee the lock order (native lock -> java lock) when adding Bridge.
+        */
+        native_lock();
         try {
             synchronized (this) {
                 Preconditions.checkArgument(mScopes.indexOfKey(mountScope.mountId) < 0);
@@ -73,6 +82,7 @@
                 return result;
             }
         } finally {
+            native_unlock();
             IoUtils.closeQuietly(mountScope);
         }
     }
@@ -159,4 +169,6 @@
     private native void native_delete(long loop);
     private native void native_start_loop(long loop);
     private native int native_add_bridge(long loop, int mountId, int deviceId);
+    private native void native_lock();
+    private native void native_unlock();
 }
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
index 94a2502..ed57067 100644
--- a/services/core/java/com/android/server/storage/StorageUserConnection.java
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -62,7 +62,7 @@
 public final class StorageUserConnection {
     private static final String TAG = "StorageUserConnection";
 
-    public static final int REMOTE_TIMEOUT_SECONDS = 5;
+    public static final int REMOTE_TIMEOUT_SECONDS = 20;
 
     private final Object mLock = new Object();
     private final Context mContext;
@@ -202,6 +202,7 @@
         try {
             if (!latch.await(REMOTE_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
                 // TODO(b/140025078): Call ActivityManager ANR API?
+                Slog.wtf(TAG, "Failed to bind to the ExternalStorageService for user " + mUserId);
                 throw new TimeoutException("Latch wait for " + reason + " elapsed");
             }
         } catch (InterruptedException e) {
diff --git a/services/core/jni/com_android_server_storage_AppFuseBridge.cpp b/services/core/jni/com_android_server_storage_AppFuseBridge.cpp
index e519633..20210ab 100644
--- a/services/core/jni/com_android_server_storage_AppFuseBridge.cpp
+++ b/services/core/jni/com_android_server_storage_AppFuseBridge.cpp
@@ -123,6 +123,14 @@
     return proxyFd[1].release();
 }
 
+void com_android_server_storage_AppFuseBridge_lock(JNIEnv* env, jobject self) {
+    fuse::FuseBridgeLoop::Lock();
+}
+
+void com_android_server_storage_AppFuseBridge_unlock(JNIEnv* env, jobject self) {
+    fuse::FuseBridgeLoop::Unlock();
+}
+
 const JNINativeMethod methods[] = {
     {
         "native_new",
@@ -143,6 +151,16 @@
         "native_add_bridge",
         "(JII)I",
         reinterpret_cast<void*>(com_android_server_storage_AppFuseBridge_add_bridge)
+    },
+    {
+        "native_lock",
+        "()V",
+        reinterpret_cast<void*>(com_android_server_storage_AppFuseBridge_lock)
+    },
+    {
+        "native_unlock",
+        "()V",
+        reinterpret_cast<void*>(com_android_server_storage_AppFuseBridge_unlock)
     }
 };
 
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SliceClientPermissionsTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SliceClientPermissionsTest.java
index ff2236d..4f092b9 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/SliceClientPermissionsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/SliceClientPermissionsTest.java
@@ -227,6 +227,23 @@
         assertEquivalent(client, deser);
     }
 
+    @Test(expected = XmlPullParserException.class)
+    public void testReadEmptyFile_ThrowException() throws XmlPullParserException, IOException {
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+        XmlSerializer serializer = XmlPullParserFactory.newInstance().newSerializer();
+        serializer.setOutput(output, Encoding.UTF_8.name());
+        // create empty xml document
+        serializer.startDocument(null, true);
+        serializer.endDocument();
+        serializer.flush();
+
+        ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray());
+        XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
+        parser.setInput(input, Encoding.UTF_8.name());
+        SliceClientPermissions.createFrom(parser, mock(DirtyTracker.class));
+        // Should throw exception since the xml is empty
+    }
+
     private void assertEquivalent(SliceClientPermissions o1, SliceClientPermissions o2) {
         assertEquals(o1.getPkg(), o2.getPkg());
         ArrayList<SliceAuthority> a1 = new ArrayList<>(o1.getAuthorities());
diff --git a/tests/net/java/android/net/DnsPacketTest.java b/tests/net/java/android/net/DnsPacketTest.java
deleted file mode 100644
index 975abf4..0000000
--- a/tests/net/java/android/net/DnsPacketTest.java
+++ /dev/null
@@ -1,159 +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 android.net;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Arrays;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class DnsPacketTest {
-    private void assertHeaderParses(DnsPacket.DnsHeader header, int id, int flag,
-            int qCount, int aCount, int nsCount, int arCount) {
-        assertEquals(header.id, id);
-        assertEquals(header.flags, flag);
-        assertEquals(header.getRecordCount(DnsPacket.QDSECTION), qCount);
-        assertEquals(header.getRecordCount(DnsPacket.ANSECTION), aCount);
-        assertEquals(header.getRecordCount(DnsPacket.NSSECTION), nsCount);
-        assertEquals(header.getRecordCount(DnsPacket.ARSECTION), arCount);
-    }
-
-    private void assertRecordParses(DnsPacket.DnsRecord record, String dname,
-            int dtype, int dclass, int ttl, byte[] rr) {
-        assertEquals(record.dName, dname);
-        assertEquals(record.nsType, dtype);
-        assertEquals(record.nsClass, dclass);
-        assertEquals(record.ttl, ttl);
-        assertTrue(Arrays.equals(record.getRR(), rr));
-    }
-
-    class TestDnsPacket extends DnsPacket {
-        TestDnsPacket(byte[] data) throws ParseException {
-            super(data);
-        }
-
-        public DnsHeader getHeader() {
-            return mHeader;
-        }
-        public List<DnsRecord> getRecordList(int secType) {
-            return mRecords[secType];
-        }
-    }
-
-    @Test
-    public void testNullDisallowed() {
-        try {
-            new TestDnsPacket(null);
-            fail("Exception not thrown for null byte array");
-        } catch (ParseException e) {
-        }
-    }
-
-    @Test
-    public void testV4Answer() throws Exception {
-        final byte[] v4blob = new byte[] {
-            /* Header */
-            0x55, 0x66, /* Transaction ID */
-            (byte) 0x81, (byte) 0x80, /* Flags */
-            0x00, 0x01, /* Questions */
-            0x00, 0x01, /* Answer RRs */
-            0x00, 0x00, /* Authority RRs */
-            0x00, 0x00, /* Additional RRs */
-            /* Queries */
-            0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
-            0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
-            0x00, 0x01, /* Type */
-            0x00, 0x01, /* Class */
-            /* Answers */
-            (byte) 0xc0, 0x0c, /* Name */
-            0x00, 0x01, /* Type */
-            0x00, 0x01, /* Class */
-            0x00, 0x00, 0x01, 0x2b, /* TTL */
-            0x00, 0x04, /* Data length */
-            (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 /* Address */
-        };
-        TestDnsPacket packet = new TestDnsPacket(v4blob);
-
-        // Header part
-        assertHeaderParses(packet.getHeader(), 0x5566, 0x8180, 1, 1, 0, 0);
-
-        // Record part
-        List<DnsPacket.DnsRecord> qdRecordList =
-                packet.getRecordList(DnsPacket.QDSECTION);
-        assertEquals(qdRecordList.size(), 1);
-        assertRecordParses(qdRecordList.get(0), "www.google.com", 1, 1, 0, null);
-
-        List<DnsPacket.DnsRecord> anRecordList =
-                packet.getRecordList(DnsPacket.ANSECTION);
-        assertEquals(anRecordList.size(), 1);
-        assertRecordParses(anRecordList.get(0), "www.google.com", 1, 1, 0x12b,
-                new byte[]{ (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 });
-    }
-
-    @Test
-    public void testV6Answer() throws Exception {
-        final byte[] v6blob = new byte[] {
-            /* Header */
-            0x77, 0x22, /* Transaction ID */
-            (byte) 0x81, (byte) 0x80, /* Flags */
-            0x00, 0x01, /* Questions */
-            0x00, 0x01, /* Answer RRs */
-            0x00, 0x00, /* Authority RRs */
-            0x00, 0x00, /* Additional RRs */
-            /* Queries */
-            0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
-            0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
-            0x00, 0x1c, /* Type */
-            0x00, 0x01, /* Class */
-            /* Answers */
-            (byte) 0xc0, 0x0c, /* Name */
-            0x00, 0x1c, /* Type */
-            0x00, 0x01, /* Class */
-            0x00, 0x00, 0x00, 0x37, /* TTL */
-            0x00, 0x10, /* Data length */
-            0x24, 0x04, 0x68, 0x00, 0x40, 0x05, 0x08, 0x0d,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04 /* Address */
-        };
-        TestDnsPacket packet = new TestDnsPacket(v6blob);
-
-        // Header part
-        assertHeaderParses(packet.getHeader(), 0x7722, 0x8180, 1, 1, 0, 0);
-
-        // Record part
-        List<DnsPacket.DnsRecord> qdRecordList =
-                packet.getRecordList(DnsPacket.QDSECTION);
-        assertEquals(qdRecordList.size(), 1);
-        assertRecordParses(qdRecordList.get(0), "www.google.com", 28, 1, 0, null);
-
-        List<DnsPacket.DnsRecord> anRecordList =
-                packet.getRecordList(DnsPacket.ANSECTION);
-        assertEquals(anRecordList.size(), 1);
-        assertRecordParses(anRecordList.get(0), "www.google.com", 28, 1, 0x37,
-                new byte[]{ 0x24, 0x04, 0x68, 0x00, 0x40, 0x05, 0x08, 0x0d,
-                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04 });
-    }
-}