diff options
Diffstat (limited to 'android/view/View.java')
-rw-r--r-- | android/view/View.java | 211 |
1 files changed, 143 insertions, 68 deletions
diff --git a/android/view/View.java b/android/view/View.java index 0525ab16..cc63a62c 100644 --- a/android/view/View.java +++ b/android/view/View.java @@ -893,6 +893,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ private static boolean sAutoFocusableOffUIThreadWontNotifyParents; + /** + * Prior to P things like setScaleX() allowed passing float values that were bogus such as + * Float.NaN. If the app is targetting P or later then passing these values will result in an + * exception being thrown. If the app is targetting an earlier SDK version, then we will + * silently clamp these values to avoid crashes elsewhere when the rendering code hits + * these bogus values. + */ + private static boolean sThrowOnInvalidFloatProperties; + /** @hide */ @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) @Retention(RetentionPolicy.SOURCE) @@ -1169,7 +1178,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private AutofillId mAutofillId; /** @hide */ - @IntDef({ + @IntDef(prefix = { "AUTOFILL_TYPE_" }, value = { AUTOFILL_TYPE_NONE, AUTOFILL_TYPE_TEXT, AUTOFILL_TYPE_TOGGLE, @@ -1240,7 +1249,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public static final int AUTOFILL_TYPE_DATE = 4; /** @hide */ - @IntDef({ + @IntDef(prefix = { "IMPORTANT_FOR_AUTOFILL_" }, value = { IMPORTANT_FOR_AUTOFILL_AUTO, IMPORTANT_FOR_AUTOFILL_YES, IMPORTANT_FOR_AUTOFILL_NO, @@ -1291,9 +1300,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8; /** @hide */ - @IntDef( - flag = true, - value = {AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS}) + @IntDef(flag = true, prefix = { "AUTOFILL_FLAG_" }, value = { + AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS + }) @Retention(RetentionPolicy.SOURCE) public @interface AutofillFlags {} @@ -1443,7 +1452,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef({DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH, DRAWING_CACHE_QUALITY_AUTO}) + @IntDef(prefix = { "DRAWING_CACHE_QUALITY_" }, value = { + DRAWING_CACHE_QUALITY_LOW, + DRAWING_CACHE_QUALITY_HIGH, + DRAWING_CACHE_QUALITY_AUTO + }) public @interface DrawingCacheQuality {} /** @@ -1542,13 +1555,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ static final int CONTEXT_CLICKABLE = 0x00800000; - /** @hide */ - @IntDef({ - SCROLLBARS_INSIDE_OVERLAY, - SCROLLBARS_INSIDE_INSET, - SCROLLBARS_OUTSIDE_OVERLAY, - SCROLLBARS_OUTSIDE_INSET + @IntDef(prefix = { "SCROLLBARS_" }, value = { + SCROLLBARS_INSIDE_OVERLAY, + SCROLLBARS_INSIDE_INSET, + SCROLLBARS_OUTSIDE_OVERLAY, + SCROLLBARS_OUTSIDE_INSET }) @Retention(RetentionPolicy.SOURCE) public @interface ScrollBarStyle {} @@ -1642,11 +1654,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, static final int TOOLTIP = 0x40000000; /** @hide */ - @IntDef(flag = true, - value = { - FOCUSABLES_ALL, - FOCUSABLES_TOUCH_MODE - }) + @IntDef(flag = true, prefix = { "FOCUSABLES_" }, value = { + FOCUSABLES_ALL, + FOCUSABLES_TOUCH_MODE + }) @Retention(RetentionPolicy.SOURCE) public @interface FocusableMode {} @@ -1663,7 +1674,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; /** @hide */ - @IntDef({ + @IntDef(prefix = { "FOCUS_" }, value = { FOCUS_BACKWARD, FOCUS_FORWARD, FOCUS_LEFT, @@ -1675,7 +1686,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public @interface FocusDirection {} /** @hide */ - @IntDef({ + @IntDef(prefix = { "FOCUS_" }, value = { FOCUS_LEFT, FOCUS_UP, FOCUS_RIGHT, @@ -2417,20 +2428,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback, static final int PFLAG2_DRAG_HOVERED = 0x00000002; /** @hide */ - @IntDef({ - LAYOUT_DIRECTION_LTR, - LAYOUT_DIRECTION_RTL, - LAYOUT_DIRECTION_INHERIT, - LAYOUT_DIRECTION_LOCALE + @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { + LAYOUT_DIRECTION_LTR, + LAYOUT_DIRECTION_RTL, + LAYOUT_DIRECTION_INHERIT, + LAYOUT_DIRECTION_LOCALE }) @Retention(RetentionPolicy.SOURCE) // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection public @interface LayoutDir {} /** @hide */ - @IntDef({ - LAYOUT_DIRECTION_LTR, - LAYOUT_DIRECTION_RTL + @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { + LAYOUT_DIRECTION_LTR, + LAYOUT_DIRECTION_RTL }) @Retention(RetentionPolicy.SOURCE) public @interface ResolvedLayoutDir {} @@ -2636,14 +2647,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; /** @hide */ - @IntDef({ - TEXT_ALIGNMENT_INHERIT, - TEXT_ALIGNMENT_GRAVITY, - TEXT_ALIGNMENT_CENTER, - TEXT_ALIGNMENT_TEXT_START, - TEXT_ALIGNMENT_TEXT_END, - TEXT_ALIGNMENT_VIEW_START, - TEXT_ALIGNMENT_VIEW_END + @IntDef(prefix = { "TEXT_ALIGNMENT_" }, value = { + TEXT_ALIGNMENT_INHERIT, + TEXT_ALIGNMENT_GRAVITY, + TEXT_ALIGNMENT_CENTER, + TEXT_ALIGNMENT_TEXT_START, + TEXT_ALIGNMENT_TEXT_END, + TEXT_ALIGNMENT_VIEW_START, + TEXT_ALIGNMENT_VIEW_END }) @Retention(RetentionPolicy.SOURCE) public @interface TextAlignment {} @@ -3040,15 +3051,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(flag = true, - value = { - SCROLL_INDICATOR_TOP, - SCROLL_INDICATOR_BOTTOM, - SCROLL_INDICATOR_LEFT, - SCROLL_INDICATOR_RIGHT, - SCROLL_INDICATOR_START, - SCROLL_INDICATOR_END, - }) + @IntDef(flag = true, prefix = { "SCROLL_INDICATOR_" }, value = { + SCROLL_INDICATOR_TOP, + SCROLL_INDICATOR_BOTTOM, + SCROLL_INDICATOR_LEFT, + SCROLL_INDICATOR_RIGHT, + SCROLL_INDICATOR_START, + SCROLL_INDICATOR_END, + }) public @interface ScrollIndicators {} /** @@ -3674,8 +3684,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; /** @hide */ - @IntDef(flag = true, - value = { FIND_VIEWS_WITH_TEXT, FIND_VIEWS_WITH_CONTENT_DESCRIPTION }) + @IntDef(flag = true, prefix = { "FIND_VIEWS_" }, value = { + FIND_VIEWS_WITH_TEXT, + FIND_VIEWS_WITH_CONTENT_DESCRIPTION + }) @Retention(RetentionPolicy.SOURCE) public @interface FindViewFlags {} @@ -4287,6 +4299,38 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ Runnable mShowTooltipRunnable; Runnable mHideTooltipRunnable; + + /** + * Hover move is ignored if it is within this distance in pixels from the previous one. + */ + int mHoverSlop; + + /** + * Update the anchor position if it significantly (that is by at least mHoverSlop) + * different from the previously stored position. Ignoring insignificant changes + * filters out the jitter which is typical for such input sources as stylus. + * + * @return True if the position has been updated. + */ + private boolean updateAnchorPos(MotionEvent event) { + final int newAnchorX = (int) event.getX(); + final int newAnchorY = (int) event.getY(); + if (Math.abs(newAnchorX - mAnchorX) <= mHoverSlop + && Math.abs(newAnchorY - mAnchorY) <= mHoverSlop) { + return false; + } + mAnchorX = newAnchorX; + mAnchorY = newAnchorY; + return true; + } + + /** + * Clear the anchor position to ensure that the next change is considered significant. + */ + private void clearAnchorPos() { + mAnchorX = Integer.MAX_VALUE; + mAnchorY = Integer.MAX_VALUE; + } } TooltipInfo mTooltipInfo; @@ -4752,6 +4796,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, sUseDefaultFocusHighlight = context.getResources().getBoolean( com.android.internal.R.bool.config_useDefaultFocusHighlight); + sThrowOnInvalidFloatProperties = targetSdkVersion >= Build.VERSION_CODES.P; + sCompatibilityDone = true; } } @@ -7208,8 +7254,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @param text The announcement text. */ public void announceForAccessibility(CharSequence text) { - if (AccessibilityManager.getInstance(mContext).isObservedEventType( - AccessibilityEvent.TYPE_ANNOUNCEMENT) && mParent != null) { + if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { AccessibilityEvent event = AccessibilityEvent.obtain( AccessibilityEvent.TYPE_ANNOUNCEMENT); onInitializeAccessibilityEvent(event); @@ -10968,8 +11013,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; invalidate(); - if (AccessibilityManager.getInstance(mContext).isObservedEventType( - AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED)) { + if (AccessibilityManager.getInstance(mContext).isEnabled()) { AccessibilityEvent event = AccessibilityEvent.obtain( AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); event.setAction(action); @@ -11794,8 +11838,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, int fromIndex, int toIndex) { - if (mParent == null || !AccessibilityManager.getInstance(mContext).isObservedEventType( - AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY)) { + if (mParent == null) { return; } AccessibilityEvent event = AccessibilityEvent.obtain( @@ -14275,7 +14318,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public void setScaleX(float scaleX) { if (scaleX != getScaleX()) { - requireIsFinite(scaleX, "scaleX"); + scaleX = sanitizeFloatPropertyValue(scaleX, "scaleX"); invalidateViewProperty(true, false); mRenderNode.setScaleX(scaleX); invalidateViewProperty(false, true); @@ -14312,7 +14355,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public void setScaleY(float scaleY) { if (scaleY != getScaleY()) { - requireIsFinite(scaleY, "scaleY"); + scaleY = sanitizeFloatPropertyValue(scaleY, "scaleY"); invalidateViewProperty(true, false); mRenderNode.setScaleY(scaleY); invalidateViewProperty(false, true); @@ -14862,13 +14905,41 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } - private static void requireIsFinite(float transform, String propertyName) { - if (Float.isNaN(transform)) { - throw new IllegalArgumentException("Cannot set '" + propertyName + "' to Float.NaN"); + private static float sanitizeFloatPropertyValue(float value, String propertyName) { + return sanitizeFloatPropertyValue(value, propertyName, -Float.MAX_VALUE, Float.MAX_VALUE); + } + + private static float sanitizeFloatPropertyValue(float value, String propertyName, + float min, float max) { + // The expected "nothing bad happened" path + if (value >= min && value <= max) return value; + + if (value < min || value == Float.NEGATIVE_INFINITY) { + if (sThrowOnInvalidFloatProperties) { + throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " + + value + ", the value must be >= " + min); + } + return min; + } + + if (value > max || value == Float.POSITIVE_INFINITY) { + if (sThrowOnInvalidFloatProperties) { + throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " + + value + ", the value must be <= " + max); + } + return max; } - if (Float.isInfinite(transform)) { - throw new IllegalArgumentException("Cannot set '" + propertyName + "' to infinity"); + + if (Float.isNaN(value)) { + if (sThrowOnInvalidFloatProperties) { + throw new IllegalArgumentException( + "Cannot set '" + propertyName + "' to Float.NaN"); + } + return 0; // Unclear which direction this NaN went so... 0? } + + // Shouldn't be possible to reach this. + throw new IllegalStateException("How do you get here?? " + value); } /** @@ -14957,7 +15028,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public void setElevation(float elevation) { if (elevation != getElevation()) { - requireIsFinite(elevation, "elevation"); + elevation = sanitizeFloatPropertyValue(elevation, "elevation"); invalidateViewProperty(true, false); mRenderNode.setElevation(elevation); invalidateViewProperty(false, true); @@ -15050,7 +15121,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public void setTranslationZ(float translationZ) { if (translationZ != getTranslationZ()) { - requireIsFinite(translationZ, "translationZ"); + translationZ = sanitizeFloatPropertyValue(translationZ, "translationZ"); invalidateViewProperty(true, false); mRenderNode.setTranslationZ(translationZ); invalidateViewProperty(false, true); @@ -25721,6 +25792,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ final Rect mStableInsets = new Rect(); + final DisplayCutout.ParcelableWrapper mDisplayCutout = + new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT); + /** * For windows that include areas that are not covered by real surface these are the outsets * for real surface. @@ -26185,8 +26259,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @Override public void run() { - if (AccessibilityManager.getInstance(mContext).isObservedEventType( - AccessibilityEvent.TYPE_VIEW_SCROLLED)) { + if (AccessibilityManager.getInstance(mContext).isEnabled()) { AccessibilityEvent event = AccessibilityEvent.obtain( AccessibilityEvent.TYPE_VIEW_SCROLLED); event.setScrollDeltaX(mDeltaX); @@ -26775,6 +26848,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mTooltipInfo = new TooltipInfo(); mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; + mTooltipInfo.mHoverSlop = ViewConfiguration.get(mContext).getScaledHoverSlop(); + mTooltipInfo.clearAnchorPos(); } mTooltipInfo.mTooltipText = tooltipText; } @@ -26815,7 +26890,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (mAttachInfo == null || mTooltipInfo == null) { return false; } - if ((mViewFlags & ENABLED_MASK) != ENABLED) { + if (fromLongClick && (mViewFlags & ENABLED_MASK) != ENABLED) { return false; } if (TextUtils.isEmpty(mTooltipInfo.mTooltipText)) { @@ -26841,6 +26916,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mTooltipInfo.mTooltipPopup.hide(); mTooltipInfo.mTooltipPopup = null; mTooltipInfo.mTooltipFromLongClick = false; + mTooltipInfo.clearAnchorPos(); if (mAttachInfo != null) { mAttachInfo.mTooltipHost = null; } @@ -26862,14 +26938,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } switch(event.getAction()) { case MotionEvent.ACTION_HOVER_MOVE: - if ((mViewFlags & TOOLTIP) != TOOLTIP || (mViewFlags & ENABLED_MASK) != ENABLED) { + if ((mViewFlags & TOOLTIP) != TOOLTIP) { break; } - if (!mTooltipInfo.mTooltipFromLongClick) { + if (!mTooltipInfo.mTooltipFromLongClick && mTooltipInfo.updateAnchorPos(event)) { if (mTooltipInfo.mTooltipPopup == null) { // Schedule showing the tooltip after a timeout. - mTooltipInfo.mAnchorX = (int) event.getX(); - mTooltipInfo.mAnchorY = (int) event.getY(); removeCallbacks(mTooltipInfo.mShowTooltipRunnable); postDelayed(mTooltipInfo.mShowTooltipRunnable, ViewConfiguration.getHoverTooltipShowTimeout()); @@ -26891,6 +26965,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return true; case MotionEvent.ACTION_HOVER_EXIT: + mTooltipInfo.clearAnchorPos(); if (!mTooltipInfo.mTooltipFromLongClick) { hideTooltip(); } |