Merge "Fixes for SyncRtSurfaceTransactionApplier" into pi-dev
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 0a667cc..a59c0f4 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -164,6 +164,7 @@
 Landroid/app/ActivityManager;->PROCESS_STATE_TOP:I
 Landroid/app/ActivityManager;->setPersistentVrThread(I)V
 Landroid/app/ActivityManager;->staticGetMemoryClass()I
+Landroid/app/ActivityManager;->switchUser(I)Z
 Landroid/app/ActivityManagerNative;-><init>()V
 Landroid/app/ActivityManagerNative;->asInterface(Landroid/os/IBinder;)Landroid/app/IActivityManager;
 Landroid/app/ActivityManagerNative;->getDefault()Landroid/app/IActivityManager;
@@ -572,6 +573,7 @@
 Landroid/app/IActivityManager$Stub$Proxy;->getProcessPss([I)[J
 Landroid/app/IActivityManager$Stub$Proxy;->isAppForeground(I)Z
 Landroid/app/IActivityManager$Stub$Proxy;->mRemote:Landroid/os/IBinder;
+Landroid/app/IActivityManager$Stub$Proxy;->setActivityController(Landroid/app/IActivityController;Z)V
 Landroid/app/IActivityManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IActivityManager;
 Landroid/app/IActivityManager;->bindService(Landroid/app/IApplicationThread;Landroid/os/IBinder;Landroid/content/Intent;Ljava/lang/String;Landroid/app/IServiceConnection;ILjava/lang/String;I)I
 Landroid/app/IActivityManager;->broadcastIntent(Landroid/app/IApplicationThread;Landroid/content/Intent;Ljava/lang/String;Landroid/content/IIntentReceiver;ILjava/lang/String;Landroid/os/Bundle;[Ljava/lang/String;ILandroid/os/Bundle;ZZI)I
@@ -895,6 +897,9 @@
 Landroid/app/SearchManager;->launchAssist(Landroid/os/Bundle;)V
 Landroid/app/SearchManager;->mSearchDialog:Landroid/app/SearchDialog;
 Landroid/app/SearchManager;->startSearch(Ljava/lang/String;ZLandroid/content/ComponentName;Landroid/os/Bundle;ZLandroid/graphics/Rect;)V
+Landroid/app/servertransaction/ClientTransaction;->mActivityCallbacks:Ljava/util/List;
+Landroid/app/servertransaction/LaunchActivityItem;->mInfo:Landroid/content/pm/ActivityInfo;
+Landroid/app/servertransaction/LaunchActivityItem;->mIntent:Landroid/content/Intent;
 Landroid/app/Service;->attach(Landroid/content/Context;Landroid/app/ActivityThread;Ljava/lang/String;Landroid/os/IBinder;Landroid/app/Application;Ljava/lang/Object;)V
 Landroid/app/Service;->mActivityManager:Landroid/app/IActivityManager;
 Landroid/app/Service;->mApplication:Landroid/app/Application;
@@ -2203,6 +2208,7 @@
 Landroid/graphics/GraphicBuffer;->CREATOR:Landroid/os/Parcelable$Creator;
 Landroid/graphics/GraphicBuffer;->mNativeObject:J
 Landroid/graphics/ImageDecoder;->postProcessAndRelease(Landroid/graphics/Canvas;)I
+Landroid/graphics/ImageFormat;->Y8:I
 Landroid/graphics/Insets;->bottom:I
 Landroid/graphics/Insets;->left:I
 Landroid/graphics/Insets;->NONE:Landroid/graphics/Insets;
@@ -4211,6 +4217,7 @@
 Landroid/os/UEventObserver$UEvent;->get(Ljava/lang/String;)Ljava/lang/String;
 Landroid/os/UEventObserver$UEvent;->get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
 Landroid/os/UEventObserver;-><init>()V
+Landroid/os/UEventObserver;->onUEvent(Landroid/os/UEventObserver$UEvent;)V
 Landroid/os/UEventObserver;->startObserving(Ljava/lang/String;)V
 Landroid/os/UEventObserver;->stopObserving()V
 Landroid/os/UpdateLock;->acquire()V
@@ -4439,9 +4446,11 @@
 Landroid/provider/Downloads$Impl;->isStatusSuccess(I)Z
 Landroid/provider/Downloads$Impl;->PUBLICLY_ACCESSIBLE_DOWNLOADS_URI:Landroid/net/Uri;
 Landroid/provider/MediaStore$Files$FileColumns;->FORMAT:Ljava/lang/String;
+Landroid/provider/MediaStore$Files$FileColumns;->STORAGE_ID:Ljava/lang/String;
 Landroid/provider/MediaStore$Files;->getMtpObjectsUri(Ljava/lang/String;)Landroid/net/Uri;
 Landroid/provider/MediaStore$Files;->getMtpObjectsUri(Ljava/lang/String;J)Landroid/net/Uri;
 Landroid/provider/MediaStore$Files;->getMtpReferencesUri(Ljava/lang/String;J)Landroid/net/Uri;
+Landroid/provider/MediaStore$MediaColumns;->IS_DRM:Ljava/lang/String;
 Landroid/provider/Settings$Bookmarks;->add(Landroid/content/ContentResolver;Landroid/content/Intent;Ljava/lang/String;Ljava/lang/String;CI)Landroid/net/Uri;
 Landroid/provider/Settings$Bookmarks;->CONTENT_URI:Landroid/net/Uri;
 Landroid/provider/Settings$ContentProviderHolder;->mContentProvider:Landroid/content/IContentProvider;
@@ -4484,6 +4493,7 @@
 Landroid/provider/Settings$Secure;->ENABLED_PRINT_SERVICES:Ljava/lang/String;
 Landroid/provider/Settings$Secure;->getIntForUser(Landroid/content/ContentResolver;Ljava/lang/String;II)I
 Landroid/provider/Settings$Secure;->getLongForUser(Landroid/content/ContentResolver;Ljava/lang/String;JI)J
+Landroid/provider/Settings$Secure;->IMMERSIVE_MODE_CONFIRMATIONS:Ljava/lang/String;
 Landroid/provider/Settings$Secure;->INCALL_POWER_BUTTON_BEHAVIOR:Ljava/lang/String;
 Landroid/provider/Settings$Secure;->LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS:Ljava/lang/String;
 Landroid/provider/Settings$Secure;->LOCK_SCREEN_LOCK_AFTER_TIMEOUT:Ljava/lang/String;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 526888d..a591eaf 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -984,6 +984,17 @@
     public static final String EXTRA_SHOW_REMOTE_INPUT_SPINNER = "android.remoteInputSpinner";
 
     /**
+     * {@link #extras} key: boolean as supplied to
+     * {@link Builder#setHideSmartReplies(boolean)}.
+     *
+     * If set to true, then any smart reply buttons will be hidden.
+     *
+     * @see Builder#setHideSmartReplies(boolean)
+     * @hide
+     */
+    public static final String EXTRA_HIDE_SMART_REPLIES = "android.hideSmartReplies";
+
+    /**
      * {@link #extras} key: this is a small piece of additional text as supplied to
      * {@link Builder#setContentInfo(CharSequence)}.
      */
@@ -3595,6 +3606,15 @@
         }
 
         /**
+         * Sets whether smart reply buttons should be hidden.
+         * @hide
+         */
+        public Builder setHideSmartReplies(boolean hideSmartReplies) {
+            mN.extras.putBoolean(EXTRA_HIDE_SMART_REPLIES, hideSmartReplies);
+            return this;
+        }
+
+        /**
          * Sets the number of items this notification represents. May be displayed as a badge count
          * for Launchers that support badging.
          */
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 1f00c78..02bf4e3 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -1584,6 +1584,20 @@
      */
     public static final int BUFFER_FLAG_PARTIAL_FRAME = 8;
 
+    /**
+     * This indicates that the buffer contains non-media data for the
+     * muxer to process.
+     *
+     * All muxer data should start with a FOURCC header that determines the type of data.
+     *
+     * For example, when it contains Exif data sent to a MediaMuxer track of
+     * {@link MediaFormat#MIMETYPE_IMAGE_ANDROID_HEIC} type, the data must start with
+     * Exif header ("Exif\0\0"), followed by the TIFF header (See JEITA CP-3451C Section 4.5.2.)
+     *
+     * @hide
+     */
+    public static final int BUFFER_FLAG_MUXER_DATA = 16;
+
     /** @hide */
     @IntDef(
         flag = true,
@@ -1593,6 +1607,7 @@
             BUFFER_FLAG_CODEC_CONFIG,
             BUFFER_FLAG_END_OF_STREAM,
             BUFFER_FLAG_PARTIAL_FRAME,
+            BUFFER_FLAG_MUXER_DATA,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface BufferFlag {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 724bd22..952c961 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -1384,6 +1384,13 @@
             smartReplyContainer.setVisibility(View.GONE);
             return null;
         }
+        // If we are keeping the notification around while sending we don't want to add the buttons.
+        boolean hideSmartReplies = entry.notification.getNotification()
+                .extras.getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false);
+        if (hideSmartReplies) {
+            smartReplyContainer.setVisibility(View.GONE);
+            return null;
+        }
         SmartReplyView smartReplyView = null;
         if (smartReplyContainer.getChildCount() == 0) {
             smartReplyView = SmartReplyView.inflate(mContext, smartReplyContainer);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
index f14ca71..30fa0c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
@@ -113,6 +113,8 @@
             Dependency.get(ForegroundServiceController.class);
     protected final NotificationListener mNotificationListener =
             Dependency.get(NotificationListener.class);
+    private final SmartReplyController mSmartReplyController =
+            Dependency.get(SmartReplyController.class);
 
     protected IStatusBarService mBarService;
     protected NotificationPresenter mPresenter;
@@ -127,6 +129,13 @@
     protected boolean mDisableNotificationAlerts;
     protected NotificationListContainer mListContainer;
     private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
+    /**
+     * Notifications with keys in this set are not actually around anymore. We kept them around
+     * when they were canceled in response to a remote input interaction. This allows us to show
+     * what you replied and allows you to continue typing into it.
+     */
+    private final ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
+
 
     private final class NotificationClicker implements View.OnClickListener {
 
@@ -220,6 +229,8 @@
         }
         pw.print("  mUseHeadsUp=");
         pw.println(mUseHeadsUp);
+        pw.print("  mKeysKeptForRemoteInput: ");
+        pw.println(mKeysKeptForRemoteInput);
     }
 
     public NotificationEntryManager(Context context) {
@@ -374,6 +385,12 @@
         final NotificationVisibility nv = NotificationVisibility.obtain(n.getKey(), rank, count,
                 true);
         NotificationData.Entry entry = mNotificationData.get(n.getKey());
+
+        if (FORCE_REMOTE_INPUT_HISTORY
+                && mKeysKeptForRemoteInput.contains(n.getKey())) {
+            mKeysKeptForRemoteInput.remove(n.getKey());
+        }
+
         mRemoteInputManager.onPerformRemoveNotification(n, entry);
         final String pkg = n.getPackageName();
         final String tag = n.getTag();
@@ -491,10 +508,35 @@
             }
             if (updated) {
                 Log.w(TAG, "Keeping notification around after sending remote input "+ entry.key);
-                mRemoteInputManager.getKeysKeptForRemoteInput().add(entry.key);
+                addKeyKeptForRemoteInput(entry.key);
                 return;
             }
         }
+
+        if (FORCE_REMOTE_INPUT_HISTORY
+                && shouldKeepForSmartReply(entry)
+                && entry.row != null && !entry.row.isDismissed()) {
+            // Turn off the spinner and hide buttons when an app cancels the notification.
+            StatusBarNotification newSbn = rebuildNotificationForCanceledSmartReplies(entry);
+            boolean updated = false;
+            try {
+                updateNotificationInternal(newSbn, null);
+                updated = true;
+            } catch (InflationException e) {
+                // Ignore just don't keep the notification around.
+            }
+            // Treat the reply as longer sending.
+            mSmartReplyController.stopSending(entry);
+            if (updated) {
+                Log.w(TAG, "Keeping notification around after sending smart reply " + entry.key);
+                addKeyKeptForRemoteInput(entry.key);
+                return;
+            }
+        }
+
+        // Actually removing notification so smart reply controller can forget about it.
+        mSmartReplyController.stopSending(entry);
+
         if (deferRemoval) {
             mLatestRankingMap = ranking;
             mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key));
