Merge "Fixed a few bugs with remoteInput" into qt-r1-dev
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 1440803..70ee752 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -52,6 +52,7 @@
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -121,6 +122,7 @@
     protected final Context mContext;
     private final UserManager mUserManager;
     private final KeyguardManager mKeyguardManager;
+    private final StatusBarStateController mStatusBarStateController;
 
     protected RemoteInputController mRemoteInputController;
     protected NotificationLifetimeExtender.NotificationSafeToRemoveCallback
@@ -259,6 +261,7 @@
             SmartReplyController smartReplyController,
             NotificationEntryManager notificationEntryManager,
             Lazy<ShadeController> shadeController,
+            StatusBarStateController statusBarStateController,
             @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
         mContext = context;
         mLockscreenUserManager = lockscreenUserManager;
@@ -271,6 +274,7 @@
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         addLifetimeExtenders();
         mKeyguardManager = context.getSystemService(KeyguardManager.class);
+        mStatusBarStateController = statusBarStateController;
 
         notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
@@ -380,7 +384,10 @@
 
         if (!mLockscreenUserManager.shouldAllowLockscreenRemoteInput()) {
             final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
-            if (mLockscreenUserManager.isLockscreenPublicMode(userId)) {
+            if (mLockscreenUserManager.isLockscreenPublicMode(userId)
+                    || mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
+                // Even if we don't have security we should go through this flow, otherwise we won't
+                // go to the shade
                 mCallback.onLockedRemoteInput(row, view);
                 return true;
             }
@@ -391,6 +398,11 @@
             }
         }
 
