From 52ba29fd8e1965143a21b66db748eff4da00ccb5 Mon Sep 17 00:00:00 2001 From: Robert Horvath Date: Tue, 8 Feb 2022 13:47:21 +0100 Subject: [PATCH] Mark focused Views as keep clear areas Mark/unmark Views as keep clear areas as they gain/lose focus with a small delay. Test: atest KeepClearRectsTests Bug: 218494300 Change-Id: I33c89b5d2ed6707f95eca8ec4b5604c9193aec05 --- core/java/android/view/View.java | 57 +++++++++++++++---- core/java/android/view/ViewConfiguration.java | 13 +++++ core/res/res/values/config.xml | 4 ++ core/res/res/values/symbols.xml | 1 + 4 files changed, 64 insertions(+), 11 deletions(-) diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index b49e075cb710d..c2229911bf128 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -4769,6 +4769,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @UnsupportedAppUsage ListenerInfo mListenerInfo; + private boolean mPreferKeepClearForFocus; + private Runnable mMarkPreferKeepClearForFocus; + private static class TooltipInfo { /** * Text to be displayed in a tooltip popup. @@ -8171,6 +8174,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } notifyEnterOrExitForAutoFillIfNeeded(gainFocus); + updatePreferKeepClearForFocus(); } /** @@ -11934,19 +11938,46 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ @NonNull List collectPreferKeepClearRects() { - final ListenerInfo info = mListenerInfo; - if (info != null) { - final List list = new ArrayList(); - if (info.mPreferKeepClear) { - list.add(new Rect(0, 0, getWidth(), getHeight())); - } - if (info.mKeepClearRects != null) { - list.addAll(info.mKeepClearRects); - } - return list; + ListenerInfo info = mListenerInfo; + final List list = new ArrayList<>(); + + if ((info != null && info.mPreferKeepClear) || mPreferKeepClearForFocus) { + list.add(new Rect(0, 0, getWidth(), getHeight())); } - return Collections.emptyList(); + if (info != null && info.mKeepClearRects != null) { + list.addAll(info.mKeepClearRects); + } + + return list; + } + + private void updatePreferKeepClearForFocus() { + if (mMarkPreferKeepClearForFocus != null) { + removeCallbacks(mMarkPreferKeepClearForFocus); + mMarkPreferKeepClearForFocus = null; + } + + final ViewConfiguration configuration = ViewConfiguration.get(mContext); + final int delay = configuration.getPreferKeepClearForFocusDelay(); + if (delay >= 0) { + mMarkPreferKeepClearForFocus = () -> { + mPreferKeepClearForFocus = isFocused(); + mMarkPreferKeepClearForFocus = null; + + updatePositionUpdateListener(); + post(this::updateKeepClearRects); + }; + postDelayed(mMarkPreferKeepClearForFocus, delay); + } + } + + private void cancelMarkPreferKeepClearForFocus() { + if (mMarkPreferKeepClearForFocus != null) { + removeCallbacks(mMarkPreferKeepClearForFocus); + mMarkPreferKeepClearForFocus = null; + } + mPreferKeepClearForFocus = false; } /** @@ -13656,6 +13687,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } invalidate(); sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); + updatePreferKeepClearForFocus(); return true; } return false; @@ -13735,6 +13767,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, sendAccessibilityEventUnchecked(event); } } + + updatePreferKeepClearForFocus(); } } @@ -20987,6 +21021,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, removePerformClickCallback(); clearAccessibilityThrottles(); stopNestedScroll(); + cancelMarkPreferKeepClearForFocus(); // Anything that started animating right before detach should already // be in its final state when re-attached. diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index b25c0255c1a6f..5775944b4e97f 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -347,6 +347,7 @@ public class ViewConfiguration { private final long mScreenshotChordKeyTimeout; private final int mSmartSelectionInitializedTimeout; private final int mSmartSelectionInitializingTimeout; + private final int mPreferKeepClearForFocusDelay; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768915) private boolean sHasPermanentMenuKey; @@ -392,6 +393,7 @@ public class ViewConfiguration { mMinScalingSpan = 0; mSmartSelectionInitializedTimeout = SMART_SELECTION_INITIALIZED_TIMEOUT_IN_MILLISECOND; mSmartSelectionInitializingTimeout = SMART_SELECTION_INITIALIZING_TIMEOUT_IN_MILLISECOND; + mPreferKeepClearForFocusDelay = -1; } /** @@ -506,6 +508,8 @@ public class ViewConfiguration { com.android.internal.R.integer.config_smartSelectionInitializedTimeoutMillis); mSmartSelectionInitializingTimeout = res.getInteger( com.android.internal.R.integer.config_smartSelectionInitializingTimeoutMillis); + mPreferKeepClearForFocusDelay = res.getInteger( + com.android.internal.R.integer.config_preferKeepClearForFocusDelayMillis); } /** @@ -1095,6 +1099,15 @@ public class ViewConfiguration { return mSmartSelectionInitializingTimeout; } + /** + * @return The delay in milliseconds before focused Views set themselves as preferred to keep + * clear, or -1 if Views should not set themselves as preferred to keep clear. + * @hide + */ + public int getPreferKeepClearForFocusDelay() { + return mPreferKeepClearForFocusDelay; + } + /** * @return the duration in milliseconds before an end of a long press causes a tooltip to be * hidden diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 0763ddb0be941..bc271bfaa222b 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -5192,6 +5192,10 @@ when TextClassifier has not been initialized. --> 500 + + -1 + false diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index dae746b4bb7c0..2112953d69623 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -493,6 +493,7 @@ +