@@ -536,18 +578,21 @@
 
         Notification.Builder b = Notification.Builder
                 .recoverBuilder(mContext, sbn.getNotification().clone());
-        CharSequence[] oldHistory = sbn.getNotification().extras
-                .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY);
-        CharSequence[] newHistory;
-        if (oldHistory == null) {
-            newHistory = new CharSequence[1];
-        } else {
-            newHistory = new CharSequence[oldHistory.length + 1];
-            System.arraycopy(oldHistory, 0, newHistory, 1, oldHistory.length);
+        if (remoteInputText != null) {
+            CharSequence[] oldHistory = sbn.getNotification().extras
+                    .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY);
+            CharSequence[] newHistory;
+            if (oldHistory == null) {
+                newHistory = new CharSequence[1];
+            } else {
+                newHistory = new CharSequence[oldHistory.length + 1];
+                System.arraycopy(oldHistory, 0, newHistory, 1, oldHistory.length);
+            }
+            newHistory[0] = String.valueOf(remoteInputText);
+            b.setRemoteInputHistory(newHistory);
         }
-        newHistory[0] = String.valueOf(remoteInputText);
-        b.setRemoteInputHistory(newHistory);
         b.setShowRemoteInputSpinner(showSpinner);
+        b.setHideSmartReplies(true);
 
         Notification newNotification = b.build();
 
