diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 9dd524f84..caee3a025 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -24,7 +24,7 @@ jobs: SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }} steps: - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@0.13.0 + uses: styfle/cancel-workflow-action@0.13.1 with: access_token: ${{ github.token }} diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c0927d67d..babf90639 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -23,7 +23,7 @@ ******************************************************************************/ plugins { - id("com.android.application") + alias(libs.plugins.android.application) } android { diff --git a/app/src/main/assets/samples/big_sample.txt b/app/src/main/assets/samples/big_sample.txt index ba6ba63e4..c048d7987 100644 --- a/app/src/main/assets/samples/big_sample.txt +++ b/app/src/main/assets/samples/big_sample.txt @@ -17,19 +17,56 @@ package android.view; import static android.content.res.Resources.ID_NULL; +import static android.os.Trace.TRACE_TAG_APP; +import static android.os.Trace.TRACE_TAG_VIEW; +import static android.service.autofill.Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION; import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP; +import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH; +import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH_HINT; +import static android.view.Surface.FRAME_RATE_CATEGORY_LOW; +import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL; +import static android.view.Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE; +import static android.view.Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; +import static android.view.Surface.FRAME_RATE_COMPATIBILITY_AT_LEAST; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED; +import static android.view.accessibility.Flags.FLAG_DEPRECATE_ACCESSIBILITY_ANNOUNCEMENT_APIS; +import static android.view.accessibility.Flags.FLAG_SUPPLEMENTAL_DESCRIPTION; +import static android.view.accessibility.Flags.removeChildHoverCheckForTouchExploration; +import static android.view.accessibility.Flags.supplementalDescription; +import static android.view.accessibility.Flags.supportMultipleLabeledby; import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_INVALID_BOUNDS; import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW; import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN; import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_UNKNOWN; import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH; import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH_ERROR_CODE; +import static android.view.flags.Flags.FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API; +import static android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY; +import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API; +import static android.view.flags.Flags.calculateBoundsInParentFromBoundsInScreen; +import static android.view.flags.Flags.enableUseMeasureCacheDuringForceLayout; +import static android.view.flags.Flags.sensitiveContentAppProtection; +import static android.view.flags.Flags.toolkitFrameRateAnimationBugfix25q1; +import static android.view.flags.Flags.toolkitFrameRateBySizeReadOnly; +import static android.view.flags.Flags.toolkitFrameRateDefaultNormalReadOnly; +import static android.view.flags.Flags.toolkitFrameRateSmallUsesPercentReadOnly; +import static android.view.flags.Flags.toolkitFrameRateVelocityMappingReadOnly; +import static android.view.flags.Flags.toolkitFrameRateViewEnablingReadOnly; +import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision; +import static android.view.flags.Flags.toolkitSetFrameRateReadOnly; +import static android.view.flags.Flags.toolkitViewgroupSetRequestedFrameRateApi; +import static android.view.flags.Flags.viewVelocityApi; +import static android.view.inputmethod.Flags.FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR; +import static android.view.inputmethod.Flags.initiationWithoutInputConnection; import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS; import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS; import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP; 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; @@ -39,6 +76,7 @@ import android.annotation.AttrRes; import android.annotation.CallSuper; import android.annotation.ColorInt; import android.annotation.DrawableRes; +import android.annotation.FlaggedApi; import android.annotation.FloatRange; import android.annotation.IdRes; import android.annotation.IntDef; @@ -54,6 +92,9 @@ import android.annotation.SystemApi; import android.annotation.TestApi; import android.annotation.UiContext; import android.annotation.UiThread; +import android.app.PendingIntent; +import android.app.jank.AppJankStats; +import android.app.jank.JankTracker; import android.compat.annotation.UnsupportedAppUsage; import android.content.AutofillOptions; import android.content.ClipData; @@ -61,10 +102,17 @@ import android.content.ClipDescription; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; +import android.content.IntentSender; import android.content.res.ColorStateList; +import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; +import android.credentials.CredentialManager; +import android.credentials.CredentialOption; +import android.credentials.GetCredentialException; +import android.credentials.GetCredentialRequest; +import android.credentials.GetCredentialResponse; import android.graphics.Bitmap; import android.graphics.BlendMode; import android.graphics.Canvas; @@ -90,22 +138,27 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.hardware.display.DisplayManagerGlobal; +import android.hardware.input.InputManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; +import android.os.OutcomeReceiver; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; +import android.service.credentials.CredentialProviderService; import android.sysprop.DisplayProperties; import android.text.InputType; import android.text.TextUtils; +import android.util.ArraySet; import android.util.AttributeSet; +import android.util.DisplayMetrics; import android.util.FloatProperty; import android.util.LayoutDirection; import android.util.Log; @@ -118,6 +171,7 @@ import android.util.SparseArray; import android.util.SparseIntArray; import android.util.StateSet; import android.util.SuperNotCalledException; +import android.util.TimeUtils; import android.util.TypedValue; import android.view.AccessibilityIterators.CharacterTextSegmentIterator; import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; @@ -151,6 +205,7 @@ import android.view.displayhash.DisplayHashManager; import android.view.displayhash.DisplayHashResultCallback; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; +import android.view.inputmethod.InputMethodManager; import android.view.inspector.InspectableProperty; import android.view.inspector.InspectableProperty.EnumEntry; import android.view.inspector.InspectableProperty.FlagEntry; @@ -160,7 +215,6 @@ import android.view.translation.ViewTranslationCallback; import android.view.translation.ViewTranslationRequest; import android.view.translation.ViewTranslationResponse; import android.widget.Checkable; -import android.widget.FrameLayout; import android.widget.ScrollBarDrawable; import android.window.OnBackInvokedDispatcher; @@ -184,6 +238,7 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -193,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; @@ -310,7 +366,7 @@ import java.util.function.Predicate; * * * - * Event processing + * Event processing * {@link #onKeyDown(int, KeyEvent)} * Called when a new hardware key event occurs. * @@ -327,7 +383,17 @@ import java.util.function.Predicate; * * * {@link #onTouchEvent(MotionEvent)} - * Called when a touch screen motion event occurs. + * Called when a motion event occurs with pointers down on the view. + * + * + * + * {@link #onGenericMotionEvent(MotionEvent)} + * Called when a generic motion event occurs. + * + * + * + * {@link #onHoverEvent(MotionEvent)} + * Called when a hover motion event occurs. * * * @@ -903,25 +969,26 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ private static boolean sCompatibilityDone = false; - /** - * Use the old (broken) way of building MeasureSpecs. - */ - private static boolean sUseBrokenMakeMeasureSpec = false; + /** @hide */ + public HapticScrollFeedbackProvider mScrollFeedbackProvider = null; /** - * Always return a size of 0 for MeasureSpec values with a mode of UNSPECIFIED + * Ignore an optimization that skips unnecessary EXACTLY layout passes. */ - static boolean sUseZeroUnspecifiedMeasureSpec = false; + private static boolean sAlwaysRemeasureExactly = false; /** - * Ignore any optimizations using the measure cache. + * When true calculates the bounds in parent from bounds in screen relative to its parents. + * This addresses the deprecated API (setBoundsInParent) in Compose, which causes empty + * getBoundsInParent call for Compose apps. */ - private static boolean sIgnoreMeasureCache = false; + private static boolean sCalculateBoundsInParentFromBoundsInScreenFlagValue = false; /** - * Ignore an optimization that skips unnecessary EXACTLY layout passes. + * When true makes it possible to use onMeasure caches also when the force layout flag is + * enabled. This helps avoiding multiple measures in the same frame with the same dimensions. */ - private static boolean sAlwaysRemeasureExactly = false; + private static boolean sUseMeasureCacheDuringForceLayoutFlagValue; /** * Allow setForeground/setBackground to be called (and ignored) on a textureview, @@ -984,6 +1051,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ private static boolean sAcceptZeroSizeDragShadow; + /** + * When true, measure and layout passes of all the newly attached views will be logged with + * {@link Trace}, so we can better debug jank due to complex view hierarchies. + */ + private static boolean sTraceLayoutSteps; + + /** + * When not null, emits a {@link Trace} instant event and the stacktrace every time a relayout + * of a class having this name happens. + */ + private static String sTraceRequestLayoutClass; + + @Nullable + private ViewCredentialHandler mViewCredentialHandler; + + /** Used to avoid computing the full strings each time when layout tracing is enabled. */ + @Nullable + private ViewTraversalTracingStrings mTracingStrings; + /** * Prior to R, {@link #dispatchApplyWindowInsets} had an issue: *

The modified insets changed by {@link #onApplyWindowInsets} were passed to the @@ -1051,7 +1137,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private static final int FOCUSABLE_MASK = 0x00000011; /** - * This view will adjust its padding to fit sytem windows (e.g. status bar) + * This view will adjust its padding to fit system windows (e.g. status bar) */ private static final int FITS_SYSTEM_WINDOWS = 0x00000002; @@ -1292,6 +1378,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // TODO(229765029): unhide this for UI toolkit public static final String AUTOFILL_HINT_PASSWORD_AUTO = "passwordAuto"; + /** + * Hint indicating that the developer intends to fill this view with output from + * CredentialManager. + * + * @hide + */ + public static final String AUTOFILL_HINT_CREDENTIAL_MANAGER = "credential"; + /** * Hints for the autofill services that describes the content of the view. */ @@ -1552,11 +1646,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ static final int DISABLED = 0x00000020; - /** - * Mask for use with setFlags indicating bits used for indicating whether - * this view is enabled - * {@hide} - */ + /** + * Mask for use with setFlags indicating bits used for indicating whether + * this view is enabled + * {@hide} + */ static final int ENABLED_MASK = 0x00000020; /** @@ -1883,6 +1977,61 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ static final int TOOLTIP = 0x40000000; + /** @hide */ + @IntDef(prefix = { "CONTENT_SENSITIVITY_" }, value = { + CONTENT_SENSITIVITY_AUTO, + CONTENT_SENSITIVITY_SENSITIVE, + CONTENT_SENSITIVITY_NOT_SENSITIVE + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ContentSensitivity {} + + /** + * Content sensitivity is determined by the framework. The framework uses a heuristic to + * determine if this view displays sensitive content. + * Autofill hints i.e. {@link #getAutofillHints()} are used in the heuristic + * to determine if this view should be considered as a sensitive view. + *

+ * {@link #AUTOFILL_HINT_USERNAME}, + * {@link #AUTOFILL_HINT_PASSWORD}, + * {@link #AUTOFILL_HINT_CREDIT_CARD_NUMBER}, + * {@link #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}, + * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}, + * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, + * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}, + * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR} + * are considered sensitive hints by the framework, and the list may include more hints + * in the future. + * + *

The window hosting a sensitive view will be marked as secure during an active media + * projection session. This would be equivalent to applying + * {@link android.view.WindowManager.LayoutParams#FLAG_SECURE} to the window. + * + * @see #getContentSensitivity() + */ + @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) + public static final int CONTENT_SENSITIVITY_AUTO = 0x0; + + /** + * The view displays sensitive content. + * + *

The window hosting a sensitive view will be marked as secure during an active media + * projection session. This would be equivalent to applying + * {@link android.view.WindowManager.LayoutParams#FLAG_SECURE} to the window. + * + * @see #getContentSensitivity() + */ + @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) + public static final int CONTENT_SENSITIVITY_SENSITIVE = 0x1; + + /** + * The view doesn't display sensitive content. + * + * @see #getContentSensitivity() + */ + @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) + public static final int CONTENT_SENSITIVITY_NOT_SENSITIVE = 0x2; + /** @hide */ @IntDef(flag = true, prefix = { "FOCUSABLES_" }, value = { FOCUSABLES_ALL, @@ -2254,6 +2403,95 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; + /** + * This indicates that the frame rate category was chosen for an unknown reason. + * @hide + */ + public static final int FRAME_RATE_CATEGORY_REASON_UNKNOWN = 0x0000_0000; + + /** + * This indicates that the frame rate category was chosen because it was a small area update. + * @hide + */ + public static final int FRAME_RATE_CATEGORY_REASON_SMALL = 0x0100_0000; + + /** + * This indicates that the frame rate category was chosen because it was an intermittent update. + * @hide + */ + public static final int FRAME_RATE_CATEGORY_REASON_INTERMITTENT = 0x0200_0000; + + /** + * This indicates that the frame rate category was chosen because it was a large View. + * @hide + */ + public static final int FRAME_RATE_CATEGORY_REASON_LARGE = 0x03000000; + + /** + * This indicates that the frame rate category was chosen because it was requested. + * @hide + */ + public static final int FRAME_RATE_CATEGORY_REASON_REQUESTED = 0x0400_0000; + + /** + * This indicates that the frame rate category was chosen because an invalid frame rate was + * requested. + * @hide + */ + public static final int FRAME_RATE_CATEGORY_REASON_INVALID = 0x0500_0000; + + /** + * This indicates that the frame rate category was chosen because the view has a velocity + * @hide + */ + public static final int FRAME_RATE_CATEGORY_REASON_VELOCITY = 0x0600_0000; + + /** + * This indicates that the frame rate category was chosen because it is currently boosting. + * @hide + */ + public static final int FRAME_RATE_CATEGORY_REASON_BOOST = 0x0800_0000; + + /** + * This indicates that the frame rate category was chosen because it is currently having + * touch boost. + * @hide + */ + public static final int FRAME_RATE_CATEGORY_REASON_TOUCH = 0x0900_0000; + + /** + * This indicates that the frame rate category was chosen because it is currently having + * touch boost. + * @hide + */ + public static final int FRAME_RATE_CATEGORY_REASON_CONFLICTED = 0x0A00_0000; + + private static final int FRAME_RATE_CATEGORY_REASON_MASK = 0xFFFF_0000; + + /** + * @hide + */ + protected static boolean sToolkitSetFrameRateReadOnlyFlagValue; + private static boolean sToolkitMetricsForFrameRateDecisionFlagValue; + private static final boolean sToolkitFrameRateDefaultNormalReadOnlyFlagValue = + toolkitFrameRateDefaultNormalReadOnly(); + private static final boolean sToolkitFrameRateBySizeReadOnlyFlagValue = + toolkitFrameRateBySizeReadOnly(); + private static final boolean sToolkitFrameRateSmallUsesPercentReadOnlyFlagValue = + toolkitFrameRateSmallUsesPercentReadOnly(); + private static final boolean sToolkitFrameRateViewEnablingReadOnlyFlagValue = + toolkitFrameRateViewEnablingReadOnly(); + private static boolean sToolkitFrameRateVelocityMappingReadOnlyFlagValue = + toolkitFrameRateVelocityMappingReadOnly(); + private static boolean sToolkitFrameRateAnimationBugfix25q1FlagValue = + toolkitFrameRateAnimationBugfix25q1(); + private static boolean sToolkitViewGroupFrameRateApiFlagValue = + toolkitViewgroupSetRequestedFrameRateApi(); + + // Used to set frame rate compatibility. + @Surface.FrameRateCompatibility int mFrameRateCompatibility = + FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; + static { EMPTY_STATE_SET = StateSet.get(0); @@ -2335,6 +2573,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); + + sToolkitSetFrameRateReadOnlyFlagValue = toolkitSetFrameRateReadOnly(); + sToolkitMetricsForFrameRateDecisionFlagValue = toolkitMetricsForFrameRateDecision(); + sCalculateBoundsInParentFromBoundsInScreenFlagValue = + calculateBoundsInParentFromBoundsInScreen(); + sUseMeasureCacheDuringForceLayoutFlagValue = enableUseMeasureCacheDuringForceLayout(); } /** @@ -3074,6 +3318,44 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; + /** + * Automatically determine whether the view should only allow interactions from + * {@link android.accessibilityservice.AccessibilityService}s with the + * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property + * set to true. + * + *

+ * Accessibility interactions from services without {@code isAccessibilityTool} set to true are + * disallowed for any of the following conditions: + *

  • this view sets {@link #getFilterTouchesWhenObscured()}.
  • + *
  • any parent of this view returns true from {@link #isAccessibilityDataSensitive()}.
  • + *

    + */ + public static final int ACCESSIBILITY_DATA_SENSITIVE_AUTO = 0x00000000; + + /** + * Only allow interactions from {@link android.accessibilityservice.AccessibilityService}s + * with the {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} + * property set to true. + */ + public static final int ACCESSIBILITY_DATA_SENSITIVE_YES = 0x00000001; + + /** + * Allow interactions from all {@link android.accessibilityservice.AccessibilityService}s, + * regardless of their + * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property. + */ + public static final int ACCESSIBILITY_DATA_SENSITIVE_NO = 0x00000002; + + /** @hide */ + @IntDef(prefix = { "ACCESSIBILITY_DATA_SENSITIVE_" }, value = { + ACCESSIBILITY_DATA_SENSITIVE_AUTO, + ACCESSIBILITY_DATA_SENSITIVE_YES, + ACCESSIBILITY_DATA_SENSITIVE_NO, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface AccessibilityDataSensitive {} + /** * Mask for obtaining the bits which specify how to determine * whether a view is important for accessibility. @@ -3099,16 +3381,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; /** - * Live region mode specifying that accessibility services should announce - * changes to this view. + * Live region mode specifying that accessibility services should notify users of changes to + * this view. *

    * Use with {@link #setAccessibilityLiveRegion(int)}. */ public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; /** - * Live region mode specifying that accessibility services should interrupt - * ongoing speech to immediately announce changes to this view. + * Live region mode specifying that accessibility services should immediately notify users of + * changes to this view. For example, a screen reader may interrupt ongoing speech to + * immediately announce these changes. *

    * Use with {@link #setAccessibilityLiveRegion(int)}. */ @@ -3532,6 +3815,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * 1 PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE * 1 PFLAG4_DRAG_A11Y_STARTED * 1 PFLAG4_AUTO_HANDWRITING_INITIATION_ENABLED + * 1 PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER + * 1 PFLAG4_TRAVERSAL_TRACING_ENABLED + * 1 PFLAG4_RELAYOUT_TRACING_ENABLED + * 1 PFLAG4_ROTARY_HAPTICS_DETERMINED + * 1 PFLAG4_ROTARY_HAPTICS_ENABLED + * 1 PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT + * 1 PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT + * 11 PFLAG4_CONTENT_SENSITIVITY_MASK + * 1 PFLAG4_IS_COUNTED_AS_SENSITIVE + * 1 PFLAG4_HAS_DRAWN + * 1 PFLAG4_HAS_MOVED + * 1 PFLAG4_HAS_VIEW_PROPERTY_INVALIDATION + * 1 PFLAG4_FORCED_OVERRIDE_FRAME_RATE + * 1 PFLAG4_SELF_REQUESTED_FRAME_RATE * |-------|-------|-------|-------| */ @@ -3612,6 +3909,87 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * Indicates that the view enables auto handwriting initiation. */ private static final int PFLAG4_AUTO_HANDWRITING_ENABLED = 0x000010000; + + /** + * Indicates that the view is important for Credential Manager. + */ + private static final int PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER = 0x000020000; + + /** + * When set, measure and layout passes of this view will be logged with {@link Trace}, so we + * can better debug jank due to complex view hierarchies. + */ + private static final int PFLAG4_TRAVERSAL_TRACING_ENABLED = 0x000040000; + + /** + * When set, emits a {@link Trace} instant event and stacktrace every time a requestLayout of + * this class happens. + */ + private static final int PFLAG4_RELAYOUT_TRACING_ENABLED = 0x000080000; + + /** Indicates if rotary scroll haptics support for the view has been determined. */ + private static final int PFLAG4_ROTARY_HAPTICS_DETERMINED = 0x100000; + + /** + * Indicates if rotary scroll haptics is enabled for this view. + * The source of truth for this info is a ViewConfiguration API; this bit only caches the value. + */ + private static final int PFLAG4_ROTARY_HAPTICS_ENABLED = 0x200000; + + /** Indicates if there has been a scroll event since the last rotary input. */ + private static final int PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT = 0x400000; + + /** + * Indicates if there has been a rotary input that may generate a scroll event. + * This flag is important so that a scroll event can be properly attributed to a rotary input. + */ + private static final int PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT = 0x800000; + + private static final int PFLAG4_CONTENT_SENSITIVITY_SHIFT = 24; + + /** + * Mask for obtaining the bits which specify how to determine whether a view + * displays sensitive content or not. + */ + private static final int PFLAG4_CONTENT_SENSITIVITY_MASK = + (CONTENT_SENSITIVITY_AUTO | CONTENT_SENSITIVITY_SENSITIVE + | CONTENT_SENSITIVITY_NOT_SENSITIVE) << PFLAG4_CONTENT_SENSITIVITY_SHIFT; + + /** + * Whether this view has been counted as a sensitive view or not. + * + * @see AttachInfo#mSensitiveViewsCount + */ + private static final int PFLAG4_IS_COUNTED_AS_SENSITIVE = 0x4000000; + + /** + * Whether this view has been drawn once with updateDisplayListIfDirty() or not. + * Used by VRR to for quick detection of scrolling. + */ + private static final int PFLAG4_HAS_DRAWN = 0x8000000; + + /** + * Whether this view has been moved with either setTranslationX/Y or setLeft/Top. + * Used by VRR to for quick detection of scrolling. + */ + private static final int PFLAG4_HAS_MOVED = 0x10000000; + + /** + * Whether the invalidateViewProperty is involked at current frame. + */ + private static final int PFLAG4_HAS_VIEW_PROPERTY_INVALIDATION = 0x20000000; + + /** + * When set, this indicates whether the frame rate of the children should be + * forcibly overridden, even if it has been explicitly configured by a user request. + */ + private static final int PFLAG4_FORCED_OVERRIDE_FRAME_RATE = 0x40000000; + + /** + * When set, this indicates that the frame rate is configured based on a user request. + */ + private static final int PFLAG4_SELF_REQUESTED_FRAME_RATE = 0x80000000; + /* End of masks for mPrivateFlags4 */ /** @hide */ @@ -4395,6 +4773,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @ViewDebug.ExportedProperty(category = "layout") @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) protected int mLeft; + /** + * The mLeft from the previous frame. Used for detecting movement for purposes of variable + * refresh rate. + */ + private int mLastFrameLeft; /** * The distance in pixels from the left edge of this view's parent * to the right edge of this view. @@ -4411,6 +4794,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @ViewDebug.ExportedProperty(category = "layout") @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) protected int mTop; + /** + * The mTop from the previous frame. Used for detecting movement for purposes of variable + * refresh rate. + */ + private int mLastFrameTop; /** * The distance in pixels from the top edge of this view's parent * to the bottom edge of this view. @@ -4474,6 +4862,26 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @UnsupportedAppUsage protected int mPaddingBottom; + /** + * The amount of pixel offset applied to the left edge of this view's handwriting bounds. + */ + private float mHandwritingBoundsOffsetLeft; + + /** + * The amount of pixel offset applied to the top edge of this view's handwriting bounds. + */ + private float mHandwritingBoundsOffsetTop; + + /** + * The amount of pixel offset applied to the right edge of this view's handwriting bounds. + */ + private float mHandwritingBoundsOffsetRight; + + /** + * The amount of pixel offset applied to the bottom edge of this view's handwriting bounds. + */ + private float mHandwritingBoundsOffsetBottom; + /** * The layout insets in pixels, that is the distance in pixels between the * visible edges of this view its bounds. @@ -4490,12 +4898,27 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ private CharSequence mContentDescription; + /** + * Brief supplemental information for view and is primarily used for accessibility support. + */ + private CharSequence mSupplementalDescription; + /** * If this view represents a distinct part of the window, it can have a title that labels the * area. */ private CharSequence mAccessibilityPaneTitle; + /** + * Describes whether this view should only allow interactions from + * {@link android.accessibilityservice.AccessibilityService}s with the + * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property + * set to true. + */ + private int mExplicitAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_AUTO; + /** Used to calculate and cache {@link #isAccessibilityDataSensitive()}. */ + private int mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_AUTO; + /** * Specifies the id of a view for which this view serves as a label for * accessibility purposes. @@ -4982,6 +5405,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ private boolean mHoveringTouchDelegate = false; + // These two fields are set if the view is a handwriting delegator. + private Runnable mHandwritingDelegatorCallback; + private String mAllowedHandwritingDelegatePackageName; + + // These three fields are set if the view is a handwriting delegate. + private boolean mIsHandwritingDelegate; + private String mAllowedHandwritingDelegatorPackageName; + private @InputMethodManager.HandwritingDelegateFlags int mHandwritingDelegateFlags; + /** * Solid color to use as a background when creating the drawing cache. Enables * the cache to use 16 bit bitmaps instead of 32 bit. @@ -5093,6 +5525,43 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public static final int DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION = 1 << 11; + /** + * Flag indicating that a drag can cross window boundaries (within the same application). When + * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called + * with this flag set, only visible windows belonging to the same application (ie. share the + * same UID) with targetSdkVersion >= {@link android.os.Build.VERSION_CODES#N API 24} will be + * able to participate in the drag operation and receive the dragged content. + * + * If both DRAG_FLAG_GLOBAL_SAME_APPLICATION and DRAG_FLAG_GLOBAL are set, then + * DRAG_FLAG_GLOBAL_SAME_APPLICATION takes precedence and the drag will only go to visible + * windows from the same application. + */ + @FlaggedApi(FLAG_DELEGATE_UNHANDLED_DRAGS) + public static final int DRAG_FLAG_GLOBAL_SAME_APPLICATION = 1 << 12; + + /** + * Flag indicating that an unhandled drag should be delegated to the system to be started if no + * visible window wishes to handle the drop. When using this flag, the caller must provide + * ClipData with an Item that contains an immutable IntentSender to an activity to be launched + * (not a broadcast, service, etc). See + * {@link ClipData.Item.Builder#setIntentSender(IntentSender)}. + * + * The system can decide to launch the intent or not based on factors like the current screen + * size or windowing mode. If the system does not launch the intent, it will be canceled via the + * normal drag and drop flow. + */ + @FlaggedApi(FLAG_DELEGATE_UNHANDLED_DRAGS) + public static final int DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG = 1 << 13; + + /** + * Flag indicating that this drag will result in the caller activity's task to be hidden for the + * duration of the drag, which means that the source activity will not receive drag events for + * the current drag gesture. Only the current + * {@link android.service.voice.VoiceInteractionService} may use this flag. + */ + @FlaggedApi(FLAG_SUPPORTS_DRAG_ASSISTANT_TO_MULTIWINDOW) + public static final int DRAG_FLAG_HIDE_CALLING_TASK_ON_DRAG_START = 1 << 14; + /** * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. */ @@ -5191,11 +5660,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @Retention(RetentionPolicy.SOURCE) public @interface LayerType {} - @ViewDebug.ExportedProperty(category = "drawing", mapping = { - @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), - @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), - @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") - }) int mLayerType = LAYER_TYPE_NONE; Paint mLayerPaint; @@ -5287,7 +5751,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * The pointer icon when the mouse hovers on this view. The default is null. */ - private PointerIcon mPointerIcon; + private PointerIcon mMousePointerIcon; /** * @hide @@ -5339,10 +5803,49 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @Nullable private ViewTranslationCallback mViewTranslationCallback; + private float mFrameContentVelocity = -1; + @Nullable private ViewTranslationResponse mViewTranslationResponse; + /** + * The size in DP that is considered small for VRR purposes, if square. + */ + private static final float FRAME_RATE_SQUARE_SMALL_SIZE_DP = 40f; + + /** + * The size in DP that is considered small for VRR purposes in the narrow dimension. Used for + * narrow Views like a progress bar. + */ + private static final float FRAME_RATE_NARROW_SIZE_DP = 10f; + + /** + * A threshold value to determine the frame rate category of the View based on the size. + */ + private static final float FRAME_RATE_SIZE_PERCENTAGE_THRESHOLD = 0.07f; + + static final float MAX_FRAME_RATE = 120; + + // The preferred frame rate of the view that is mainly used for + // touch boosting, view velocity handling, and TextureView. + private float mPreferredFrameRate = REQUESTED_FRAME_RATE_CATEGORY_DEFAULT; + + private int mLastFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE; + + @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) + public static final float REQUESTED_FRAME_RATE_CATEGORY_DEFAULT = Float.NaN; + @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) + public static final float REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE = -1; + @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) + public static final float REQUESTED_FRAME_RATE_CATEGORY_LOW = -2; + @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) + public static final float REQUESTED_FRAME_RATE_CATEGORY_NORMAL = -3; + @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) + public static final float REQUESTED_FRAME_RATE_CATEGORY_HIGH = -4; + + private int mSizeBasedFrameRateCategoryAndReason; + /** * Simple constructor to use when creating a view from code. * @@ -5361,7 +5864,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); - mPrivateFlags4 = PFLAG4_AUTO_HANDWRITING_ENABLED; final ViewConfiguration configuration = ViewConfiguration.get(context); mTouchSlop = configuration.getScaledTouchSlop(); @@ -5375,20 +5877,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (!sCompatibilityDone && context != null) { final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; - // Older apps may need this compatibility hack for measurement. - sUseBrokenMakeMeasureSpec = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1; - - // Older apps expect onMeasure() to always be called on a layout pass, regardless - // of whether a layout was requested on that View. - sIgnoreMeasureCache = targetSdkVersion < Build.VERSION_CODES.KITKAT; - - // In M and newer, our widgets can pass a "hint" value in the size - // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers - // know what the expected parent size is going to be, so e.g. list items can size - // themselves at 1/3 the size of their container. It breaks older apps though, - // specifically apps that use some popular open source libraries. - sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < Build.VERSION_CODES.M; - // Old versions of the platform would give different results from // LinearLayout measurement passes using EXACTLY and non-EXACTLY // modes, so we always need to run an additional EXACTLY pass. @@ -5565,8 +6053,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, boolean leftPaddingDefined = false; boolean rightPaddingDefined = false; - final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; - // Set default values. viewFlagValues |= FOCUSABLE_AUTO; viewFlagMasks |= FOCUSABLE_AUTO; @@ -5787,11 +6273,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, break; //noinspection deprecation case R.styleable.View_fadingEdge: - if (targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - // Ignore the attribute starting with ICS - break; - } - // With builds < ICS, fall through and apply fading edges + break; case R.styleable.View_requiresFadingEdge: final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); if (fadingEdge != FADING_EDGE_NONE) { @@ -5889,6 +6371,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, setImportantForAccessibility(a.getInt(attr, IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); break; + case R.styleable.View_accessibilityDataSensitive: + setAccessibilityDataSensitive(a.getInt(attr, + ACCESSIBILITY_DATA_SENSITIVE_AUTO)); + break; case R.styleable.View_accessibilityLiveRegion: setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); break; @@ -5925,35 +6411,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback, PROVIDER_BACKGROUND)); break; case R.styleable.View_foreground: - if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { - setForeground(a.getDrawable(attr)); - } + setForeground(a.getDrawable(attr)); break; case R.styleable.View_foregroundGravity: - if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { - setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); - } + setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); break; case R.styleable.View_foregroundTintMode: - if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { - setForegroundTintBlendMode( - Drawable.parseBlendMode(a.getInt(attr, -1), - null)); - } + setForegroundTintBlendMode( + Drawable.parseBlendMode(a.getInt(attr, -1), + null)); break; case R.styleable.View_foregroundTint: - if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { - setForegroundTintList(a.getColorStateList(attr)); - } + setForegroundTintList(a.getColorStateList(attr)); break; case R.styleable.View_foregroundInsidePadding: - if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { - if (mForegroundInfo == null) { - mForegroundInfo = new ForegroundInfo(); - } - mForegroundInfo.mInsidePadding = a.getBoolean(attr, - mForegroundInfo.mInsidePadding); + if (mForegroundInfo == null) { + mForegroundInfo = new ForegroundInfo(); } + mForegroundInfo.mInsidePadding = a.getBoolean(attr, + mForegroundInfo.mInsidePadding); break; case R.styleable.View_scrollIndicators: final int scrollIndicators = @@ -6039,6 +6515,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, setImportantForContentCapture(a.getInt(attr, IMPORTANT_FOR_CONTENT_CAPTURE_AUTO)); } + break; + case R.styleable.View_isCredential: + if (a.peekValue(attr) != null) { + setIsCredential(a.getBoolean(attr, false)); + } + break; case R.styleable.View_defaultFocusHighlightEnabled: if (a.peekValue(attr) != null) { setDefaultFocusHighlightEnabled(a.getBoolean(attr, true)); @@ -6076,8 +6558,30 @@ public class View implements Drawable.Callback, KeyEvent.Callback, setPreferKeepClear(a.getBoolean(attr, false)); break; case R.styleable.View_autoHandwritingEnabled: - setAutoHandwritingEnabled(a.getBoolean(attr, true)); + setAutoHandwritingEnabled(a.getBoolean(attr, false)); + break; + case R.styleable.View_handwritingBoundsOffsetLeft: + mHandwritingBoundsOffsetLeft = a.getDimension(attr, 0); break; + case R.styleable.View_handwritingBoundsOffsetTop: + mHandwritingBoundsOffsetTop = a.getDimension(attr, 0); + break; + case R.styleable.View_handwritingBoundsOffsetRight: + mHandwritingBoundsOffsetRight = a.getDimension(attr, 0); + break; + case R.styleable.View_handwritingBoundsOffsetBottom: + mHandwritingBoundsOffsetBottom = a.getDimension(attr, 0); + break; + case R.styleable.View_contentSensitivity: + setContentSensitivity(a.getInt(attr, CONTENT_SENSITIVITY_AUTO)); + break; + default: { + if (supplementalDescription()) { + if (attr == com.android.internal.R.styleable.View_supplementalDescription) { + setSupplementalDescription(a.getString(attr)); + } + } + } } } @@ -6537,6 +7041,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, out.append(mRight); out.append(','); out.append(mBottom); + appendId(out); + if (mAutofillId != null) { + out.append(" aid="); out.append(mAutofillId); + } + out.append("}"); + return out.toString(); + } + + void appendId(StringBuilder out) { final int id = getId(); if (id != NO_ID) { out.append(" #"); @@ -6568,11 +7081,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } } - if (mAutofillId != null) { - out.append(" aid="); out.append(mAutofillId); - } - out.append("}"); - return out.toString(); } /** @@ -6656,12 +7164,81 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Returns the size of the horizontal faded edges used to indicate that more - * content in this view is visible. + * Clears the request and callback previously set + * through {@link View#setPendingCredentialRequest}. + * Once this API is invoked, there will be no request fired to {@link CredentialManager} + * on future view focus events. * - * @return The size in pixels of the horizontal faded edge or 0 if horizontal - * faded edges are not enabled for this view. - * @attr ref android.R.styleable#View_fadingEdgeLength + * @see #setPendingCredentialRequest + */ + @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) + public void clearPendingCredentialRequest() { + if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { + Log.v(AUTOFILL_LOG_TAG, "clearPendingCredentialRequest called"); + } + mViewCredentialHandler = null; + } + + /** + * Sets a {@link CredentialManager} request to retrieve credentials, when the user focuses + * on this given view. + * + * When this view is focused, the given {@code request} will be fired to + * {@link CredentialManager}, which will fetch content from all + * {@link android.service.credentials.CredentialProviderService} services on the + * device, and then display credential options to the user on a relevant UI + * (dropdown, keyboard suggestions etc.). + * + * When the user selects a credential, the final {@link GetCredentialResponse} will be + * propagated to the given {@code callback}. Developers are expected to handle the response + * programmatically and perform a relevant action, e.g. signing in the user. + * + *

    For details on how to build a Credential Manager request, please see + * {@link GetCredentialRequest}. + * + *

    This API should be called at any point before the user focuses on the view, e.g. during + * {@code onCreate} of an Activity. + * + * @param request the request to be fired when this view is entered + * @param callback to be invoked when either a response or an exception needs to be + * propagated for the given view + */ + @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) + public void setPendingCredentialRequest(@NonNull GetCredentialRequest request, + @NonNull OutcomeReceiver callback) { + Preconditions.checkNotNull(request, "request must not be null"); + Preconditions.checkNotNull(callback, "callback must not be null"); + + for (CredentialOption option : request.getCredentialOptions()) { + ArrayList ids = option.getCandidateQueryData() + .getParcelableArrayList( + CredentialProviderService.EXTRA_AUTOFILL_ID, AutofillId.class); + ids = ids != null ? ids : new ArrayList<>(); + if (!ids.contains(getAutofillId())) { + ids.add(getAutofillId()); + } + option.getCandidateQueryData() + .putParcelableArrayList(CredentialProviderService.EXTRA_AUTOFILL_ID, ids); + } + mViewCredentialHandler = new ViewCredentialHandler(request, callback); + } + + /** + * + * @hide + */ + @Nullable + public ViewCredentialHandler getViewCredentialHandler() { + return mViewCredentialHandler; + } + + /** + * Returns the size of the horizontal faded edges used to indicate that more + * content in this view is visible. + * + * @return The size in pixels of the horizontal faded edge or 0 if horizontal + * faded edges are not enabled for this view. + * @attr ref android.R.styleable#View_fadingEdgeLength */ public int getHorizontalFadingEdgeLength() { if (isHorizontalFadingEdgeEnabled()) { @@ -7581,9 +8158,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); boolean handled = false; - final ListenerInfo li = mListenerInfo; - if (li != null && li.mOnLongClickListener != null) { - handled = li.mOnLongClickListener.onLongClick(View.this); + final OnLongClickListener listener = + mListenerInfo == null ? null : mListenerInfo.mOnLongClickListener; + boolean shouldPerformHapticFeedback = true; + if (listener != null) { + handled = listener.onLongClick(View.this); + if (handled) { + shouldPerformHapticFeedback = listener.onLongClickUseDefaultHapticFeedback( + View.this); + } } if (!handled) { final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); @@ -7594,7 +8177,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, handled = showLongClickTooltip((int) x, (int) y); } } - if (handled) { + if (handled && shouldPerformHapticFeedback) { performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); } return handled; @@ -7916,6 +8499,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @param rectangle The rectangle in the View's content coordinate space * @return Whether any parent scrolled. + * @see AccessibilityAction#ACTION_SHOW_ON_SCREEN */ public boolean requestRectangleOnScreen(Rect rectangle) { return requestRectangleOnScreen(rectangle, false); @@ -7998,8 +8582,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * hierarchy * @param refocus when propagate is true, specifies whether to request the * root view place new focus + * @hide */ - void clearFocusInternal(View focused, boolean propagate, boolean refocus) { + public void clearFocusInternal(View focused, boolean propagate, boolean refocus) { if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { mPrivateFlags &= ~PFLAG_FOCUSED; clearParentsWantFocus(); @@ -8146,6 +8731,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @CallSuper protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, @Nullable Rect previouslyFocusedRect) { + if (DBG) { + Log.d(VIEW_LOG_TAG, "onFocusChanged() entered. gainFocus: " + + gainFocus); + } if (gainFocus) { sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); } else { @@ -8166,6 +8755,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, onFocusLost(); } else if (hasWindowFocus()) { notifyFocusChangeToImeFocusController(true /* hasFocus */); + ViewRootImpl viewRoot = getViewRootImpl(); + if (viewRoot != null) { + if (mIsHandwritingDelegate) { + viewRoot.getHandwritingInitiator().onDelegateViewFocused(this); + } else if (initiationWithoutInputConnection() && onCheckIsTextEditor()) { + viewRoot.getHandwritingInitiator().onEditorFocused(this); + } + } } invalidate(true); @@ -8203,11 +8800,28 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (canNotifyAutofillEnterExitEvent()) { AutofillManager afm = getAutofillManager(); if (afm != null) { + if (DBG) { + Log.d(VIEW_LOG_TAG, this + " afm is not null"); + } if (enter) { // We have not been laid out yet, hence cannot evaluate // whether this view is visible to the user, we will do // the evaluation once layout is complete. - if (!isLaidOut()) { + // Sometimes, views are already laid out, but it's still + // not visible to the user, we also do the evaluation once + // the view is visible. ex: There is a fade-in animation + // for the activity, the view will be laid out when the + // animation beginning. On the time, the view is not visible + // to the user. And then as the animation progresses, the view + // becomes visible to the user. + if (DBG) { + Log.d(VIEW_LOG_TAG, + "notifyEnterOrExitForAutoFillIfNeeded:" + + " isLaidOut(): " + isLaidOut() + + " isVisibleToUser(): " + isVisibleToUser() + + " isFocused(): " + isFocused()); + } + if (!isLaidOut() || !isVisibleToUser()) { mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; } else if (isVisibleToUser()) { if (isFocused()) { @@ -8229,11 +8843,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Visually distinct portion of a window with window-like semantics are considered panes for - * accessibility purposes. One example is the content view of a fragment that is replaced. + * accessibility purposes. One example is the content view of a large fragment that is replaced. * In order for accessibility services to understand a pane's window-like behavior, panes - * should have descriptive titles. Views with pane titles produce {@link AccessibilityEvent}s - * when they appear, disappear, or change title. + * should have descriptive titles. Views with pane titles produce + * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}s when they appear, disappear, or change + * title. * + *

    + * When transitioning from one Activity to another, instead of using + * {@code setAccessibilityPaneTitle()}, set a descriptive title for its window by using + * {@code android:label} + * for the matching Activity entry in your application's manifest or updating the title at + * runtime with {@link android.app.Activity#setTitle(CharSequence)}. + * + *

    + *

    * @param accessibilityPaneTitle The pane's title. Setting to {@code null} indicates that this * View is not a pane. * @@ -8331,17 +8959,45 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} - * {@link AccessibilityEvent} to suggest that an accessibility service announce the - * specified text to its users. - *

    - * Note: The event generated with this API carries no semantic meaning, and is appropriate only - * in exceptional situations. Apps can generally achieve correct behavior for accessibility by - * accurately supplying the semantics of their UI. - * They should not need to specify what exactly is announced to users. + * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} {@link + * AccessibilityEvent} to suggest that an accessibility service announce the specified text to + * its users. + * + *

    Note: The event generated with this API carries no semantic meaning, and accessibility + * services may choose to ignore it. Apps that accurately supply accessibility with the + * semantics of their UI should not need to specify what exactly is announced. + * + *

    In general, do not attempt to generate announcements as confirmation message for simple + * actions like a button press. Label your controls concisely and precisely instead. + * + *

    To convey significant UI changes like window changes, use {@link + * android.app.Activity#setTitle(CharSequence)} and {@link + * #setAccessibilityPaneTitle(CharSequence)}. * + *

    Use {@link #setAccessibilityLiveRegion(int)} to inform the user of changes to critical + * views within the user interface. These should still be used sparingly as they may generate + * announcements every time a View is updated. + * + *

    Use {@link #setStateDescription(CharSequence)} to convey state changes to views within the + * user interface. While a live region may send different types of events generated by the view, + * state description will send {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} events of + * type {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_STATE_DESCRIPTION}. + * + *

    For notifying users about errors, such as in a login screen with text that displays an + * "incorrect password" notification, set {@link AccessibilityNodeInfo#setError(CharSequence)} + * and dispatch an {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event with a change + * type of {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_ERROR}, instead. Some widgets may + * expose methods that convey error states to accessibility automatically, such as {@link + * android.widget.TextView#setError(CharSequence)}, which manages these accessibility semantics + * and event dispatch for callers. + * + * @deprecated Use one of the methods described in the documentation above to semantically + * describe UI instead of using an announcement, as accessibility services may choose to + * ignore events dispatched with this method. * @param text The announcement text. */ + @FlaggedApi(FLAG_DEPRECATE_ACCESSIBILITY_ANNOUNCEMENT_APIS) + @Deprecated public void announceForAccessibility(CharSequence text) { if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { AccessibilityEvent event = AccessibilityEvent.obtain( @@ -8460,15 +9116,43 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then - * to its children for adding their text content to the event. Note that the - * event text is populated in a separate dispatch path since we add to the + * Dispatches an {@link AccessibilityEvent} to the {@link View} to add the text content of the + * view and its children. + *

    + * Note: This method should only be used with event.setText(). + * Avoid mutating other event state in this method. In general, put UI metadata in the node for + * services to easily query. + *

    + *

    + * Note that the event text is populated in a separate dispatch path + * ({@link #onPopulateAccessibilityEvent(AccessibilityEvent)}) since we add to the * event not only the text of the source but also the text of all its descendants. + *

    * A typical implementation will call - * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view + * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on this view * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} - * on each child. Override this method if custom population of the event text - * content is required. + * on each child or the first child that is visible. Override this method if custom population + * of the event text content is required. + * *

    * If an {@link AccessibilityDelegate} has been specified via calling * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its @@ -8476,6 +9160,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * is responsible for handling this call. *

    *

    + * If this view sets {@link #isAccessibilityDataSensitive()} then this view should only append + * sensitive information to an event that also sets + * {@link AccessibilityEvent#isAccessibilityDataSensitive()}. + *

    + *

    * Note: Accessibility events of certain types are not dispatched for * populating the event text via this method. For details refer to {@link AccessibilityEvent}. *

    @@ -8507,9 +9196,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} * giving a chance to this View to populate the accessibility event with its - * text content. While this method is free to modify event - * attributes other than text content, doing so should normally be performed in - * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. + * text content. + *

    + * Note: This method should only be used with event.setText(). + * Avoid mutating other event state in this method. Instead, follow the practices described in + * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)}. In general, put UI + * metadata in the node for services to easily query, than in transient events. *

    * Example: Adding formatted date string to an accessibility event in addition * to the text added by the super implementation: @@ -8731,7 +9423,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @hide */ @UnsupportedAppUsage - public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { + @TestApi + public void getBoundsOnScreen(@NonNull Rect outRect, boolean clipToParent) { if (mAttachInfo == null) { return; } @@ -8739,6 +9432,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, getBoundsToScreenInternal(position, clipToParent); outRect.set(Math.round(position.left), Math.round(position.top), Math.round(position.right), Math.round(position.bottom)); + // If "Sandboxing View Bounds APIs" override is enabled, applyViewBoundsSandboxingIfNeeded + // will sandbox outRect within window bounds. + mAttachInfo.mViewRootImpl.applyViewBoundsSandboxingIfNeeded(outRect); } /** @@ -8757,11 +9453,33 @@ public class View implements Drawable.Callback, KeyEvent.Callback, outRect.set(position.left, position.top, position.right, position.bottom); } + /** + * Gets the location of this view in window coordinates. + * + * @param outRect The output location + * @param clipToParent Whether to clip child bounds to the parent ones. + * @hide + */ + public void getBoundsInWindow(Rect outRect, boolean clipToParent) { + if (mAttachInfo == null) { + return; + } + RectF position = mAttachInfo.mTmpTransformRect; + getBoundsToWindowInternal(position, clipToParent); + outRect.set(Math.round(position.left), Math.round(position.top), + Math.round(position.right), Math.round(position.bottom)); + } + private void getBoundsToScreenInternal(RectF position, boolean clipToParent) { position.set(0, 0, mRight - mLeft, mBottom - mTop); mapRectFromViewToScreenCoords(position, clipToParent); } + private void getBoundsToWindowInternal(RectF position, boolean clipToParent) { + position.set(0, 0, mRight - mLeft, mBottom - mTop); + mapRectFromViewToWindowCoords(position, clipToParent); + } + /** * Map a rectangle from view-relative coordinates to screen-relative coordinates * @@ -8770,6 +9488,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @hide */ public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) { + mapRectFromViewToWindowCoords(rect, clipToParent); + rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); + } + + /** + * Map a rectangle from view-relative coordinates to window-relative coordinates + * + * @param rect The rectangle to be mapped + * @param clipToParent Whether to clip child bounds to the parent ones. + * @hide + */ + public void mapRectFromViewToWindowCoords(RectF rect, boolean clipToParent) { if (!hasIdentityMatrix()) { getMatrix().mapRect(rect); } @@ -8802,8 +9532,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, ViewRootImpl viewRootImpl = (ViewRootImpl) parent; rect.offset(0, -viewRootImpl.mCurScrollY); } - - rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); } /** @@ -8987,6 +9715,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, structure.setAutofillType(autofillType); structure.setAutofillHints(getAutofillHints()); structure.setAutofillValue(getAutofillValue()); + structure.setIsCredential(isCredential()); + } + if (getViewCredentialHandler() != null) { + structure.setPendingCredentialRequest( + getViewCredentialHandler().getRequest(), + getViewCredentialHandler().getCallback()); } structure.setImportantForAutofill(getImportantForAutofill()); structure.setReceiveContentMimeTypes(getReceiveContentMimeTypes()); @@ -9004,8 +9738,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } while (parentGroup != null && !parentGroup.isImportantForAutofill()) { - ignoredParentLeft += parentGroup.mLeft; - ignoredParentTop += parentGroup.mTop; + ignoredParentLeft += parentGroup.mLeft - parentGroup.mScrollX; + ignoredParentTop += parentGroup.mTop - parentGroup.mScrollY; viewParent = parentGroup.getParent(); if (viewParent instanceof View) { @@ -9090,8 +9824,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, final AccessibilityNodeInfo info = createAccessibilityNodeInfo(); structure.setChildCount(1); final ViewStructure root = structure.newChild(0); - populateVirtualStructure(root, provider, info, forAutofill); - info.recycle(); + if (info != null) { + populateVirtualStructure(root, provider, info, null, forAutofill); + info.recycle(); + } else { + Log.w(AUTOFILL_LOG_TAG, "AccessibilityNodeInfo is null."); + } } } @@ -9381,6 +10119,28 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } + /** + * @hide + */ + public void onGetCredentialResponse(GetCredentialResponse response) { + if (getPendingCredentialCallback() == null) { + Log.w(AUTOFILL_LOG_TAG, "onGetCredentialResponse called but no callback found"); + return; + } + getPendingCredentialCallback().onResult(response); + } + + /** + * @hide + */ + public void onGetCredentialException(String errorType, String errorMsg) { + if (getPendingCredentialCallback() == null) { + Log.w(AUTOFILL_LOG_TAG, "onGetCredentialException called but no callback found"); + return; + } + getPendingCredentialCallback().onError(new GetCredentialException(errorType, errorMsg)); + } + /** * Gets the unique, logical identifier of this view in the activity, for autofill purposes. * @@ -9400,6 +10160,53 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return mAutofillId; } + /** + * Returns the {@link GetCredentialRequest} associated with the view. + * If the return value is null, that means no request has been set + * on the view and no {@link CredentialManager} flow will be invoked + * when this view is focused. Traditioanl autofill flows will still + * work, autofilling content if applicable, from + * the active {@link android.service.autofill.AutofillService} on + * the device. + * + *

    See {@link #setPendingCredentialRequest} for more info. + * + * @return The credential request associated with this View. + */ + @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) + @Nullable + public final GetCredentialRequest getPendingCredentialRequest() { + if (mViewCredentialHandler == null) { + return null; + } + return mViewCredentialHandler.getRequest(); + } + + + /** + * Returns the callback that has previously been set up on this view through + * the {@link #setPendingCredentialRequest} API. + * If the return value is null, that means no callback, or request, has been set + * on the view and no {@link CredentialManager} flow will be invoked + * when this view is focused. Traditioanl autofill flows will still + * work, and autofillable content will still be returned through the + * {@link #autofill(AutofillValue)} )} API. + * + *

    See {@link #setPendingCredentialRequest} for more info. + * + * @return The callback associated with this view that will be invoked on a response from + * {@link CredentialManager} . + */ + @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) + @Nullable + public final OutcomeReceiver getPendingCredentialCallback() { + if (mViewCredentialHandler == null) { + return null; + } + return mViewCredentialHandler.getCallback(); + } + /** * Sets the unique, logical identifier of this view in the activity, for autofill purposes. * @@ -9613,10 +10420,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * *

    Note: Setting the mode as {@link #IMPORTANT_FOR_AUTOFILL_NO} or * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS} does not guarantee the view (and its - * children) will be always be considered not important; for example, when the user explicitly - * makes an autofill request, all views are considered important. See - * {@link #isImportantForAutofill()} for more details about how the View's importance for - * autofill is used. + * children) will not be used for autofill purpose; for example, when the user explicitly + * makes an autofill request, all views are included in the ViewStructure, and starting in + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} the system uses other factors along + * with importance to determine the autofill behavior. See {@link #isImportantForAutofill()} + * for more details about how the View's importance for autofill is used. * * @param mode {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, {@link #IMPORTANT_FOR_AUTOFILL_YES}, * {@link #IMPORTANT_FOR_AUTOFILL_NO}, {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, @@ -9662,21 +10470,36 @@ public class View implements Drawable.Callback, KeyEvent.Callback, *

  • otherwise, it returns {@code false}. * * - *

    When a view is considered important for autofill: - *

    - * - *

    On the other hand, when a view is considered not important for autofill: - *

    + *

    The behavior of importances depends on Android version: + *

      + *
    1. For {@link android.os.Build.VERSION_CODES#TIRAMISU} and below: + *
        + *
      1. When a view is considered important for autofill: + *
          + *
        1. The view might automatically trigger an autofill request when focused on. + *
        2. The contents of the view are included in the {@link ViewStructure} used in an + * autofill request. + *
        + *
      2. On the other hand, when a view is considered not important for autofill: + *
          + *
        1. The view never automatically triggers autofill requests, but it can trigger a + * manual request through {@link AutofillManager#requestAutofill(View)}. + *
        2. The contents of the view are not included in the {@link ViewStructure} used in + * an autofill request, unless the request has the + * {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag. + *
        + *
      + *
    2. For {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above: + *
        + *
      1. The system uses importance, along with other view properties and other optimization + * factors, to determine if a view should trigger autofill on focus. + *
      2. The contents of {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, + * {@link #IMPORTANT_FOR_AUTOFILL_YES}, {@link #IMPORTANT_FOR_AUTOFILL_NO}, + * {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, and + * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS} views will be included in the + * {@link ViewStructure} used in an autofill request. + *
      + *
    * * @return whether the view is considered important for autofill. * @@ -9753,6 +10576,93 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return false; } + /** + * Sets content sensitivity mode to determine whether this view displays sensitive content + * (e.g. username, password etc.). The system will improve user privacy i.e. hide content + * drawn by a sensitive view from screen sharing and recording. + * + *

    The window hosting a sensitive view will be marked as secure during an active media + * projection session. This would be equivalent to applying + * {@link android.view.WindowManager.LayoutParams#FLAG_SECURE} to the window. + * + * @param mode {@link #CONTENT_SENSITIVITY_AUTO}, {@link #CONTENT_SENSITIVITY_NOT_SENSITIVE} + * or {@link #CONTENT_SENSITIVITY_SENSITIVE} + */ + @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) + public final void setContentSensitivity(@ContentSensitivity int mode) { + mPrivateFlags4 &= ~PFLAG4_CONTENT_SENSITIVITY_MASK; + mPrivateFlags4 |= ((mode << PFLAG4_CONTENT_SENSITIVITY_SHIFT) + & PFLAG4_CONTENT_SENSITIVITY_MASK); + if (sensitiveContentAppProtection()) { + updateSensitiveViewsCountIfNeeded(isAggregatedVisible()); + } + } + + /** + * Gets content sensitivity mode to determine whether this view displays sensitive content. + * + *

    See {@link #setContentSensitivity(int)} and + * {@link #isContentSensitive()} for more info about this mode. + * + * @return {@link #CONTENT_SENSITIVITY_AUTO} by default, or value passed to + * {@link #setContentSensitivity(int)}. + */ + @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) + public @ContentSensitivity final int getContentSensitivity() { + return (mPrivateFlags4 & PFLAG4_CONTENT_SENSITIVITY_MASK) + >> PFLAG4_CONTENT_SENSITIVITY_SHIFT; + } + + /** + * Returns whether this view displays sensitive content, based + * on the value explicitly set by {@link #setContentSensitivity(int)}. + * + * @return whether the view displays sensitive content. + * + * @see #setContentSensitivity(int) + * @see #CONTENT_SENSITIVITY_AUTO + * @see #CONTENT_SENSITIVITY_SENSITIVE + * @see #CONTENT_SENSITIVITY_NOT_SENSITIVE + */ + @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) + public final boolean isContentSensitive() { + final int contentSensitivity = getContentSensitivity(); + if (contentSensitivity == CONTENT_SENSITIVITY_SENSITIVE) { + return true; + } else if (contentSensitivity == CONTENT_SENSITIVITY_NOT_SENSITIVE) { + return false; + } else if (sensitiveContentAppProtection()) { + return SensitiveAutofillHintsHelper + .containsSensitiveAutofillHint(getAutofillHints()); + } + return false; + } + + /** + * Helper used to track sensitive views when they are added or removed from the window + * based on whether it's laid out and visible. + * + *

    This method is called from many places (visibility changed, view laid out, view attached + * or detached to/from window, etc...) + */ + private void updateSensitiveViewsCountIfNeeded(boolean appeared) { + if (!sensitiveContentAppProtection() || mAttachInfo == null) { + return; + } + + if (appeared && isContentSensitive()) { + if ((mPrivateFlags4 & PFLAG4_IS_COUNTED_AS_SENSITIVE) == 0) { + mPrivateFlags4 |= PFLAG4_IS_COUNTED_AS_SENSITIVE; + mAttachInfo.increaseSensitiveViewsCount(); + } + } else { + if ((mPrivateFlags4 & PFLAG4_IS_COUNTED_AS_SENSITIVE) != 0) { + mPrivateFlags4 &= ~PFLAG4_IS_COUNTED_AS_SENSITIVE; + mAttachInfo.decreaseSensitiveViewsCount(); + } + } + } + /** * Gets the mode for determining whether this view is important for content capture. * @@ -9979,6 +10889,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, setNotifiedContentCaptureAppeared(); if (ai != null) { + makeParentImportantAndNotifyAppearedEventIfNeed(); ai.delayNotifyContentCaptureEvent(session, this, appeared); } else { if (DEBUG_CONTENT_CAPTURE) { @@ -10006,6 +10917,22 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } + private void makeParentImportantAndNotifyAppearedEventIfNeed() { + // If view sent the appeared event to Content Capture, Content Capture also + // would like to receive its parents' appeared events. So checks its parents + // whether the appeared event is sent or not. If not, send the appeared event. + final ViewParent parent = getParent(); + if (parent instanceof View) { + View p = ((View) parent); + if (p.getNotifiedContentCaptureAppeared()) { + return; + } + // Set important for content capture in the cache. + p.mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK; + p.notifyAppearedOrDisappearedForContentCaptureIfNeeded(/* appeared */ true); + } + } + private void setNotifiedContentCaptureAppeared() { mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; @@ -10097,36 +11024,119 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return mContext.getSystemService(AutofillManager.class); } + /** + * Check whether current activity / package is in autofill denylist. + * + * Called by viewGroup#populateChildrenForAutofill() to determine whether to include view in + * assist structure + */ + final boolean isActivityDeniedForAutofillForUnimportantView() { + final AutofillManager afm = getAutofillManager(); + if (afm == null) return false; + return afm.isActivityDeniedForAutofill(); + } + + /** + * Check whether current view matches autofillable heuristics + * + * Called by viewGroup#populateChildrenForAutofill() to determine whether to include view in + * assist structure + */ + final boolean isMatchingAutofillableHeuristics() { + final AutofillManager afm = getAutofillManager(); + if (afm == null) return false; + // check the flag to see if trigger fill request on not important views is enabled + return afm.isTriggerFillRequestOnUnimportantViewEnabled() + ? afm.isAutofillable(this) : false; + } + + /** + * Returns whether the view is autofillable. + * + * @return whether the view is autofillable, and should send out autofill request to provider. + */ private boolean isAutofillable() { - if (getAutofillType() == AUTOFILL_TYPE_NONE) return false; + if (DBG) { + Log.d(VIEW_LOG_TAG, "isAutofillable() entered."); + } + if (getAutofillType() == AUTOFILL_TYPE_NONE) { + if (DBG) { + Log.d(VIEW_LOG_TAG, "getAutofillType() returns AUTOFILL_TYPE_NONE"); + } + return false; + } - if (!isImportantForAutofill()) { - // View is not important for "regular" autofill, so we must check if Augmented Autofill - // is enabled for the activity - final AutofillOptions options = mContext.getAutofillOptions(); - if (options == null || !options.isAugmentedAutofillEnabled(mContext)) { - return false; + final AutofillManager afm = getAutofillManager(); + if (afm == null) { + if (DBG) { + Log.d(VIEW_LOG_TAG, "AutofillManager is null"); } - final AutofillManager afm = getAutofillManager(); - if (afm == null) return false; - afm.notifyViewEnteredForAugmentedAutofill(this); + return false; + } + + // Check whether view is not part of an activity. If it's not, return false. + if (getAutofillViewId() <= LAST_APP_AUTOFILL_ID) { + if (DBG) { + Log.d(VIEW_LOG_TAG, "getAutofillViewId()<=LAST_APP_AUTOFILL_ID"); + } + return false; } - return getAutofillViewId() > LAST_APP_AUTOFILL_ID; + // If view is important and filter important view flag is turned on, or view is not + // important and trigger fill request on not important view flag is turned on, then use + // AutofillManager.isAutofillable() to decide whether view is autofillable instead. + if ((isImportantForAutofill() && afm.isTriggerFillRequestOnFilteredImportantViewsEnabled()) + || (!isImportantForAutofill() + && afm.isTriggerFillRequestOnUnimportantViewEnabled())) { + if (DBG) { + Log.d(VIEW_LOG_TAG, "isImportantForAutofill(): " + isImportantForAutofill() + + "afm.isAutofillable(): " + afm.isAutofillable(this)); + } + return afm.isAutofillable(this) ? true : notifyAugmentedAutofillIfNeeded(afm); + } + + // If the previous condition is not met, fall back to the previous way to trigger fill + // request based on autofill importance instead. + if (DBG) { + Log.d(VIEW_LOG_TAG, "isImportantForAutofill(): " + isImportantForAutofill()); + } + return isImportantForAutofill() ? true : notifyAugmentedAutofillIfNeeded(afm); + } + + private boolean notifyAugmentedAutofillIfNeeded(AutofillManager afm) { + final AutofillOptions options = mContext.getAutofillOptions(); + if (options == null || !options.isAugmentedAutofillEnabled(mContext)) { + return false; + } + afm.notifyViewEnteredForAugmentedAutofill(this); + return true; } /** @hide */ public boolean canNotifyAutofillEnterExitEvent() { + if (DBG) { + Log.d(VIEW_LOG_TAG, "canNotifyAutofillEnterExitEvent() entered. " + + " isAutofillable(): " + isAutofillable() + + " isAttachedToWindow(): " + isAttachedToWindow()); + } return isAutofillable() && isAttachedToWindow(); } private void populateVirtualStructure(ViewStructure structure, AccessibilityNodeProvider provider, AccessibilityNodeInfo info, - boolean forAutofill) { + @Nullable AccessibilityNodeInfo parentInfo, boolean forAutofill) { structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), null, null, info.getViewIdResourceName()); Rect rect = structure.getTempRect(); - info.getBoundsInParent(rect); + // The bounds in parent for Jetpack Compose views aren't set as setBoundsInParent is + // deprecated, and only setBoundsInScreen is called. + // The bounds in parent can be calculated by diff'ing the child view's bounds in screen with + // the parent's. + if (sCalculateBoundsInParentFromBoundsInScreenFlagValue) { + getBoundsInParent(info, parentInfo, rect); + } else { + info.getBoundsInParent(rect); + } structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); structure.setVisibility(VISIBLE); structure.setEnabled(info.isEnabled()); @@ -10161,6 +11171,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, structure.setAutofillId(new AutofillId(getAutofillId(), AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()))); } + if (getViewCredentialHandler() != null) { + structure.setPendingCredentialRequest( + getViewCredentialHandler().getRequest(), + getViewCredentialHandler().getCallback()); + } CharSequence cname = info.getClassName(); structure.setClassName(cname != null ? cname.toString() : null); structure.setContentDescription(info.getContentDescription()); @@ -10205,13 +11220,32 @@ public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); if (cinfo != null) { ViewStructure child = structure.newChild(i); - populateVirtualStructure(child, provider, cinfo, forAutofill); + populateVirtualStructure(child, provider, cinfo, info, forAutofill); cinfo.recycle(); } } } } + private void getBoundsInParent(@NonNull AccessibilityNodeInfo info, + @Nullable AccessibilityNodeInfo parentInfo, @NonNull Rect rect) { + info.getBoundsInParent(rect); + // Fallback to calculate bounds in parent by diffing the bounds in + // screen if it's all 0. + if ((rect.left | rect.top | rect.right | rect.bottom) == 0) { + if (parentInfo != null) { + Rect parentBoundsInScreen = parentInfo.getBoundsInScreen(); + Rect boundsInScreen = info.getBoundsInScreen(); + rect.set(boundsInScreen.left - parentBoundsInScreen.left, + boundsInScreen.top - parentBoundsInScreen.top, + boundsInScreen.right - parentBoundsInScreen.left, + boundsInScreen.bottom - parentBoundsInScreen.top); + } else { + info.getBoundsInScreen(rect); + } + } + } + /** * Dispatch creation of {@link ViewStructure} down the hierarchy. The default * implementation calls {@link #onProvideStructure} and @@ -10321,11 +11355,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return; } - session.internalNotifyViewTreeEvent(/* started= */ true); + session.notifyViewTreeEvent(/* started= */ true); try { dispatchProvideContentCaptureStructure(); } finally { - session.internalNotifyViewTreeEvent(/* started= */ false); + session.notifyViewTreeEvent(/* started= */ false); } } @@ -10359,6 +11393,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, getBoundsOnScreen(bounds, true); info.setBoundsInScreen(bounds); + getBoundsInWindow(bounds, true); + info.setBoundsInWindow(bounds); ViewParent parent = getParentForAccessibility(); if (parent instanceof View) { @@ -10373,11 +11409,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, View label = rootView.findLabelForView(this, mID); if (label != null) { - info.setLabeledBy(label); + if (supportMultipleLabeledby()) { + info.addLabeledBy(label); + } else { + info.setLabeledBy(label); + } } if ((mAttachInfo.mAccessibilityFetchFlags - & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0 + & AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_REPORT_VIEW_IDS) != 0 && Resources.resourceHasPackage(mID)) { try { String viewId = getResources().getResourceName(mID); @@ -10426,6 +11466,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, info.setVisibleToUser(isVisibleToUser()); info.setImportantForAccessibility(isImportantForAccessibility()); + info.setAccessibilityDataSensitive(isAccessibilityDataSensitive()); info.setPackageName(mContext.getPackageName()); info.setClassName(getAccessibilityClassName()); info.setStateDescription(getStateDescription()); @@ -10844,6 +11885,39 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return mContentDescription; } + /** + * Returns the {@link View}'s supplemental description. + *

    + * A supplemental description provides + * brief supplemental information for this node, such as the purpose of the node when + * that purpose is not conveyed within its textual representation. For example, if a + * dropdown select has a purpose of setting font family, the supplemental description + * could be "font family". If this node has children, its supplemental description serves + * as additional information and is not intended to replace any existing information + * in the subtree. This is different from the {@link #getContentDescription()} in that + * this description is purely supplemental while a content description may be used + * to replace a description for a node or its subtree that an assistive technology + * would otherwise compute based on other properties of the node and its descendants. + * + *

    + * Note: Do not override this method, as it will have no + * effect on the supplemental description presented to accessibility services. + * You must call {@link #setSupplementalDescription(CharSequence)} to modify the + * supplemental description. + * + * @return the supplemental description + * @see #setSupplementalDescription(CharSequence) + * @see #getContentDescription() + * @attr ref android.R.styleable#View_supplementalDescription + */ + @FlaggedApi(FLAG_SUPPLEMENTAL_DESCRIPTION) + @ViewDebug.ExportedProperty(category = "accessibility") + @InspectableProperty + @Nullable + public CharSequence getSupplementalDescription() { + return mSupplementalDescription; + } + /** * Sets the {@link View}'s state description. *

    @@ -10858,6 +11932,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @param stateDescription The state description. * @see #getStateDescription() + * @see #setContentDescription(CharSequence) for the difference between content and + * state descriptions. */ @RemotableViewMethod public void setStateDescription(@Nullable CharSequence stateDescription) { @@ -10893,8 +11969,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * description. An image of a floppy disk that is used to save a file may * use "Save". * + *

    + * This should omit role or state. Role refers to the kind of user-interface element the View + * is, such as a Button or Checkbox. State refers to a frequently changing property of the View, + * such as an On/Off state of a button or the audio level of a volume slider. + * + *

    + * Content description updates are not frequent, and are used when the semantic content - not + * the state - of the element changes. For example, a Play button might change to a Pause + * button during music playback. + * * @param contentDescription The content description. * @see #getContentDescription() + * @see #setStateDescription(CharSequence)} for state changes. * @attr ref android.R.styleable#View_contentDescription */ @RemotableViewMethod @@ -10918,26 +12005,83 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Sets the id of a view before which this one is visited in accessibility traversal. - * A screen-reader must visit the content of this view before the content of the one - * it precedes. For example, if view B is set to be before view A, then a screen-reader - * will traverse the entire content of B before traversing the entire content of A, - * regardles of what traversal strategy it is using. + * Sets the {@link View}'s supplemental description. *

    - * Views that do not have specified before/after relationships are traversed in order - * determined by the screen-reader. - *

    + * A supplemental description provides + * brief supplemental information for this node, such as the purpose of the node when + * that purpose is not conveyed within its textual representation. For example, if a + * dropdown select has a purpose of setting font family, the supplemental description + * could be "font family". If this node has children, its supplemental description serves + * as additional information and is not intended to replace any existing information + * in the subtree. This is different from the {@link #setContentDescription(CharSequence)} + * in that this description is purely supplemental while a content description may be used + * to replace a description for a node or its subtree that an assistive technology + * would otherwise compute based on other properties of the node and its descendants. + * *

    - * Setting that this view is before a view that is not important for accessibility - * or if this view is not important for accessibility will have no effect as the - * screen-reader is not aware of unimportant views. - *

    + * This should omit role or state. Role refers to the kind of user-interface element the View + * is, such as a Button or Checkbox. State refers to a frequently changing property of the View, + * such as an On/Off state of a button or the audio level of a volume slider. + * + * @param supplementalDescription The supplemental description. + * @see #getSupplementalDescription() + * @see #setContentDescription(CharSequence) + * @see #setStateDescription(CharSequence) for state changes. + * @attr ref android.R.styleable#View_supplementalDescription + */ + @FlaggedApi(FLAG_SUPPLEMENTAL_DESCRIPTION) + @RemotableViewMethod + public void setSupplementalDescription(@Nullable CharSequence supplementalDescription) { + if (mSupplementalDescription == null) { + if (supplementalDescription == null) { + return; + } + } else if (mSupplementalDescription.equals(supplementalDescription)) { + return; + } + mSupplementalDescription = supplementalDescription; + final boolean nonEmptyDesc = supplementalDescription != null + && !supplementalDescription.isEmpty(); + if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { + setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); + notifySubtreeAccessibilityStateChangedIfNeeded(); + } else { + notifyViewAccessibilityStateChangedIfNeeded( + AccessibilityEvent.CONTENT_CHANGE_TYPE_SUPPLEMENTAL_DESCRIPTION); + } + } + + /** + * Sets the id of a view that screen readers are requested to visit after this view. + * + *

    + * + * For example, if view B should be visited before view A, with + * B.setAccessibilityTraversalBefore(A), this requests that screen readers visit and traverse + * view B before visiting view A. + * + *

    + * Note: Views are visited in the order determined by the screen reader. Avoid + * explicitly manipulating focus order, as this may result in inconsistent user + * experiences between apps. Instead, use other semantics, such as restructuring the view + * hierarchy layout, to communicate order. + * + *

    + * Setting this view to be after a view that is not important for accessibility, + * or if this view is not important for accessibility, means this method will have no effect if + * the service is not aware of unimportant views. + * + *

    + * To avoid a risk of loops, set clear relationships between views. For example, if focus order + * should be B -> A, and B.setAccessibilityTraversalBefore(A), then also call + * A.setAccessibilityTraversalAfter(B). * * @param beforeId The id of a view this one precedes in accessibility traversal. * * @attr ref android.R.styleable#View_accessibilityTraversalBefore * * @see #setImportantForAccessibility(int) + * @see #setAccessibilityTraversalAfter(int) */ @RemotableViewMethod public void setAccessibilityTraversalBefore(@IdRes int beforeId) { @@ -10964,26 +12108,34 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Sets the id of a view after which this one is visited in accessibility traversal. - * A screen-reader must visit the content of the other view before the content of this - * one. For example, if view B is set to be after view A, then a screen-reader - * will traverse the entire content of A before traversing the entire content of B, - * regardles of what traversal strategy it is using. + * Sets the id of a view that screen readers are requested to visit before this view. + * *

    - * Views that do not have specified before/after relationships are traversed in order - * determined by the screen-reader. - *

    + * For example, if view B should be visited after A, with B.setAccessibilityTraversalAfter(A), + * then this requests that screen readers visit and traverse view A before visiting view B. + * *

    - * Setting that this view is after a view that is not important for accessibility - * or if this view is not important for accessibility will have no effect as the - * screen-reader is not aware of unimportant views. - *

    + * Note: Views are visited in the order determined by the screen reader. Avoid + * explicitly manipulating focus order, as this may result in inconsistent user + * experiences between apps. Instead, use other semantics, such as restructuring the view + * hierarchy layout, to communicate order. + * + *

    + * Setting this view to be after a view that is not important for accessibility, + * or if this view is not important for accessibility, means this method will have no effect if + * the service is not aware of unimportant views. + * + *

    + * To avoid a risk of loops, set clear relationships between views. For example, if focus order + * should be B -> A, and B.setAccessibilityTraversalBefore(A), then also call + * A.setAccessibilityTraversalAfter(B). * - * @param afterId The id of a view this one succedees in accessibility traversal. + * @param afterId The id of a view this one succeeds in accessibility traversal. * * @attr ref android.R.styleable#View_accessibilityTraversalAfter * * @see #setImportantForAccessibility(int) + * @see #setAccessibilityTraversalBefore(int) */ @RemotableViewMethod public void setAccessibilityTraversalAfter(@IdRes int afterId) { @@ -11738,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() { @@ -11754,7 +12911,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (getSystemGestureExclusionRects().isEmpty() && collectPreferKeepClearRects().isEmpty() && collectUnrestrictedPreferKeepClearRects().isEmpty() - && (info.mHandwritingArea == null || !isAutoHandwritingEnabled())) { + && (info.mHandwritingArea == null || !shouldTrackHandwritingArea())) { if (info.mPositionUpdateListener != null) { mRenderNode.removePositionUpdateListener(info.mPositionUpdateListener); info.mPositionUpdateListener = null; @@ -12006,12 +13163,91 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Set a list of handwriting areas in this view. If there is any stylus {@link MotionEvent} - * occurs within those areas, it will trigger stylus handwriting mode. This can be disabled by + * Set the amount of offset applied to this view's stylus handwriting bounds. A positive offset + * will offset the edge outwards.The base handwriting bounds of a view is its visible bounds. + * The handwriting bounds offsets are applied to the base handwriting bounds to determine the + * final handwriting bounds. + *

    This method is mainly used to enlarge the view's handwriting bounds for a better user + * experience. + *

    Note that when the view is clipped (e.g. the view is in a + * {@link android.widget.ScrollView}), the offsets are applied after the view's handwriting + * bounds is clipped. + * + * @param offsetLeft the amount of pixel offset applied to the left edge outwards of the view's + * handwriting bounds. + * @param offsetTop the amount of pixel offset applied to the top edge outwards of the view's + * handwriting bounds. + * @param offsetRight the amount of pixel offset applied to the right edge outwards of the + * view's handwriting bounds. + * @param offsetBottom the amount of pixel offset applied to the bottom edge outwards of the + * view's handwriting bounds. + * + * @see #setAutoHandwritingEnabled(boolean) + * @see #getHandwritingBoundsOffsetLeft() + * @see #getHandwritingBoundsOffsetTop() + * @see #getHandwritingBoundsOffsetRight() + * @see #getHandwritingBoundsOffsetBottom() + */ + public void setHandwritingBoundsOffsets(float offsetLeft, float offsetTop, + float offsetRight, float offsetBottom) { + mHandwritingBoundsOffsetLeft = offsetLeft; + mHandwritingBoundsOffsetTop = offsetTop; + mHandwritingBoundsOffsetRight = offsetRight; + mHandwritingBoundsOffsetBottom = offsetBottom; + } + + /** + * Return the amount of offset applied to the left edge of this view's handwriting bounds, + * in the unit of pixel. + * + * @see #setAutoHandwritingEnabled(boolean) + * @see #setHandwritingBoundsOffsets(float, float, float, float) + */ + public float getHandwritingBoundsOffsetLeft() { + return mHandwritingBoundsOffsetLeft; + } + + /** + * Return the amount of offset applied to the top edge of this view's handwriting bounds, + * in the unit of pixel. + * + * @see #setAutoHandwritingEnabled(boolean) + * @see #setHandwritingBoundsOffsets(float, float, float, float) + */ + public float getHandwritingBoundsOffsetTop() { + return mHandwritingBoundsOffsetTop; + } + + /** + * Return the amount of offset applied to the right edge of this view's handwriting bounds, in + * the unit of pixel. + * + * @see #setAutoHandwritingEnabled(boolean) + * @see #setHandwritingBoundsOffsets(float, float, float, float) + */ + public float getHandwritingBoundsOffsetRight() { + return mHandwritingBoundsOffsetRight; + } + + /** + * Return the amount of offset applied to the bottom edge of this view's handwriting bounds, in + * the unit of pixel. + * + * @see #setAutoHandwritingEnabled(boolean) + * @see #setHandwritingBoundsOffsets(float, float, float, float) + */ + public float getHandwritingBoundsOffsetBottom() { + return mHandwritingBoundsOffsetBottom; + } + + + /** + * Set a handwriting area in this view. If there is any stylus {@link MotionEvent} + * occurs within this area, it will trigger stylus handwriting mode. This can be disabled by * disabling the auto handwriting initiation by calling * {@link #setAutoHandwritingEnabled(boolean)} with false. * - * @attr rects a list of handwriting area in the view's local coordiniates. + * @attr rect the handwriting area in the view's local coordiniates. * * @see android.view.inputmethod.InputMethodManager#startStylusHandwriting(View) * @see #setAutoHandwritingEnabled(boolean) @@ -12042,13 +13278,197 @@ public class View implements Drawable.Callback, KeyEvent.Callback, void updateHandwritingArea() { // If autoHandwritingArea is not enabled, do nothing. - if (!isAutoHandwritingEnabled()) return; + if (!shouldTrackHandwritingArea()) return; final AttachInfo ai = mAttachInfo; if (ai != null) { ai.mViewRootImpl.getHandwritingInitiator().updateHandwritingAreasForView(this); } } + /** + * Returns true if a stylus {@link MotionEvent} within this view's bounds should initiate + * handwriting mode, either for this view ({@link #isAutoHandwritingEnabled()} is {@code true}) + * or for a handwriting delegate view ({@link #getHandwritingDelegatorCallback()} is not {@code + * null}). + */ + boolean shouldInitiateHandwriting() { + return isAutoHandwritingEnabled() || getHandwritingDelegatorCallback() != null; + } + + /** + * Returns whether the handwriting initiator should track the handwriting area for this view, + * either to initiate handwriting mode, or to prepare handwriting delegation, or to show the + * handwriting unsupported message. + * @hide + */ + public boolean shouldTrackHandwritingArea() { + return shouldInitiateHandwriting(); + } + + /** + * Sets a callback which should be called when a stylus {@link MotionEvent} occurs within this + * view's bounds. The callback will be called from the UI thread. + * + *

    Setting a callback allows this view to act as a handwriting delegator, so that handwriting + * mode for a delegate editor view can be initiated by stylus movement on this delegator view. + * The callback implementation is expected to show and focus the delegate editor view. If a view + * which returns {@code true} for {@link #isHandwritingDelegate()} creates an input connection + * while the same stylus {@link MotionEvent} sequence is ongoing, handwriting mode will be + * initiated for that view. + * + *

    A common use case is a custom view which looks like a text editor but does not actually + * support text editing itself, and clicking on the custom view causes an EditText to be shown. + * To support handwriting initiation in this case, this method can be called on the custom view + * to configure it as a delegator. The EditText should call {@link #setIsHandwritingDelegate} to + * set it as a delegate. The {@code callback} implementation is typically the same as the click + * listener implementation which shows the EditText. + * + *

    If {@code null} is passed, this view will no longer act as a handwriting initiation + * delegator. + * + * @param callback a callback which should be called when a stylus {@link MotionEvent} occurs + * within this view's bounds + */ + public void setHandwritingDelegatorCallback(@Nullable Runnable callback) { + mHandwritingDelegatorCallback = callback; + if (callback != null) { + setHandwritingArea(new Rect(0, 0, getWidth(), getHeight())); + } + } + + /** + * Returns the callback set by {@link #setHandwritingDelegatorCallback} which should be called + * when a stylus {@link MotionEvent} occurs within this view's bounds. The callback should only + * be called from the UI thread. + */ + @Nullable + public Runnable getHandwritingDelegatorCallback() { + return mHandwritingDelegatorCallback; + } + + /** + * Specifies that this view may act as a handwriting initiation delegator for a delegate editor + * view from the specified package. If this method is not called, delegators may only be used to + * initiate handwriting mode for a delegate editor view from the same package as the delegator + * view. This method allows specifying a different trusted package which may contain a delegate + * editor view linked to this delegator view. + * + *

    This method has no effect unless {@link #setHandwritingDelegatorCallback} is also called + * to configure this view to act as a handwriting delegator. + * + *

    If this method is called on the delegator view, then {@link + * #setAllowedHandwritingDelegatorPackage} should also be called on the delegate editor view. + * + *

    For example, to configure a delegator view in package 1: + * + *

    +     * delegatorView.setHandwritingDelegatorCallback(callback);
    +     * delegatorView.setAllowedHandwritingDelegatePackage(package2);
    + * + * Then to configure the corresponding delegate editor view in package 2: + * + *
    +     * delegateEditorView.setIsHandwritingDelegate(true);
    +     * delegateEditorView.setAllowedHandwritingDelegatorPackage(package1);
    + * + * @param allowedPackageName the package name of a delegate editor view linked to this delegator + * view, or {@code null} to restore the default behavior of only allowing delegate editor + * views from the same package as this delegator view + */ + public void setAllowedHandwritingDelegatePackage(@Nullable String allowedPackageName) { + mAllowedHandwritingDelegatePackageName = allowedPackageName; + } + + /** + * Returns the allowed package for delegate editor views for which this view may act as a + * handwriting delegator, as set by {@link #setAllowedHandwritingDelegatePackage}. If {@link + * #setAllowedHandwritingDelegatePackage} has not been called, or called with {@code null} + * argument, this will return {@code null}, meaning that this delegator view may only be used to + * initiate handwriting mode for a delegate editor view from the same package as this delegator + * view. + */ + @Nullable + public String getAllowedHandwritingDelegatePackageName() { + return mAllowedHandwritingDelegatePackageName; + } + + /** + * Sets this view to be a handwriting delegate. If a delegate view creates an input connection + * while a stylus {@link MotionEvent} sequence from a delegator view is ongoing, handwriting + * mode will be initiated for the delegate view. + * + * @param isHandwritingDelegate whether this view is a handwriting initiation delegate + * @see #setHandwritingDelegatorCallback(Runnable) + */ + public void setIsHandwritingDelegate(boolean isHandwritingDelegate) { + mIsHandwritingDelegate = isHandwritingDelegate; + } + + /** + * Returns whether this view has been set as a handwriting delegate by {@link + * #setIsHandwritingDelegate}. + */ + public boolean isHandwritingDelegate() { + return mIsHandwritingDelegate; + } + + /** + * Specifies that a view from the specified package may act as a handwriting delegator for this + * delegate editor view. If this method is not called, only views from the same package as this + * delegate editor view may act as a handwriting delegator. This method allows specifying a + * different trusted package which may contain a delegator view linked to this delegate editor + * view. + * + *

    This method has no effect unless {@link #setIsHandwritingDelegate} is also called to + * configure this view to act as a handwriting delegate. + * + *

    If this method is called on the delegate editor view, then {@link + * #setAllowedHandwritingDelegatePackage} should also be called on the delegator view. + * + * @param allowedPackageName the package name of a delegator view linked to this delegate editor + * view, or {@code null} to restore the default behavior of only allowing delegator views + * from the same package as this delegate editor view + */ + public void setAllowedHandwritingDelegatorPackage(@Nullable String allowedPackageName) { + mAllowedHandwritingDelegatorPackageName = allowedPackageName; + } + + /** + * Returns the allowed package for views which may act as a handwriting delegator for this + * delegate editor view, as set by {@link #setAllowedHandwritingDelegatorPackage}. If {@link + * #setAllowedHandwritingDelegatorPackage} has not been called, or called with {@code null} + * argument, this will return {@code null}, meaning that only views from the same package as + * this delegator editor view may act as a handwriting delegator. + */ + @Nullable + public String getAllowedHandwritingDelegatorPackageName() { + return mAllowedHandwritingDelegatorPackageName; + } + + /** + * Sets flags configuring the handwriting delegation behavior for this delegate editor view. + * + *

    This method has no effect unless {@link #setIsHandwritingDelegate} is also called to + * configure this view to act as a handwriting delegate. + * + * @param flags {@link InputMethodManager#HANDWRITING_DELEGATE_FLAG_HOME_DELEGATOR_ALLOWED} or + * {@code 0} + */ + @FlaggedApi(FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR) + public void setHandwritingDelegateFlags( + @InputMethodManager.HandwritingDelegateFlags int flags) { + mHandwritingDelegateFlags = flags; + } + + /** + * Returns flags configuring the handwriting delegation behavior for this delegate editor view, + * as set by {@link #setHandwritingDelegateFlags}. + */ + @FlaggedApi(FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR) + public @InputMethodManager.HandwritingDelegateFlags int getHandwritingDelegateFlags() { + return mHandwritingDelegateFlags; + } + /** * Gets the coordinates of this view in the coordinate space of the * {@link Surface} that contains the view. @@ -12174,6 +13594,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } + /** + * @return True if the window has the {@link OnContentApplyWindowInsetsListener}, and this means + * the framework will apply window insets on the content of the window. + * @hide + */ + protected boolean hasContentOnApplyWindowInsetsListener() { + return mAttachInfo != null && mAttachInfo.mContentOnApplyWindowInsetsListener != null; + } + /** * Sets whether or not this view should account for system screen decorations * such as the status bar and inset its content; that is, controlling whether @@ -12333,6 +13762,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (!enabled) { cancelPendingInputEvents(); } + notifyViewAccessibilityStateChangedIfNeeded( + AccessibilityEvent.CONTENT_CHANGE_TYPE_ENABLED); } /** @@ -12431,6 +13862,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } else { mAutofillHints = autofillHints; } + if (sensitiveContentAppProtection()) { + if (getContentSensitivity() == CONTENT_SENSITIVITY_AUTO) { + updateSensitiveViewsCountIfNeeded(isAggregatedVisible()); + } + } } /** @@ -12600,11 +14036,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, }) @ResolvedLayoutDir public int getLayoutDirection() { - final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; - if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { - mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; - return LAYOUT_DIRECTION_RESOLVED_DEFAULT; - } return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; } @@ -12709,7 +14140,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (mViewTranslationCallback != null) { mViewTranslationCallback.onClearTranslation(this); } - clearViewTranslationCallback(); clearViewTranslationResponse(); if (hasTranslationTransientState()) { setHasTransientState(false); @@ -13079,6 +14509,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public void setFilterTouchesWhenObscured(boolean enabled) { setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, FILTER_TOUCHES_WHEN_OBSCURED); + calculateAccessibilityDataSensitive(); } /** @@ -13161,6 +14592,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Returns whether the view should be treated as a focusable unit by screen reader * accessibility tools. + *

    + * Note: Use + * {@link androidx.core.view.ViewCompat#setScreenReaderFocusable(View, boolean)} + * for backwards-compatibility. * @see #setScreenReaderFocusable(boolean) * * @return Whether the view should be treated as a focusable unit by screen reader. @@ -13202,6 +14637,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Set if view is a heading for a section of content for accessibility purposes. + *

    + * Users of some accessibility services can choose to navigate between headings + * instead of between paragraphs, words, etc. Apps that provide headings on + * sections of text can help the text navigation experience. + *

    + * Note: Use {@link androidx.core.view.ViewCompat#setAccessibilityHeading(View, boolean)} + * for backwards-compatibility. * * @param isHeading {@code true} if the view is a heading, {@code false} otherwise. * @@ -13712,6 +15154,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * See also {@link #focusSearch(int)}, which is what you call to say that you * have focus, and you want your parent to look for the next one. * + *

    + * Note: Avoid setting accessibility focus. This is intended to be controlled by screen + * readers. Apps changing focus can confuse screen readers, so the resulting behavior can vary + * by device and screen reader version. + * * @return Whether this view actually took accessibility focus. * * @hide @@ -13775,7 +15222,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // working solution. View source = this; while (true) { - if (source.includeForAccessibility()) { + if (source.includeForAccessibility(false)) { source.sendAccessibilityEvent(eventType); return; } @@ -14044,19 +15491,57 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * to the view's content description or text, or to the content descriptions * or text of the view's children (where applicable). *

    - * For example, in a login screen with a TextView that displays an "incorrect - * password" notification, that view should be marked as a live region with - * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. + * Different priority levels are available: + *

    *

    - * To disable change notifications for this view, use - * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region - * mode for most views. + * Examples: + *

    + *

    + * For error notifications, like an "incorrect password" warning in a login screen, views + * should send a {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} + * {@code AccessibilityEvent} with a content change type + * {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_ERROR} and set + * {@link AccessibilityNodeInfo#setError(CharSequence)}. Custom widgets should provide + * error-setting methods that support accessibility. For example, use + * {@link android.widget.TextView#setError(CharSequence)} instead of explicitly sending events. *

    - * To indicate that the user should be notified of changes, use - * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. + * Don't use live regions for frequently-updating UI elements (e.g., progress bars), as this can + * overwhelm the user with feedback from accessibility services. If necessary, use + * {@link AccessibilityNodeInfo#setMinDurationBetweenContentChanges(Duration)} to throttle + * feedback and reduce disruptions. *

    - * If the view's changes should interrupt ongoing speech and notify the user - * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. + *

    * * @param mode The live region mode for this view, one of: *