diff options
| -rw-r--r-- | core/java/android/view/View.java | 17 | ||||
| -rw-r--r-- | core/java/android/view/ViewRootImpl.java | 13 | ||||
| -rw-r--r-- | core/java/android/view/ViewRootRectTracker.java | 21 | ||||
| -rw-r--r-- | core/java/android/window/flags/windowing_frontend.aconfig | 11 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/view/ViewRootRectTrackerTest.java | 70 |
5 files changed, 123 insertions, 9 deletions
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 0866e0d832b1..c048d7987515 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -66,6 +66,7 @@ import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFI import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION; import static com.android.window.flags.Flags.FLAG_DELEGATE_UNHANDLED_DRAGS; import static com.android.window.flags.Flags.FLAG_SUPPORTS_DRAG_ASSISTANT_TO_MULTIWINDOW; +import static com.android.window.flags.Flags.reduceChangedExclusionRectsMsgs; import static java.lang.Math.max; @@ -247,6 +248,7 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; @@ -12888,15 +12890,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (rects.isEmpty() && mListenerInfo == null) return; final ListenerInfo info = getListenerInfo(); + final boolean rectsChanged = !reduceChangedExclusionRectsMsgs() + || !Objects.equals(info.mSystemGestureExclusionRects, rects); if (info.mSystemGestureExclusionRects != null) { - info.mSystemGestureExclusionRects.clear(); - info.mSystemGestureExclusionRects.addAll(rects); + if (rectsChanged) { + info.mSystemGestureExclusionRects.clear(); + info.mSystemGestureExclusionRects.addAll(rects); + } } else { info.mSystemGestureExclusionRects = new ArrayList<>(rects); } - - updatePositionUpdateListener(); - postUpdate(this::updateSystemGestureExclusionRects); + if (rectsChanged) { + updatePositionUpdateListener(); + postUpdate(this::updateSystemGestureExclusionRects); + } } private void updatePositionUpdateListener() { diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 23c43f56f2bc..f1074ac0c188 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -133,6 +133,7 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility.PACK import static com.android.text.flags.Flags.disableHandwritingInitiatorForIme; import static com.android.window.flags.Flags.enableBufferTransformHintFromDisplay; import static com.android.window.flags.Flags.predictiveBackSwipeEdgeNoneApi; +import static com.android.window.flags.Flags.reduceChangedExclusionRectsMsgs; import static com.android.window.flags.Flags.setScPropertiesInClient; import android.Manifest; @@ -6027,8 +6028,12 @@ public final class ViewRootImpl implements ViewParent, } void updateSystemGestureExclusionRectsForView(View view) { + boolean msgInQueue = reduceChangedExclusionRectsMsgs() + && mGestureExclusionTracker.isWaitingForComputeChanges(); mGestureExclusionTracker.updateRectsForView(view); - mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED); + if (!msgInQueue) { + mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED); + } } void systemGestureExclusionChanged() { @@ -6072,8 +6077,12 @@ public final class ViewRootImpl implements ViewParent, * the root's view hierarchy. */ public void setRootSystemGestureExclusionRects(@NonNull List<Rect> rects) { + boolean msgInQueue = reduceChangedExclusionRectsMsgs() + && mGestureExclusionTracker.isWaitingForComputeChanges(); mGestureExclusionTracker.setRootRects(rects); - mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED); + if (!msgInQueue) { + mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED); + } } /** diff --git a/core/java/android/view/ViewRootRectTracker.java b/core/java/android/view/ViewRootRectTracker.java index 152729b8d1d8..0bef3255f1dc 100644 --- a/core/java/android/view/ViewRootRectTracker.java +++ b/core/java/android/view/ViewRootRectTracker.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Rect; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.lang.ref.WeakReference; @@ -32,8 +33,10 @@ import java.util.function.Function; /** * Abstract class to track a collection of rects reported by the views under the same * {@link ViewRootImpl}. + * @hide */ -class ViewRootRectTracker { +@VisibleForTesting +public class ViewRootRectTracker { private final Function<View, List<Rect>> mRectCollector; private boolean mViewsChanged = false; private boolean mRootRectsChanged = false; @@ -41,11 +44,18 @@ class ViewRootRectTracker { private List<ViewInfo> mViewInfos = new ArrayList<>(); private List<Rect> mRects = Collections.emptyList(); + // Keeps track of whether updateRectsForView has been called but there was no subsequent call + // on computeChanges yet. Since updateRectsForView is called when sending a message and + // computeChanges when it is received, this tracks whether such message is in the queue already + private boolean mWaitingForComputeChanges = false; + /** * @param rectCollector given a view returns a list of the rects of interest for this * ViewRootRectTracker + * @hide */ - ViewRootRectTracker(Function<View, List<Rect>> rectCollector) { + @VisibleForTesting + public ViewRootRectTracker(Function<View, List<Rect>> rectCollector) { mRectCollector = rectCollector; } @@ -70,6 +80,7 @@ class ViewRootRectTracker { mViewInfos.add(new ViewInfo(view)); mViewsChanged = true; } + mWaitingForComputeChanges = true; } /** @@ -92,6 +103,7 @@ class ViewRootRectTracker { * @return {@code true} if there were changes, {@code false} otherwise. */ public boolean computeChanges() { + mWaitingForComputeChanges = false; boolean changed = mRootRectsChanged; final Iterator<ViewInfo> i = mViewInfos.iterator(); final List<Rect> rects = new ArrayList<>(mRootRects); @@ -121,6 +133,10 @@ class ViewRootRectTracker { return false; } + public boolean isWaitingForComputeChanges() { + return mWaitingForComputeChanges; + } + /** * Returns a List of all Rects from all visible Views in the global (root) coordinate system. * This list is only updated when calling {@link #computeChanges()} or @@ -140,6 +156,7 @@ class ViewRootRectTracker { Preconditions.checkNotNull(rects, "rects must not be null"); mRootRects = rects; mRootRectsChanged = true; + mWaitingForComputeChanges = true; } @NonNull diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig index 9f6ea42c6fc4..2d0a1a7dbd00 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -417,6 +417,17 @@ flag { } flag { + name: "reduce_changed_exclusion_rects_msgs" + namespace: "windowing_frontend" + description: "Don't send MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED when there is no change" + bug: "388231176" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "keep_app_window_hide_while_locked" namespace: "windowing_frontend" description: "Do not let app window visible while device is locked" diff --git a/core/tests/coretests/src/android/view/ViewRootRectTrackerTest.java b/core/tests/coretests/src/android/view/ViewRootRectTrackerTest.java new file mode 100644 index 000000000000..c66e10079bc8 --- /dev/null +++ b/core/tests/coretests/src/android/view/ViewRootRectTrackerTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2025 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.view; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.testng.AssertJUnit.assertEquals; + +import android.graphics.Rect; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.google.common.collect.Lists; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Collections; +import java.util.List; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class ViewRootRectTrackerTest { + private ViewRootRectTracker mTracker; + private final List<Rect> mRects = Lists.newArrayList(new Rect(0, 0, 5, 5), + new Rect(5, 5, 10, 10)); + + @Before + public void setUp() { + mTracker = new ViewRootRectTracker(v -> Collections.emptyList()); + } + + @Test + public void setRootRectsAndComputeTest() { + mTracker.setRootRects(mRects); + mTracker.computeChanges(); + assertEquals(mRects, mTracker.getLastComputedRects()); + } + + @Test + public void waitingForComputeChangesTest() { + mTracker.setRootRects(mRects); + assertTrue(mTracker.isWaitingForComputeChanges()); + mTracker.computeChangedRects(); + assertFalse(mTracker.isWaitingForComputeChanges()); + + View mockView = mock(View.class); + mTracker.updateRectsForView(mockView); + assertTrue(mTracker.isWaitingForComputeChanges()); + mTracker.computeChangedRects(); + assertFalse(mTracker.isWaitingForComputeChanges()); + } +} |