+        if (!riv.isAttachedToWindow()) {
+            // the remoteInput isn't attached to the window anymore :/ Let's focus on the expanded
+            // one instead if it's available
+            riv = null;
+        }
         if (riv == null) {
             riv = findRemoteInputView(row.getPrivateLayout().getExpandedChild());
             if (riv == null) {
@@ -405,6 +417,10 @@
             return true;
         }
 
+        if (!riv.isAttachedToWindow()) {
+            // if we still didn't find a view that is attached, let's abort.
+            return false;
+        }
         int width = view.getWidth();
         if (view instanceof TextView) {
             // Center the reveal on the text which might be off-center from the TextView
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
index 6111178..b11329a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
@@ -24,6 +24,7 @@
     /**
      * Executes an action that requres the screen to be unlocked, showing the keyguard if
      * necessary. Does not close the notification shade (in case it was open).
+     * @param requiresShadeOpen does the shade need to be forced open when hiding the keyguard?
      */
-    void executeWhenUnlocked(OnDismissAction action);
+    void executeWhenUnlocked(OnDismissAction action, boolean requiresShadeOpen);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
index e541e14..834d2a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
@@ -37,7 +37,7 @@
     public KeyguardDismissUtil() {
     }
 
-    /** Sets the actual {@link DismissHandler} implementation. */
+    /** Sets the actual {@link KeyguardDismissHandler} implementation. */
     public void setDismissHandler(KeyguardDismissHandler dismissHandler) {
         mDismissHandler = dismissHandler;
     }
@@ -46,15 +46,17 @@
      * Executes an action that requires the screen to be unlocked.
      *
      * <p>Must be called after {@link #setDismissHandler}.
+     *
+     * @param requiresShadeOpen does the shade need to be forced open when hiding the keyguard?
      */
     @Override
-    public void executeWhenUnlocked(OnDismissAction action) {
+    public void executeWhenUnlocked(OnDismissAction action, boolean requiresShadeOpen) {
         KeyguardDismissHandler dismissHandler = mDismissHandler;
         if (dismissHandler == null) {
             Log.wtf(TAG, "KeyguardDismissHandler not set.");
             action.onDismiss();
             return;
         }
-        dismissHandler.executeWhenUnlocked(action);
+        dismissHandler.executeWhenUnlocked(action, requiresShadeOpen);
     }
 }
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 55f61fa..ad13b28 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -2618,8 +2618,8 @@
         }
     }
 
-    private void executeWhenUnlocked(OnDismissAction action) {
-        if (mStatusBarKeyguardViewManager.isShowing()) {
+    private void executeWhenUnlocked(OnDismissAction action, boolean requiresShadeOpen) {
+        if (mStatusBarKeyguardViewManager.isShowing() && requiresShadeOpen) {
             mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
         }
         dismissKeyguardThenExecute(action, null /* cancelAction */, false /* afterKeyguardGone */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 6691f7a..13d4b8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -48,6 +48,7 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.RemoteInputView;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -93,9 +94,11 @@
 
     @Override
     public void onStateChanged(int state) {
-        if (state == StatusBarState.SHADE && mStatusBarStateController.leaveOpenOnKeyguardHide()) {
+        boolean hasPendingRemoteInput = mPendingRemoteInputView != null;
+        if (state == StatusBarState.SHADE
+                && (mStatusBarStateController.leaveOpenOnKeyguardHide() || hasPendingRemoteInput)) {
             if (!mStatusBarStateController.isKeyguardRequested()) {
-                if (mPendingRemoteInputView != null) {
+                if (hasPendingRemoteInput) {
                     mMainHandler.post(mPendingRemoteInputView::callOnClick);
                 }
                 mPendingRemoteInputView = null;
@@ -105,7 +108,9 @@
 
     @Override
     public void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
-        mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
+        if (!row.isPinned()) {
+            mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
+        }
         mShadeController.showBouncer(true /* scrimmed */);
         mPendingRemoteInputView = clicked;
     }
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 640f0f0..282d28c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -303,7 +303,7 @@
         };
 
         OnClickListener onClickListener = view ->
-            smartReplyView.mKeyguardDismissUtil.executeWhenUnlocked(action);
+            smartReplyView.mKeyguardDismissUtil.executeWhenUnlocked(action, !entry.isRowPinned());
         if (useDelayedOnClickListener) {
             onClickListener = new DelayedOnClickListener(onClickListener,
                     smartReplyView.mConstants.getOnClickInitDelay());
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 b81e048..da25eed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -1,3 +1,4 @@
+
 package com.android.systemui.statusbar;
 
 import static junit.framework.Assert.assertEquals;
@@ -22,12 +23,14 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationRemoteInputManager.RemoteInputActiveExtender;
 import com.android.systemui.statusbar.NotificationRemoteInputManager.RemoteInputHistoryExtender;
 import com.android.systemui.statusbar.NotificationRemoteInputManager.SmartReplyHistoryExtender;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.ShadeController;
 
 import com.google.android.collect.Sets;
@@ -54,6 +57,7 @@
     @Mock private SmartReplyController mSmartReplyController;
     @Mock private NotificationListenerService.RankingMap mRanking;
     @Mock private ExpandableNotificationRow mRow;
+    @Mock private StatusBarStateController mStateController;
 
     // Dependency mocks:
     @Mock private NotificationEntryManager mEntryManager;
@@ -73,6 +77,7 @@
         mRemoteInputManager = new TestableNotificationRemoteInputManager(mContext,
                 mLockscreenUserManager, mSmartReplyController, mEntryManager,
                 () -> mock(ShadeController.class),
+                mStateController,
                 Handler.createAsync(Looper.myLooper()));
         mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
                 0, new Notification(), UserHandle.CURRENT, null, 0);
@@ -196,15 +201,15 @@
 
     private class TestableNotificationRemoteInputManager extends NotificationRemoteInputManager {
 
-
         TestableNotificationRemoteInputManager(Context context,
                 NotificationLockscreenUserManager lockscreenUserManager,
                 SmartReplyController smartReplyController,
                 NotificationEntryManager notificationEntryManager,
                 Lazy<ShadeController> shadeController,
+                StatusBarStateController statusBarStateController,
                 Handler mainHandler) {
             super(context, lockscreenUserManager, smartReplyController, notificationEntryManager,
-                    shadeController, mainHandler);
+                    shadeController, statusBarStateController, mainHandler);
         }
 
         public void setUpWithPresenterForTest(Callback callback,
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 81e373a..185723f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -38,6 +38,7 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.phone.ShadeController;
@@ -70,6 +71,7 @@
     @Mock private StatusBarNotification mSbn;
     @Mock private NotificationEntryManager mNotificationEntryManager;
     @Mock private IStatusBarService mIStatusBarService;
+    @Mock private StatusBarStateController mStatusBarStateController;
 
     @Before
     public void setUp() {
@@ -85,6 +87,7 @@
         mRemoteInputManager = new NotificationRemoteInputManager(mContext,
                 mock(NotificationLockscreenUserManager.class), mSmartReplyController,
                 mNotificationEntryManager, () -> mock(ShadeController.class),
+                mStatusBarStateController,
                 Handler.createAsync(Looper.myLooper()));
         mRemoteInputManager.setUpWithCallback(mCallback, mDelegate);
         mNotification = new Notification.Builder(mContext, "")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index 8c5fac4..0cb5754 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -109,7 +109,9 @@
         MockitoAnnotations.initMocks(this);
         mReceiver = new BlockingQueueIntentReceiver();
         mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION));
-        mDependency.get(KeyguardDismissUtil.class).setDismissHandler(action -> action.onDismiss());
+        mDependency.get(KeyguardDismissUtil.class).setDismissHandler((action, unused) -> {
+            action.onDismiss();
+        });
         mDependency.injectMockDependency(ShadeController.class);
         mDependency.injectTestDependency(ActivityStarter.class, mActivityStarter);
         mDependency.injectTestDependency(SmartReplyConstants.class, mConstants);
@@ -162,7 +164,7 @@
 
     @Test
     public void testSendSmartReply_keyguardCancelled() throws InterruptedException {
-        mDependency.get(KeyguardDismissUtil.class).setDismissHandler(action -> {});
+        mDependency.get(KeyguardDismissUtil.class).setDismissHandler((action, unused) -> {});
         setSmartReplies(TEST_CHOICES);
 
         mView.getChildAt(2).performClick();
@@ -173,7 +175,9 @@
     @Test
     public void testSendSmartReply_waitsForKeyguard() throws InterruptedException {
         AtomicReference<OnDismissAction> actionRef = new AtomicReference<>();
-        mDependency.get(KeyguardDismissUtil.class).setDismissHandler(actionRef::set);
+        mDependency.get(KeyguardDismissUtil.class).setDismissHandler((action, unused) -> {
+            actionRef.set(action);
+        });
         setSmartReplies(TEST_CHOICES);
 
         mView.getChildAt(2).performClick();