@@ -563,6 +608,17 @@
         return newSbn;
     }
 
+    @VisibleForTesting
+    StatusBarNotification rebuildNotificationForCanceledSmartReplies(
+            NotificationData.Entry entry) {
+        return rebuildNotificationWithRemoteInput(entry, null /* remoteInputTest */,
+                false /* showSpinner */);
+    }
+
+    private boolean shouldKeepForSmartReply(NotificationData.Entry entry) {
+        return entry != null && mSmartReplyController.isSendingSmartReply(entry.key);
+    }
+
     private boolean shouldKeepForRemoteInput(NotificationData.Entry entry) {
         if (entry == null) {
             return false;
@@ -792,6 +848,7 @@
         }
         mHeadsUpEntriesToRemoveOnSwitch.remove(entry);
         mRemoteInputManager.onUpdateNotification(entry);
+        mSmartReplyController.stopSending(entry);
 
         if (key.equals(mGutsManager.getKeyToRemoveOnGutsClosed())) {
             mGutsManager.setKeyToRemoveOnGutsClosed(null);
@@ -955,6 +1012,20 @@
         return mHeadsUpManager.isHeadsUp(key);
     }
 
+    public boolean isNotificationKeptForRemoteInput(String key) {
+        return mKeysKeptForRemoteInput.contains(key);
+    }
+
+    public void removeKeyKeptForRemoteInput(String key) {
+        mKeysKeptForRemoteInput.remove(key);
+    }
+
+    public void addKeyKeptForRemoteInput(String key) {
+        if (FORCE_REMOTE_INPUT_HISTORY) {
+            mKeysKeptForRemoteInput.add(key);
+        }
+    }
+
     /**
      * Callback for NotificationEntryManager.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index 0144f42..a2d0c2b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -75,7 +75,7 @@
             mPresenter.getHandler().post(() -> {
                 processForRemoteInput(sbn.getNotification(), mContext);
                 String key = sbn.getKey();
-                mRemoteInputManager.getKeysKeptForRemoteInput().remove(key);
+                mEntryManager.removeKeyKeptForRemoteInput(key);
                 boolean isUpdate =
                         mEntryManager.getNotificationData().get(key) != null;
                 // In case we don't allow child notifications, we ignore children of
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index a333654..9e87a0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -77,12 +77,6 @@
     protected final NotificationLockscreenUserManager mLockscreenUserManager =
             Dependency.get(NotificationLockscreenUserManager.class);
 
-    /**
-     * Notifications with keys in this set are not actually around anymore. We kept them around
-     * when they were canceled in response to a remote input interaction. This allows us to show
-     * what you replied and allows you to continue typing into it.
-     */
-    protected final ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
     protected final Context mContext;
     private final UserManager mUserManager;
 
@@ -290,7 +284,8 @@
         mRemoteInputController.addCallback(new RemoteInputController.Callback() {
             @Override
             public void onRemoteInputSent(NotificationData.Entry entry) {
-                if (FORCE_REMOTE_INPUT_HISTORY && mKeysKeptForRemoteInput.contains(entry.key)) {
+                if (FORCE_REMOTE_INPUT_HISTORY
+                        && mEntryManager.isNotificationKeptForRemoteInput(entry.key)) {
                     mEntryManager.removeNotification(entry.key, null);
                 } else if (mRemoteInputEntriesToRemoveOnCollapse.contains(entry)) {
                     // We're currently holding onto this notification, but from the apps point of
@@ -340,10 +335,6 @@
         if (mRemoteInputController.isRemoteInputActive(entry)) {
             mRemoteInputController.removeRemoteInput(entry, null);
         }
-        if (FORCE_REMOTE_INPUT_HISTORY
-                && mKeysKeptForRemoteInput.contains(n.getKey())) {
-            mKeysKeptForRemoteInput.remove(n.getKey());
-        }
     }
 
     public void removeRemoteInputEntriesKeptUntilCollapsed() {
@@ -368,8 +359,6 @@
         pw.println("NotificationRemoteInputManager state:");
         pw.print("  mRemoteInputEntriesToRemoveOnCollapse: ");
         pw.println(mRemoteInputEntriesToRemoveOnCollapse);
-        pw.print("  mKeysKeptForRemoteInput: ");
-        pw.println(mKeysKeptForRemoteInput);
     }
 
     public void bindRow(ExpandableNotificationRow row) {
@@ -377,10 +366,6 @@
         row.setRemoteViewClickHandler(mOnClickHandler);
     }
 
-    public Set<String> getKeysKeptForRemoteInput() {
-        return mKeysKeptForRemoteInput;
-    }
-
     @VisibleForTesting
     public Set<NotificationData.Entry> getRemoteInputEntriesToRemoveOnCollapse() {
         return mRemoteInputEntriesToRemoveOnCollapse;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
index 67da68c..5ba75de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
@@ -17,10 +17,12 @@
 
 import android.os.RemoteException;
 import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
 
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.Dependency;
 
+import java.util.Set;
 
 /**
  * Handles when smart replies are added to a notification
@@ -28,18 +30,20 @@
  */
 public class SmartReplyController {
     private IStatusBarService mBarService;
-    private NotificationEntryManager mNotificationEntryManager;
+    private Set<String> mSendingKeys = new ArraySet<>();
 
     public SmartReplyController() {
         mBarService = Dependency.get(IStatusBarService.class);
-        mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
     }
 
     public void smartReplySent(NotificationData.Entry entry, int replyIndex, CharSequence reply) {
+        NotificationEntryManager notificationEntryManager
+                = Dependency.get(NotificationEntryManager.class);
         StatusBarNotification newSbn =
-                mNotificationEntryManager.rebuildNotificationWithRemoteInput(entry, reply,
+                notificationEntryManager.rebuildNotificationWithRemoteInput(entry, reply,
                         true /* showSpinner */);
-        mNotificationEntryManager.updateNotification(newSbn, null /* ranking */);
+        notificationEntryManager.updateNotification(newSbn, null /* ranking */);
+        mSendingKeys.add(entry.key);
 
         try {
             mBarService.onNotificationSmartReplySent(entry.notification.getKey(),
@@ -49,6 +53,14 @@
         }
     }
 
+    /**
+     * Have we posted an intent to an app about sending a smart reply from the
+     * notification with this key.
+     */
+    public boolean isSendingSmartReply(String key) {
+        return mSendingKeys.contains(key);
+    }
+
     public void smartRepliesAdded(final NotificationData.Entry entry, int replyCount) {
         try {
             mBarService.onNotificationSmartRepliesAdded(entry.notification.getKey(),
@@ -57,4 +69,10 @@
             // Nothing to do, system going down
         }
     }
+
+    public void stopSending(final NotificationData.Entry entry) {
+        if (entry != null) {
+            mSendingKeys.remove(entry.notification.getKey());
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index ee83250..f7b7eeb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -165,7 +165,9 @@
                 showNotificationIconArea(animate);
             }
         }
-        if ((diff1 & DISABLE_CLOCK) != 0) {
+        // The clock may have already been hidden, but we might want to shift its
+        // visibility to GONE from INVISIBLE or vice versa
+        if ((diff1 & DISABLE_CLOCK) != 0 || mClockView.getVisibility() != clockHiddenMode()) {
             if ((state1 & DISABLE_CLOCK) != 0) {
                 hideClock(animate);
             } else {
@@ -212,13 +214,24 @@
     }
 
     public void hideClock(boolean animate) {
-        animateHiddenState(mClockView, View.GONE, animate);
+        animateHiddenState(mClockView, clockHiddenMode(), animate);
     }
 
     public void showClock(boolean animate) {
         animateShow(mClockView, animate);
     }
 
+    /**
+     * If panel is expanded/expanding it usually means QS shade is opening, so
+     * don't set the clock GONE otherwise it'll mess up the animation.
+     */
+    private int clockHiddenMode() {
+        if (!mStatusBar.isClosed() && !mKeyguardMonitor.isShowing()) {
+            return View.INVISIBLE;
+        }
+        return View.GONE;
+    }
+
     public void hideNotificationIconArea(boolean animate) {
         animateHide(mNotificationIconAreaInner, animate);
     }
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 d5d87cc..2a1db4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -5161,8 +5161,7 @@
                     removeNotification(parentToCancelFinal);
                 }
                 if (shouldAutoCancel(sbn)
-                        || mRemoteInputManager.getKeysKeptForRemoteInput().contains(
-                                notificationKey)) {
+                        || mEntryManager.isNotificationKeptForRemoteInput(notificationKey)) {
                     // Automatically remove all notifications that we may have kept around longer
                     removeNotification(sbn);
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index cc802a8..585787e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -207,6 +207,7 @@
         b.setText(choice);
 
         OnDismissAction action = () -> {
+            smartReplyController.smartReplySent(entry, replyIndex, b.getText());
             Bundle results = new Bundle();
             results.putString(remoteInput.getResultKey(), choice.toString());
             Intent intent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@@ -217,7 +218,6 @@
             } catch (PendingIntent.CanceledException e) {
                 Log.w(TAG, "Unable to send smart reply", e);
             }
-            smartReplyController.smartReplySent(entry, replyIndex, b.getText());
             mSmartReplyContainer.setVisibility(View.GONE);
             return false; // do not defer
         };
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java
index f05cf6b..afe16cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java
@@ -19,6 +19,7 @@
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.assertFalse;
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
@@ -97,6 +98,7 @@
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
     @Mock private VisualStabilityManager mVisualStabilityManager;
     @Mock private MetricsLogger mMetricsLogger;
+    @Mock private SmartReplyController mSmartReplyController;
 
     private NotificationData.Entry mEntry;
     private StatusBarNotification mSbn;
@@ -158,6 +160,7 @@
                 mDeviceProvisionedController);
         mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager);
         mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
+        mDependency.injectTestDependency(SmartReplyController.class, mSmartReplyController);
 
         mCountDownLatch = new CountDownLatch(1);
 
@@ -262,6 +265,7 @@
 
         verify(mMediaManager).onNotificationRemoved(mSbn.getKey());
         verify(mRemoteInputManager).onRemoveNotification(mEntry);
+        verify(mSmartReplyController).stopSending(mEntry);
         verify(mForegroundServiceController).removeNotification(mSbn);
         verify(mListContainer).cleanUpViewState(mRow);
         verify(mPresenter).updateNotificationViews();
@@ -272,6 +276,20 @@
     }
 
     @Test
+    public void testRemoveNotification_blockedBySendingSmartReply() throws Exception {
+        com.android.systemui.util.Assert.isNotMainThread();
+
+        mEntry.row = mRow;
+        mEntryManager.getNotificationData().add(mEntry);
+        when(mSmartReplyController.isSendingSmartReply(mEntry.key)).thenReturn(true);
+
+        mEntryManager.removeNotification(mSbn.getKey(), mRankingMap);
+
+        assertNotNull(mEntryManager.getNotificationData().get(mSbn.getKey()));
+        assertTrue(mEntryManager.isNotificationKeptForRemoteInput(mEntry.key));
+    }
+
+    @Test
     public void testUpdateAppOps_foregroundNoti() {
         com.android.systemui.util.Assert.isNotMainThread();
 
@@ -365,6 +383,8 @@
         Assert.assertEquals("A Reply", messages[0]);
         Assert.assertFalse(newSbn.getNotification().extras
                 .getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false));
+        Assert.assertTrue(newSbn.getNotification().extras
+                .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false));
     }
 
     @Test
@@ -377,6 +397,8 @@
         Assert.assertEquals("A Reply", messages[0]);
         Assert.assertTrue(newSbn.getNotification().extras
                 .getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false));
+        Assert.assertTrue(newSbn.getNotification().extras
+                .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false));
     }
 
     @Test
@@ -394,4 +416,15 @@
         Assert.assertEquals("Reply 2", messages[0]);
         Assert.assertEquals("A Reply", messages[1]);
     }
+
+    @Test
+    public void testRebuildNotificationForCanceledSmartReplies() {
+        // Try rebuilding to remove spinner and hide buttons.
+        StatusBarNotification newSbn =
+                mEntryManager.rebuildNotificationForCanceledSmartReplies(mEntry);
+        Assert.assertFalse(newSbn.getNotification().extras
+                .getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false));
+        Assert.assertTrue(newSbn.getNotification().extras
+                .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false));
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
index c6397e6..26f91b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -60,7 +60,6 @@
 
     private NotificationListener mListener;
     private StatusBarNotification mSbn;
-    private Set<String> mKeysKeptForRemoteInput;
 
     @Before
     public void setUp() {
@@ -69,11 +68,8 @@
         mDependency.injectTestDependency(NotificationRemoteInputManager.class,
                 mRemoteInputManager);
 
-        mKeysKeptForRemoteInput = new HashSet<>();
-
         when(mPresenter.getHandler()).thenReturn(Handler.createAsync(Looper.myLooper()));
         when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
-        when(mRemoteInputManager.getKeysKeptForRemoteInput()).thenReturn(mKeysKeptForRemoteInput);
 
         mListener = new NotificationListener(mContext);
         mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
@@ -91,10 +87,9 @@
 
     @Test
     public void testPostNotificationRemovesKeyKeptForRemoteInput() {
-        mKeysKeptForRemoteInput.add(mSbn.getKey());
         mListener.onNotificationPosted(mSbn, mRanking);
         TestableLooper.get(this).processAllMessages();
-        assertTrue(mKeysKeptForRemoteInput.isEmpty());
+        verify(mEntryManager).removeKeyKeptForRemoteInput(mSbn.getKey());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index 8b2f6cd..7a2cb3a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -86,11 +86,9 @@
     @Test
     public void testPerformOnRemoveNotification() {
         when(mController.isRemoteInputActive(mEntry)).thenReturn(true);
-        mRemoteInputManager.getKeysKeptForRemoteInput().add(mEntry.key);
         mRemoteInputManager.onPerformRemoveNotification(mSbn, mEntry);
 
         verify(mController).removeRemoteInput(mEntry, null);
-        assertTrue(mRemoteInputManager.getKeysKeptForRemoteInput().isEmpty());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
index 84dceae..e91530d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -14,6 +14,8 @@
 
 package com.android.systemui.statusbar;
 
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.isNull;
@@ -74,7 +76,7 @@
     }
 
     @Test
-    public void testSendSmartReply_updatesRemoteInput() throws RemoteException {
+    public void testSendSmartReply_updatesRemoteInput() {
         StatusBarNotification sbn = mock(StatusBarNotification.class);
         when(sbn.getKey()).thenReturn(TEST_NOTIFICATION_KEY);
         when(mNotificationEntryManager.rebuildNotificationWithRemoteInput(
@@ -118,4 +120,21 @@
         verify(mIStatusBarService).onNotificationSmartRepliesAdded(TEST_NOTIFICATION_KEY,
                 TEST_CHOICE_COUNT);
     }
+
+    @Test
+    public void testSendSmartReply_reportsSending() {
+        SmartReplyController controller = new SmartReplyController();
+        controller.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT);
+
+        assertTrue(controller.isSendingSmartReply(TEST_NOTIFICATION_KEY));
+    }
+
+    @Test
+    public void testSendingSmartReply_afterRemove_shouldReturnFalse() {
+        SmartReplyController controller = new SmartReplyController();
+        controller.isSendingSmartReply(TEST_NOTIFICATION_KEY);
+        controller.stopSending(mEntry);
+
+        assertFalse(controller.isSendingSmartReply(TEST_NOTIFICATION_KEY));
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 6f572df..4c2a940 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -64,6 +64,7 @@
 import com.android.internal.util.FastPrintWriter;
 import com.android.server.AppStateTracker;
 import com.android.server.LocalServices;
+import com.android.server.SystemService;
 import com.android.server.am.ActivityManagerService.ItemMatcher;
 import com.android.server.am.ActivityManagerService.NeededUriGrants;
 
@@ -2012,6 +2013,25 @@
                 + why + " of " + r + " in app " + r.app);
         else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING, ">>> EXECUTING "
                 + why + " of " + r.shortName);
+
+        // For b/34123235: Services within the system server won't start until SystemServer
+        // does Looper.loop(), so we shouldn't try to start/bind to them too early in the boot
+        // process. However, since there's a little point of showing the ANR dialog in that case,
+        // let's suppress the timeout until PHASE_THIRD_PARTY_APPS_CAN_START.
+        //
+        // (Note there are multiple services start at PHASE_THIRD_PARTY_APPS_CAN_START too,
+        // which technically could also trigger this timeout if there's a system server
+        // that takes a long time to handle PHASE_THIRD_PARTY_APPS_CAN_START, but that shouldn't
+        // happen.)
+        boolean timeoutNeeded = true;
+        if ((mAm.mBootPhase < SystemService.PHASE_THIRD_PARTY_APPS_CAN_START)
+                && (r.app != null) && (r.app.pid == android.os.Process.myPid())) {
+
+            Slog.w(TAG, "Too early to start/bind service in system_server: Phase=" + mAm.mBootPhase
+                    + " " + r.getComponentName());
+            timeoutNeeded = false;
+        }
+
         long now = SystemClock.uptimeMillis();
         if (r.executeNesting == 0) {
             r.executeFg = fg;
@@ -2022,13 +2042,15 @@
             if (r.app != null) {
                 r.app.executingServices.add(r);
                 r.app.execServicesFg |= fg;
-                if (r.app.executingServices.size() == 1) {
+                if (timeoutNeeded && r.app.executingServices.size() == 1) {
                     scheduleServiceTimeoutLocked(r.app);
                 }
             }
         } else if (r.app != null && fg && !r.app.execServicesFg) {
             r.app.execServicesFg = true;
-            scheduleServiceTimeoutLocked(r.app);
+            if (timeoutNeeded) {
+                scheduleServiceTimeoutLocked(r.app);
+            }
         }
         r.executeFg |= fg;
         r.executeNesting++;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 70648c6..113f452 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1850,6 +1850,11 @@
      */
     boolean mBooted = false;
 
+    /**
+     * Current boot phase.
+     */
+    int mBootPhase;
+
     WindowManagerService mWindowManager;
     final ActivityThread mSystemThread;
 
@@ -2881,6 +2886,7 @@
 
         @Override
         public void onBootPhase(int phase) {
+            mService.mBootPhase = phase;
             if (phase == PHASE_SYSTEM_SERVICES_READY) {
                 mService.mBatteryStatsService.systemServicesReady();
                 mService.mServices.systemServicesReady();
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index 5764382..ddf9552 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -132,6 +132,8 @@
         if (showingChanged) {
             dismissDockedStackIfNeeded();
             setKeyguardGoingAway(false);
+            mWindowManager.setKeyguardOrAodShowingOnDefaultDisplay(
+                    isKeyguardOrAodShowing(DEFAULT_DISPLAY));
             if (keyguardShowing) {
                 mDismissalRequested = false;
             }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index fe2fd532..42215c9 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -5082,7 +5082,7 @@
         final int fl = PolicyControl.getWindowFlags(win, attrs);
         final int pfl = attrs.privateFlags;
         final int sim = attrs.softInputMode;
-        final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(win, null);
+        final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
         final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
 
         final Rect pf = mTmpParentFrame;
diff --git a/services/core/java/com/android/server/policy/PolicyControl.java b/services/core/java/com/android/server/policy/PolicyControl.java
index 3f26d86..48e72bc 100644
--- a/services/core/java/com/android/server/policy/PolicyControl.java
+++ b/services/core/java/com/android/server/policy/PolicyControl.java
@@ -65,7 +65,8 @@
 
     public static int getSystemUiVisibility(WindowState win, LayoutParams attrs) {
         attrs = attrs != null ? attrs : win.getAttrs();
-        int vis = win != null ? win.getSystemUiVisibility() : attrs.systemUiVisibility;
+        int vis = win != null ? win.getSystemUiVisibility()
+                : (attrs.systemUiVisibility | attrs.subtreeSystemUiVisibility);
         if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
             vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                     | View.SYSTEM_UI_FLAG_FULLSCREEN
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 39a3629..cd8d677 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -692,7 +692,7 @@
 
         // Do not minimize when dock is already minimized while keyguard is showing and not
         // occluded such as unlocking the screen
-        if (mMinimizedDock && mService.mPolicy.isKeyguardShowingAndNotOccluded()) {
+        if (mMinimizedDock && mService.mKeyguardOrAodShowingOnDefaultDisplay) {
             return;
         }
         final TaskStack topSecondaryStack = mDisplayContent.getTopStackInWindowingMode(
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 16399008..cb64142 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -369,7 +369,10 @@
     final WindowTracing mWindowTracing;
 
     final private KeyguardDisableHandler mKeyguardDisableHandler;
+    // TODO: eventually unify all keyguard state in a common place instead of having it spread over
+    // AM's KeyguardController and the policy's KeyguardServiceDelegate.
     boolean mKeyguardGoingAway;
+    boolean mKeyguardOrAodShowingOnDefaultDisplay;
     // VR Vr2d Display Id.
     int mVr2dDisplayId = INVALID_DISPLAY;
 
@@ -2909,6 +2912,12 @@
         }
     }
 
+    public void setKeyguardOrAodShowingOnDefaultDisplay(boolean showing) {
+        synchronized (mWindowMap) {
+            mKeyguardOrAodShowingOnDefaultDisplay = showing;
+        }
+    }
+
     // -------------------------------------------------------------
     // Misc IWindowSession methods
     // -------------------------------------------------------------
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 91c449b..4e12daf 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -409,7 +409,7 @@
 
     final Rect mContainingFrame = new Rect();
 
-    private final Rect mParentFrame = new Rect();
+    final Rect mParentFrame = new Rect();
 
     /** Whether the parent frame would have been different if there was no display cutout. */
     private boolean mParentFrameWasClippedByDisplayCutout;
@@ -931,6 +931,17 @@
                     mContainingFrame.set(contentFrame);
                 }
             }
+
+            final TaskStack stack = getStack();
+            if (inPinnedWindowingMode() && stack != null
+                    && stack.lastAnimatingBoundsWasToFullscreen()) {
+                // PIP edge case: When going from pinned to fullscreen, we apply a
+                // tempInsetFrame for the full task - but we're still at the start of the animation.
+                // To prevent a jump if there's a letterbox, restrict to the parent frame.
+                mInsetFrame.intersectUnchecked(parentFrame);
+                mContainingFrame.intersectUnchecked(parentFrame);
+            }
+
             mDisplayFrame.set(mContainingFrame);
             layoutXDiff = !mInsetFrame.isEmpty() ? mInsetFrame.left - mContainingFrame.left : 0;
             layoutYDiff = !mInsetFrame.isEmpty() ? mInsetFrame.top - mContainingFrame.top : 0;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 4a6587b..c44a582 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -927,6 +927,13 @@
                 mTmpSourceBounds.inset(mWin.mLastRelayoutContentInsets);
                 allowStretching = true;
             }
+
+            // Make sure that what we're animating to and from is actually the right size in case
+            // the window cannot take up the full screen.
+            mTmpStackBounds.intersectUnchecked(w.mParentFrame);
+            mTmpSourceBounds.intersectUnchecked(w.mParentFrame);
+            mTmpAnimatingBounds.intersectUnchecked(w.mParentFrame);
+
             if (!mTmpSourceBounds.isEmpty()) {
                 // Get the final target stack bounds, if we are not animating, this is just the
                 // current stack bounds