Merge "Fix performance issue caused by triggering hover focus animation accidentally" into main
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
index b8afd9d..c3efc3c 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -34,7 +34,6 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Flags;
 import com.android.launcher3.R;
-import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.BorderAnimator;
 
@@ -136,6 +135,10 @@
      * Enable or disable showing border on focus change
      */
     public void setBorderEnabled(boolean enabled) {
+        if (mBorderEnabled == enabled) {
+            return;
+        }
+
         mBorderEnabled = enabled;
         if (mFocusBorderAnimator != null) {
             mFocusBorderAnimator.setBorderVisibility(/* visible= */
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 43965b2..1e2a259 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -582,6 +582,10 @@
      * Enable or disable showing border on hover and focus change
      */
     public void setBorderEnabled(boolean enabled) {
+        if (mBorderEnabled == enabled) {
+            return;
+        }
+
         mBorderEnabled = enabled;
         // Set the animation correctly in case it misses the hover/focus event during state
         // transition
diff --git a/quickstep/tests/src/com/android/quickstep/TaskViewTest.java b/quickstep/tests/src/com/android/quickstep/TaskViewTest.java
index 8eec903..512557b 100644
--- a/quickstep/tests/src/com/android/quickstep/TaskViewTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaskViewTest.java
@@ -17,9 +17,11 @@
 package com.android.quickstep;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -34,7 +36,6 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.quickstep.util.BorderAnimator;
 import com.android.quickstep.views.TaskView;
@@ -74,6 +75,7 @@
 
     @Test
     public void notShowBorderOnBorderDisabled() {
+        presetBorderStatus(/* enabled= */ true);
         mTaskView.setBorderEnabled(/* enabled= */ false);
         MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0.0f, 0.0f, 0);
         mTaskView.onHoverEvent(MotionEvent.obtain(event));
@@ -86,7 +88,7 @@
     }
 
     @Test
-    public void showBorderOnBorderEnabled() {
+    public void showBorderOnHoverEvent() {
         mTaskView.setBorderEnabled(/* enabled= */ true);
         MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0.0f, 0.0f, 0);
         mTaskView.onHoverEvent(MotionEvent.obtain(event));
@@ -98,7 +100,18 @@
     }
 
     @Test
+    public void showBorderOnBorderEnabled() {
+        presetBorderStatus(/* enabled= */ false);
+        mTaskView.setBorderEnabled(/* enabled= */ true);
+        verify(mHoverAnimator, times(1)).setBorderVisibility(/* visible= */ true, /* animated= */
+                true);
+        verify(mFocusAnimator, times(1)).setBorderVisibility(/* visible= */ true, /* animated= */
+                true);
+    }
+
+    @Test
     public void hideBorderOnBorderDisabled() {
+        presetBorderStatus(/* enabled= */ true);
         mTaskView.setBorderEnabled(/* enabled= */ false);
         verify(mHoverAnimator, times(1)).setBorderVisibility(/* visible= */ false, /* animated= */
                 true);
@@ -107,13 +120,35 @@
     }
 
     @Test
+    public void notTriggerAnimatorWhenEnableStatusUnchanged() {
+        presetBorderStatus(/* enabled= */ false);
+        // Border is disabled by default, no animator is triggered after it is disabled again
+        mTaskView.setBorderEnabled(/* enabled= */ false);
+        verify(mHoverAnimator, never()).setBorderVisibility(/* visible= */
+                anyBoolean(), /* animated= */ anyBoolean());
+        verify(mFocusAnimator, never()).setBorderVisibility(/* visible= */
+                anyBoolean(), /* animated= */ anyBoolean());
+    }
+
+    private void presetBorderStatus(boolean enabled) {
+        // Make the task view focused and hovered
+        MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0.0f, 0.0f, 0);
+        mTaskView.onHoverEvent(MotionEvent.obtain(event));
+        mTaskView.requestFocus();
+        mTaskView.setBorderEnabled(/* enabled= */ enabled);
+        // Reset invocation count after presetting status
+        reset(mHoverAnimator);
+        reset(mFocusAnimator);
+    }
+
+    @Test
     public void notShowBorderByDefault() {
         MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0.0f, 0.0f, 0);
         mTaskView.onHoverEvent(MotionEvent.obtain(event));
-        verify(mHoverAnimator, never()).setBorderVisibility(/* visible= */ false, /* animated= */
-                true);
+        verify(mHoverAnimator, never()).setBorderVisibility(/* visible= */
+                anyBoolean(), /* animated= */ anyBoolean());
         mTaskView.onFocusChanged(true, 0, new Rect());
-        verify(mHoverAnimator, never()).setBorderVisibility(/* visible= */ false, /* animated= */
-                true);
+        verify(mHoverAnimator, never()).setBorderVisibility(/* visible= */
+                anyBoolean(), /* animated= */ anyBoolean());
     }
 }