View-without-comments.java
unknown
java
4 months ago
666 kB
29
No Index
in 8 months
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_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_GTE; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED; 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.enableUseMeasureCacheDuringForceLayout; import static android.view.flags.Flags.sensitiveContentAppProtection; 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.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 java.lang.Math.max; import android.animation.AnimatorInflater; import android.animation.StateListAnimator; 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; import android.annotation.IntRange; import android.annotation.LayoutRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.Size; import android.annotation.StyleRes; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; import android.annotation.UiContext; import android.annotation.UiThread; import android.app.PendingIntent; import android.compat.annotation.UnsupportedAppUsage; import android.content.AutofillOptions; import android.content.ClipData; 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; import android.graphics.Color; import android.graphics.Insets; import android.graphics.Interpolator; import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Outline; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.RecordingCanvas; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.graphics.RenderEffect; import android.graphics.RenderNode; import android.graphics.Shader; 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.os.Vibrator; import android.os.vibrator.Flags; 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; import android.util.LongSparseArray; import android.util.LongSparseLongArray; import android.util.Pair; import android.util.Pools.SynchronizedPool; import android.util.Property; 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; import android.view.AccessibilityIterators.TextSegmentIterator; import android.view.AccessibilityIterators.WordTextSegmentIterator; import android.view.ContextMenu.ContextMenuInfo; import android.view.InputDevice.InputSourceClass; import android.view.Window.OnContentApplyWindowInsetsListener; import android.view.WindowInsets.Type; import android.view.WindowInsetsAnimation.Bounds; import android.view.WindowManager.LayoutParams; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityEventSource; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeIdManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.view.accessibility.AccessibilityNodeProvider; import android.view.accessibility.AccessibilityWindowInfo; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.Transformation; import android.view.autofill.AutofillId; import android.view.autofill.AutofillManager; import android.view.autofill.AutofillValue; import android.view.contentcapture.ContentCaptureContext; import android.view.contentcapture.ContentCaptureManager; import android.view.contentcapture.ContentCaptureSession; import android.view.displayhash.DisplayHash; 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; import android.view.translation.TranslationCapability; import android.view.translation.TranslationSpec.DataFormat; import android.view.translation.ViewTranslationCallback; import android.view.translation.ViewTranslationRequest; import android.view.translation.ViewTranslationResponse; import android.widget.Checkable; import android.widget.ScrollBarDrawable; import android.window.OnBackInvokedDispatcher; import com.android.internal.R; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.Preconditions; import com.android.internal.view.ScrollCaptureInternal; import com.android.internal.view.TooltipPopup; import com.android.internal.view.menu.MenuBuilder; import com.android.internal.widget.ScrollBarUtils; import com.google.android.collect.Lists; import com.google.android.collect.Maps; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; 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; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.function.Predicate; @UiThread public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private static final boolean DBG = false; public static boolean DEBUG_DRAW = false; protected static final String VIEW_LOG_TAG = "View"; private static final String AUTOFILL_LOG_TAG = "View.Autofill"; private static final String CONTENT_CAPTURE_LOG_TAG = "View.ContentCapture"; private static final boolean DEBUG_CONTENT_CAPTURE = false; public static boolean sDebugViewAttributes = false; public static String sDebugViewAttributesApplicationPackage; public static final int NO_ID = -1; public static final int LAST_APP_AUTOFILL_ID = Integer.MAX_VALUE / 2; private static final int[] AUTOFILL_HIGHLIGHT_ATTR = new int[]{android.R.attr.autofilledHighlight}; private static boolean sCompatibilityDone = false; public HapticScrollFeedbackProvider mScrollFeedbackProvider = null; private static boolean sAlwaysRemeasureExactly = false; private static boolean sUseMeasureCacheDuringForceLayoutFlagValue; static boolean sTextureViewIgnoresDrawableSetters = false; protected static boolean sPreserveMarginParamsInLayoutParamConversion; static boolean sCascadedDragDrop; static boolean sHasFocusableExcludeAutoFocusable; private static boolean sAutoFocusableOffUIThreadWontNotifyParents; private static boolean sThrowOnInvalidFloatProperties; private static boolean sAcceptZeroSizeDragShadow; private static boolean sTraceLayoutSteps; private static String sTraceRequestLayoutClass; @Nullable private ViewCredentialHandler mViewCredentialHandler; @Nullable private ViewTraversalTracingStrings mTracingStrings; static boolean sBrokenInsetsDispatch; protected static boolean sBrokenWindowBackground; static boolean sForceLayoutWhenInsetsChanged; @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) @Retention(RetentionPolicy.SOURCE) public @interface Focusable {} public static final int NOT_FOCUSABLE = 0x00000000; public static final int FOCUSABLE = 0x00000001; public static final int FOCUSABLE_AUTO = 0x00000010; private static final int FOCUSABLE_MASK = 0x00000011; private static final int FITS_SYSTEM_WINDOWS = 0x00000002; @IntDef({VISIBLE, INVISIBLE, GONE}) @Retention(RetentionPolicy.SOURCE) public @interface Visibility {} public static final int VISIBLE = 0x00000000; public static final int INVISIBLE = 0x00000004; public static final int GONE = 0x00000008; static final int VISIBILITY_MASK = 0x0000000C; private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress"; public static final String AUTOFILL_HINT_NAME = "name"; public static final String AUTOFILL_HINT_USERNAME = "username"; public static final String AUTOFILL_HINT_PASSWORD = "password"; public static final String AUTOFILL_HINT_PHONE = "phone"; public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress"; public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode"; public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber"; public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode"; public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = "creditCardExpirationDate"; public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = "creditCardExpirationMonth"; public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = "creditCardExpirationYear"; public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay"; public static final String AUTOFILL_HINT_PASSWORD_AUTO = "passwordAuto"; public static final String AUTOFILL_HINT_CREDENTIAL_MANAGER = "credential"; private @Nullable String[] mAutofillHints; private AutofillId mAutofillId; @IntDef(prefix = { "AUTOFILL_TYPE_" }, value = { AUTOFILL_TYPE_NONE, AUTOFILL_TYPE_TEXT, AUTOFILL_TYPE_TOGGLE, AUTOFILL_TYPE_LIST, AUTOFILL_TYPE_DATE, }) @Retention(RetentionPolicy.SOURCE) public @interface AutofillType {} public static final int AUTOFILL_TYPE_NONE = 0; public static final int AUTOFILL_TYPE_TEXT = 1; public static final int AUTOFILL_TYPE_TOGGLE = 2; public static final int AUTOFILL_TYPE_LIST = 3; public static final int AUTOFILL_TYPE_DATE = 4; @IntDef(prefix = { "IMPORTANT_FOR_AUTOFILL_" }, value = { IMPORTANT_FOR_AUTOFILL_AUTO, IMPORTANT_FOR_AUTOFILL_YES, IMPORTANT_FOR_AUTOFILL_NO, IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS }) @Retention(RetentionPolicy.SOURCE) public @interface AutofillImportance {} public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0x0; public static final int IMPORTANT_FOR_AUTOFILL_YES = 0x1; public static final int IMPORTANT_FOR_AUTOFILL_NO = 0x2; public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 0x4; public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8; @IntDef(flag = true, prefix = { "AUTOFILL_FLAG_" }, value = { AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS }) @Retention(RetentionPolicy.SOURCE) public @interface AutofillFlags {} public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x1; @IntDef(prefix = { "IMPORTANT_FOR_CONTENT_CAPTURE_" }, value = { IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, IMPORTANT_FOR_CONTENT_CAPTURE_YES, IMPORTANT_FOR_CONTENT_CAPTURE_NO, IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS }) @Retention(RetentionPolicy.SOURCE) public @interface ContentCaptureImportance {} public static final int IMPORTANT_FOR_CONTENT_CAPTURE_AUTO = 0x0; public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES = 0x1; public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO = 0x2; public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS = 0x4; public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS = 0x8; @IntDef(flag = true, prefix = {"SCROLL_CAPTURE_HINT_"}, value = { SCROLL_CAPTURE_HINT_AUTO, SCROLL_CAPTURE_HINT_EXCLUDE, SCROLL_CAPTURE_HINT_INCLUDE, SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS }) @Retention(RetentionPolicy.SOURCE) public @interface ScrollCaptureHint {} public static final int SCROLL_CAPTURE_HINT_AUTO = 0; public static final int SCROLL_CAPTURE_HINT_EXCLUDE = 0x1; public static final int SCROLL_CAPTURE_HINT_INCLUDE = 0x2; public static final int SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS = 0x4; static final int ENABLED = 0x00000000; static final int DISABLED = 0x00000020; static final int ENABLED_MASK = 0x00000020; static final int WILL_NOT_DRAW = 0x00000080; static final int DRAW_MASK = 0x00000080; static final int SCROLLBARS_NONE = 0x00000000; static final int SCROLLBARS_HORIZONTAL = 0x00000100; static final int SCROLLBARS_VERTICAL = 0x00000200; static final int SCROLLBARS_MASK = 0x00000300; static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; static final int FADING_EDGE_NONE = 0x00000000; static final int FADING_EDGE_HORIZONTAL = 0x00001000; static final int FADING_EDGE_VERTICAL = 0x00002000; static final int FADING_EDGE_MASK = 0x00003000; static final int CLICKABLE = 0x00004000; static final int DRAWING_CACHE_ENABLED = 0x00008000; static final int SAVE_DISABLED = 0x000010000; static final int SAVE_DISABLED_MASK = 0x000010000; static final int WILL_NOT_CACHE_DRAWING = 0x000020000; static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "DRAWING_CACHE_QUALITY_" }, value = { DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH, DRAWING_CACHE_QUALITY_AUTO }) public @interface DrawingCacheQuality {} @Deprecated public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; @Deprecated public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; @Deprecated public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH }; static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; static final int LONG_CLICKABLE = 0x00200000; static final int DUPLICATE_PARENT_STATE = 0x00400000; static final int CONTEXT_CLICKABLE = 0x00800000; @IntDef(prefix = { "SCROLLBARS_" }, value = { SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, SCROLLBARS_OUTSIDE_OVERLAY, SCROLLBARS_OUTSIDE_INSET }) @Retention(RetentionPolicy.SOURCE) public @interface ScrollBarStyle {} public static final int SCROLLBARS_INSIDE_OVERLAY = 0; public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; static final int SCROLLBARS_INSET_MASK = 0x01000000; static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; static final int SCROLLBARS_STYLE_MASK = 0x03000000; public static final int KEEP_SCREEN_ON = 0x04000000; public static final int SOUND_EFFECTS_ENABLED = 0x08000000; public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; static final int PARENT_SAVE_DISABLED = 0x20000000; static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; private static Paint sDebugPaint; static final int TOOLTIP = 0x40000000; @IntDef(prefix = { "CONTENT_SENSITIVITY_" }, value = { CONTENT_SENSITIVITY_AUTO, CONTENT_SENSITIVITY_SENSITIVE, CONTENT_SENSITIVITY_NOT_SENSITIVE }) @Retention(RetentionPolicy.SOURCE) public @interface ContentSensitivity {} @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) public static final int CONTENT_SENSITIVITY_AUTO = 0x0; @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) public static final int CONTENT_SENSITIVITY_SENSITIVE = 0x1; @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) public static final int CONTENT_SENSITIVITY_NOT_SENSITIVE = 0x2; @IntDef(flag = true, prefix = { "FOCUSABLES_" }, value = { FOCUSABLES_ALL, FOCUSABLES_TOUCH_MODE }) @Retention(RetentionPolicy.SOURCE) public @interface FocusableMode {} public static final int FOCUSABLES_ALL = 0x00000000; public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; @IntDef(prefix = { "FOCUS_" }, value = { FOCUS_BACKWARD, FOCUS_FORWARD, FOCUS_LEFT, FOCUS_UP, FOCUS_RIGHT, FOCUS_DOWN }) @Retention(RetentionPolicy.SOURCE) public @interface FocusDirection {} @IntDef(prefix = { "FOCUS_" }, value = { FOCUS_LEFT, FOCUS_UP, FOCUS_RIGHT, FOCUS_DOWN }) @Retention(RetentionPolicy.SOURCE) public @interface FocusRealDirection {} public static final int FOCUS_BACKWARD = 0x00000001; public static final int FOCUS_FORWARD = 0x00000002; public static final int FOCUS_LEFT = 0x00000011; public static final int FOCUS_UP = 0x00000021; public static final int FOCUS_RIGHT = 0x00000042; public static final int FOCUS_DOWN = 0x00000082; public static final int MEASURED_SIZE_MASK = 0x00ffffff; public static final int MEASURED_STATE_MASK = 0xff000000; public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; protected static final int[] EMPTY_STATE_SET; protected static final int[] ENABLED_STATE_SET; protected static final int[] FOCUSED_STATE_SET; protected static final int[] SELECTED_STATE_SET; protected static final int[] PRESSED_STATE_SET; protected static final int[] WINDOW_FOCUSED_STATE_SET; protected static final int[] ENABLED_FOCUSED_STATE_SET; protected static final int[] ENABLED_SELECTED_STATE_SET; protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; protected static final int[] FOCUSED_SELECTED_STATE_SET; protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; protected static final int[] PRESSED_SELECTED_STATE_SET; protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; protected static final int[] PRESSED_FOCUSED_STATE_SET; protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; protected static final int[] PRESSED_ENABLED_STATE_SET; protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; public static final int FRAME_RATE_CATEGORY_REASON_UNKNOWN = 0x0000_0000; public static final int FRAME_RATE_CATEGORY_REASON_SMALL = 0x0100_0000; public static final int FRAME_RATE_CATEGORY_REASON_INTERMITTENT = 0x0200_0000; public static final int FRAME_RATE_CATEGORY_REASON_LARGE = 0x03000000; public static final int FRAME_RATE_CATEGORY_REASON_REQUESTED = 0x0400_0000; public static final int FRAME_RATE_CATEGORY_REASON_INVALID = 0x0500_0000; public static final int FRAME_RATE_CATEGORY_REASON_VELOCITY = 0x0600_0000; public static final int FRAME_RATE_CATEGORY_REASON_BOOST = 0x0800_0000; public static final int FRAME_RATE_CATEGORY_REASON_TOUCH = 0x0900_0000; public static final int FRAME_RATE_CATEGORY_REASON_CONFLICTED = 0x0A00_0000; private static final int FRAME_RATE_CATEGORY_REASON_MASK = 0xFFFF_0000; 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(); @Surface.FrameRateCompatibility int mFrameRateCompatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; static { EMPTY_STATE_SET = StateSet.get(0); WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); FOCUSED_SELECTED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); ENABLED_SELECTED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); ENABLED_FOCUSED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); PRESSED_SELECTED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); PRESSED_FOCUSED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); PRESSED_ENABLED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 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(); sUseMeasureCacheDuringForceLayoutFlagValue = enableUseMeasureCacheDuringForceLayout(); } private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = AccessibilityEvent.TYPE_VIEW_CLICKED | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED | AccessibilityEvent.TYPE_VIEW_SELECTED | AccessibilityEvent.TYPE_VIEW_FOCUSED | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); static final int DEBUG_CORNERS_SIZE_DIP = 8; static final ThreadLocal<Rect> sThreadLocal = ThreadLocal.withInitial(Rect::new); @UnsupportedAppUsage private SparseArray<Object> mKeyedTags; private static int sNextAccessibilityViewId; protected Animation mCurrentAnimation = null; @ViewDebug.ExportedProperty(category = "measurement") @UnsupportedAppUsage int mMeasuredWidth; @ViewDebug.ExportedProperty(category = "measurement") @UnsupportedAppUsage int mMeasuredHeight; @UnsupportedAppUsage boolean mRecreateDisplayList = false; @IdRes @ViewDebug.ExportedProperty(resolveId = true) int mID = NO_ID; private int mAutofillViewId = NO_ID; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int mAccessibilityViewId = NO_ID; private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) protected Object mTag = null; static final int PFLAG_WANTS_FOCUS = 0x00000001; static final int PFLAG_FOCUSED = 0x00000002; static final int PFLAG_SELECTED = 0x00000004; static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; static final int PFLAG_HAS_BOUNDS = 0x00000010; static final int PFLAG_DRAWN = 0x00000020; static final int PFLAG_DRAW_ANIMATION = 0x00000040; static final int PFLAG_SKIP_DRAW = 0x00000080; static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; static final int PFLAG_FORCE_LAYOUT = 0x00001000; static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; private static final int PFLAG_PRESSED = 0x00004000; static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; static final int PFLAG_ANIMATION_STARTED = 0x00010000; private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; static final int PFLAG_ALPHA_SET = 0x00040000; static final int PFLAG_SCROLL_CONTAINER = 0x00080000; static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; static final int PFLAG_DIRTY = 0x00200000; static final int PFLAG_DIRTY_MASK = 0x00200000; static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; static final int PFLAG_OPAQUE_MASK = 0x01800000; private static final int PFLAG_PREPRESSED = 0x02000000; static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; private static final int PFLAG_HOVERED = 0x10000000; private static final int PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK = 0x20000000; static final int PFLAG_ACTIVATED = 0x40000000; static final int PFLAG_INVALIDATED = 0x80000000; static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; static final int PFLAG2_DRAG_HOVERED = 0x00000002; @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { LAYOUT_DIRECTION_LTR, LAYOUT_DIRECTION_RTL, LAYOUT_DIRECTION_INHERIT, LAYOUT_DIRECTION_LOCALE }) @Retention(RetentionPolicy.SOURCE) public @interface LayoutDir {} @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { LAYOUT_DIRECTION_LTR, LAYOUT_DIRECTION_RTL }) @Retention(RetentionPolicy.SOURCE) public @interface ResolvedLayoutDir {} public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; private static final int[] LAYOUT_DIRECTION_FLAGS = { LAYOUT_DIRECTION_LTR, LAYOUT_DIRECTION_RTL, LAYOUT_DIRECTION_INHERIT, LAYOUT_DIRECTION_LOCALE }; private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; public static final int TEXT_DIRECTION_INHERIT = 0; public static final int TEXT_DIRECTION_FIRST_STRONG = 1; public static final int TEXT_DIRECTION_ANY_RTL = 2; public static final int TEXT_DIRECTION_LTR = 3; public static final int TEXT_DIRECTION_RTL = 4; public static final int TEXT_DIRECTION_LOCALE = 5; public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT }; static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; @IntDef(prefix = { "TEXT_ALIGNMENT_" }, value = { TEXT_ALIGNMENT_INHERIT, TEXT_ALIGNMENT_GRAVITY, TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_TEXT_START, TEXT_ALIGNMENT_TEXT_END, TEXT_ALIGNMENT_VIEW_START, TEXT_ALIGNMENT_VIEW_END }) @Retention(RetentionPolicy.SOURCE) public @interface TextAlignment {} public static final int TEXT_ALIGNMENT_INHERIT = 0; public static final int TEXT_ALIGNMENT_GRAVITY = 1; public static final int TEXT_ALIGNMENT_TEXT_START = 2; public static final int TEXT_ALIGNMENT_TEXT_END = 3; public static final int TEXT_ALIGNMENT_CENTER = 4; public static final int TEXT_ALIGNMENT_VIEW_START = 5; public static final int TEXT_ALIGNMENT_VIEW_END = 6; private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT }; static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; public static final int ACCESSIBILITY_DATA_SENSITIVE_AUTO = 0x00000000; public static final int ACCESSIBILITY_DATA_SENSITIVE_YES = 0x00000001; public static final int ACCESSIBILITY_DATA_SENSITIVE_NO = 0x00000002; @IntDef(prefix = { "ACCESSIBILITY_DATA_SENSITIVE_" }, value = { ACCESSIBILITY_DATA_SENSITIVE_AUTO, ACCESSIBILITY_DATA_SENSITIVE_YES, ACCESSIBILITY_DATA_SENSITIVE_NO, }) @Retention(RetentionPolicy.SOURCE) public @interface AccessibilityDataSensitive {} static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; static final int PFLAG2_PADDING_RESOLVED = 0x20000000; static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_PADDING_RESOLVED | PFLAG2_DRAWABLE_RESOLVED; static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; static final int PFLAG3_IS_LAID_OUT = 0x4; static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; static final int PFLAG3_CALLED_SUPER = 0x10; static final int PFLAG3_APPLYING_INSETS = 0x20; static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; static final int SCROLL_INDICATORS_NONE = 0x0000; static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START | PFLAG3_SCROLL_INDICATOR_END; static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; @Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, prefix = { "SCROLL_INDICATOR_" }, value = { SCROLL_INDICATOR_TOP, SCROLL_INDICATOR_BOTTOM, SCROLL_INDICATOR_LEFT, SCROLL_INDICATOR_RIGHT, SCROLL_INDICATOR_START, SCROLL_INDICATOR_END, }) public @interface ScrollIndicators {} public static final int SCROLL_INDICATOR_TOP = PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; public static final int SCROLL_INDICATOR_BOTTOM = PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; public static final int SCROLL_INDICATOR_LEFT = PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; public static final int SCROLL_INDICATOR_RIGHT = PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; public static final int SCROLL_INDICATOR_START = PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; public static final int SCROLL_INDICATOR_END = PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; static final int PFLAG3_ASSIST_BLOCKED = 0x4000; private static final int PFLAG3_CLUSTER = 0x8000; private static final int PFLAG3_IS_AUTOFILLED = 0x10000; private static final int PFLAG3_FINGER_DOWN = 0x20000; private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000; static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT = 19; static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK = (IMPORTANT_FOR_AUTOFILL_AUTO | IMPORTANT_FOR_AUTOFILL_YES | IMPORTANT_FOR_AUTOFILL_NO | IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS | IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS) << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x8000000; private static final int PFLAG3_SCREEN_READER_FOCUSABLE = 0x10000000; private static final int PFLAG3_AGGREGATED_VISIBLE = 0x20000000; private static final int PFLAG3_AUTOFILLID_EXPLICITLY_SET = 0x40000000; private static final int PFLAG3_ACCESSIBILITY_HEADING = 0x80000000; private static final int PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO | IMPORTANT_FOR_CONTENT_CAPTURE_YES | IMPORTANT_FOR_CONTENT_CAPTURE_NO | IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS | IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS; private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED = 0x10; private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED = 0x20; private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED = 0x40; private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE = 0x80; private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK = PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED | PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; static final int PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS = 0x000000100; private static final int PFLAG4_AUTOFILL_HIDE_HIGHLIGHT = 0x200; static final int PFLAG4_SCROLL_CAPTURE_HINT_SHIFT = 10; static final int PFLAG4_SCROLL_CAPTURE_HINT_MASK = (SCROLL_CAPTURE_HINT_INCLUDE | SCROLL_CAPTURE_HINT_EXCLUDE | SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS) << PFLAG4_SCROLL_CAPTURE_HINT_SHIFT; private static final int PFLAG4_ALLOW_CLICK_WHEN_DISABLED = 0x000001000; private static final int PFLAG4_DETACHED = 0x000002000; private static final int PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE = 0x000004000; private static final int PFLAG4_DRAG_A11Y_STARTED = 0x000008000; private static final int PFLAG4_AUTO_HANDWRITING_ENABLED = 0x000010000; private static final int PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER = 0x000020000; private static final int PFLAG4_TRAVERSAL_TRACING_ENABLED = 0x000040000; private static final int PFLAG4_RELAYOUT_TRACING_ENABLED = 0x000080000; private static final int PFLAG4_ROTARY_HAPTICS_DETERMINED = 0x100000; private static final int PFLAG4_ROTARY_HAPTICS_ENABLED = 0x200000; private static final int PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT = 0x400000; private static final int PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT = 0x800000; private static final int PFLAG4_CONTENT_SENSITIVITY_SHIFT = 24; private static final int PFLAG4_CONTENT_SENSITIVITY_MASK = (CONTENT_SENSITIVITY_AUTO | CONTENT_SENSITIVITY_SENSITIVE | CONTENT_SENSITIVITY_NOT_SENSITIVE) << PFLAG4_CONTENT_SENSITIVITY_SHIFT; private static final int PFLAG4_IS_COUNTED_AS_SENSITIVE = 0x4000000; private static final int PFLAG4_HAS_DRAWN = 0x8000000; private static final int PFLAG4_HAS_MOVED = 0x10000000; private static final int PFLAG4_HAS_VIEW_PROPERTY_INVALIDATION = 0x20000000; protected static final int VIEW_STRUCTURE_FOR_ASSIST = 0; protected static final int VIEW_STRUCTURE_FOR_AUTOFILL = 1; protected static final int VIEW_STRUCTURE_FOR_CONTENT_CAPTURE = 2; @IntDef(flag = true, prefix = { "VIEW_STRUCTURE_FOR" }, value = { VIEW_STRUCTURE_FOR_ASSIST, VIEW_STRUCTURE_FOR_AUTOFILL, VIEW_STRUCTURE_FOR_CONTENT_CAPTURE }) @Retention(RetentionPolicy.SOURCE) public @interface ViewStructureType {} public static final int OVER_SCROLL_ALWAYS = 0; public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; public static final int OVER_SCROLL_NEVER = 2; @Deprecated public static final int SYSTEM_UI_FLAG_VISIBLE = 0; @Deprecated public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; @Deprecated public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; @Deprecated public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; @Deprecated public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; @Deprecated public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; @Deprecated public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; @Deprecated public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; @Deprecated public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; @Deprecated public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; @Deprecated public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; @Deprecated public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; @UnsupportedAppUsage public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; @UnsupportedAppUsage public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; @UnsupportedAppUsage public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; public static final int STATUS_BAR_DISABLE_ONGOING_CALL_CHIP = 0x04000000; public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; public static final int SYSTEM_UI_CLEARABLE_FLAGS = SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION | SYSTEM_UI_FLAG_FULLSCREEN; @Deprecated public static final int SYSTEM_UI_LAYOUT_FLAGS = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; @IntDef(flag = true, prefix = { "FIND_VIEWS_" }, value = { FIND_VIEWS_WITH_TEXT, FIND_VIEWS_WITH_CONTENT_DESCRIPTION }) @Retention(RetentionPolicy.SOURCE) public @interface FindViewFlags {} public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; public static final int SCREEN_STATE_OFF = 0x0; public static final int SCREEN_STATE_ON = 0x1; public static final int SCROLL_AXIS_NONE = 0; public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; public static final int SCROLL_AXIS_VERTICAL = 1 << 1; private int mOverScrollMode; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) protected ViewParent mParent; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) AttachInfo mAttachInfo; @ViewDebug.ExportedProperty(flagMapping = { @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, name = "FORCE_LAYOUT"), @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, name = "LAYOUT_REQUIRED"), @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, name = "DRAWING_CACHE_INVALID", outputIf = false), @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") }, formatToHexString = true) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769414) public int mPrivateFlags; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768943) int mPrivateFlags2; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 129147060) int mPrivateFlags3; private int mPrivateFlags4; @ViewDebug.ExportedProperty(flagMapping = { @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, equals = SYSTEM_UI_FLAG_LOW_PROFILE, name = "LOW_PROFILE"), @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, name = "HIDE_NAVIGATION"), @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_FULLSCREEN, equals = SYSTEM_UI_FLAG_FULLSCREEN, name = "FULLSCREEN"), @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_STABLE, equals = SYSTEM_UI_FLAG_LAYOUT_STABLE, name = "LAYOUT_STABLE"), @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, equals = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, name = "LAYOUT_HIDE_NAVIGATION"), @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, equals = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, name = "LAYOUT_FULLSCREEN"), @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE, equals = SYSTEM_UI_FLAG_IMMERSIVE, name = "IMMERSIVE"), @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, equals = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, name = "IMMERSIVE_STICKY"), @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, equals = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, name = "LIGHT_STATUS_BAR"), @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, equals = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, name = "LIGHT_NAVIGATION_BAR"), @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_EXPAND, equals = STATUS_BAR_DISABLE_EXPAND, name = "STATUS_BAR_DISABLE_EXPAND"), @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, equals = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, name = "STATUS_BAR_DISABLE_NOTIFICATION_ICONS"), @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, equals = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, name = "STATUS_BAR_DISABLE_NOTIFICATION_ALERTS"), @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, equals = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, name = "STATUS_BAR_DISABLE_NOTIFICATION_TICKER"), @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SYSTEM_INFO, equals = STATUS_BAR_DISABLE_SYSTEM_INFO, name = "STATUS_BAR_DISABLE_SYSTEM_INFO"), @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_HOME, equals = STATUS_BAR_DISABLE_HOME, name = "STATUS_BAR_DISABLE_HOME"), @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_BACK, equals = STATUS_BAR_DISABLE_BACK, name = "STATUS_BAR_DISABLE_BACK"), @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_CLOCK, equals = STATUS_BAR_DISABLE_CLOCK, name = "STATUS_BAR_DISABLE_CLOCK"), @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_RECENT, equals = STATUS_BAR_DISABLE_RECENT, name = "STATUS_BAR_DISABLE_RECENT"), @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SEARCH, equals = STATUS_BAR_DISABLE_SEARCH, name = "STATUS_BAR_DISABLE_SEARCH"), @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, equals = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, name = "STATUS_BAR_DISABLE_ONGOING_CALL_CHIP") }, formatToHexString = true) @SystemUiVisibility int mSystemUiVisibility; @IntDef(flag = true, prefix = "", value = { SYSTEM_UI_FLAG_LOW_PROFILE, SYSTEM_UI_FLAG_HIDE_NAVIGATION, SYSTEM_UI_FLAG_FULLSCREEN, SYSTEM_UI_FLAG_LAYOUT_STABLE, SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, SYSTEM_UI_FLAG_IMMERSIVE, SYSTEM_UI_FLAG_IMMERSIVE_STICKY, SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, STATUS_BAR_DISABLE_EXPAND, STATUS_BAR_DISABLE_NOTIFICATION_ICONS, STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, STATUS_BAR_DISABLE_NOTIFICATION_TICKER, STATUS_BAR_DISABLE_SYSTEM_INFO, STATUS_BAR_DISABLE_HOME, STATUS_BAR_DISABLE_BACK, STATUS_BAR_DISABLE_CLOCK, STATUS_BAR_DISABLE_RECENT, STATUS_BAR_DISABLE_SEARCH, STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, }) @Retention(RetentionPolicy.SOURCE) public @interface SystemUiVisibility {} int mTransientStateCount = 0; int mWindowAttachCount; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) protected ViewGroup.LayoutParams mLayoutParams; @ViewDebug.ExportedProperty(formatToHexString = true) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) int mViewFlags; static class TransformationInfo { private final Matrix mMatrix = new Matrix(); private Matrix mInverseMatrix; @ViewDebug.ExportedProperty private float mAlpha = 1f; float mTransitionAlpha = 1f; } @UnsupportedAppUsage public TransformationInfo mTransformationInfo; @ViewDebug.ExportedProperty(category = "drawing") Rect mClipBounds = null; private boolean mLastIsOpaque; @ViewDebug.ExportedProperty(category = "layout") @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) protected int mLeft; private int mLastFrameLeft; @ViewDebug.ExportedProperty(category = "layout") @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) protected int mRight; @ViewDebug.ExportedProperty(category = "layout") @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) protected int mTop; private int mLastFrameTop; @ViewDebug.ExportedProperty(category = "layout") @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) protected int mBottom; @ViewDebug.ExportedProperty(category = "scrolling") @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) protected int mScrollX; @ViewDebug.ExportedProperty(category = "scrolling") @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) protected int mScrollY; @ViewDebug.ExportedProperty(category = "padding") @UnsupportedAppUsage protected int mPaddingLeft = 0; @ViewDebug.ExportedProperty(category = "padding") @UnsupportedAppUsage protected int mPaddingRight = 0; @ViewDebug.ExportedProperty(category = "padding") @UnsupportedAppUsage protected int mPaddingTop; @ViewDebug.ExportedProperty(category = "padding") @UnsupportedAppUsage protected int mPaddingBottom; private float mHandwritingBoundsOffsetLeft; private float mHandwritingBoundsOffsetTop; private float mHandwritingBoundsOffsetRight; private float mHandwritingBoundsOffsetBottom; private Insets mLayoutInsets; private CharSequence mStateDescription; private CharSequence mContentDescription; private CharSequence mAccessibilityPaneTitle; private int mExplicitAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_AUTO; private int mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_AUTO; private int mLabelForId = View.NO_ID; private MatchLabelForPredicate mMatchLabelForPredicate; private int mAccessibilityTraversalBeforeId = NO_ID; private int mAccessibilityTraversalAfterId = NO_ID; private MatchIdPredicate mMatchIdPredicate; @ViewDebug.ExportedProperty(category = "padding") protected int mUserPaddingRight; @ViewDebug.ExportedProperty(category = "padding") protected int mUserPaddingBottom; @ViewDebug.ExportedProperty(category = "padding") protected int mUserPaddingLeft; @ViewDebug.ExportedProperty(category = "padding") int mUserPaddingStart; @ViewDebug.ExportedProperty(category = "padding") int mUserPaddingEnd; int mUserPaddingLeftInitial; int mUserPaddingRightInitial; private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; private boolean mLeftPaddingDefined = false; private boolean mRightPaddingDefined = false; int mOldWidthMeasureSpec = Integer.MIN_VALUE; int mOldHeightMeasureSpec = Integer.MIN_VALUE; private LongSparseLongArray mMeasureCache; @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private Drawable mBackground; private TintInfo mBackgroundTint; @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") private ForegroundInfo mForegroundInfo; private Drawable mScrollIndicatorDrawable; RenderNode mBackgroundRenderNode; @UnsupportedAppUsage private int mBackgroundResource; private boolean mBackgroundSizeChanged; private Drawable mDefaultFocusHighlight; private Drawable mDefaultFocusHighlightCache; private boolean mDefaultFocusHighlightSizeChanged; private static boolean sUseDefaultFocusHighlight; private static boolean sCanFocusZeroSized; private static boolean sAlwaysAssignFocus; private String mTransitionName; static class TintInfo { ColorStateList mTintList; BlendMode mBlendMode; boolean mHasTintMode; boolean mHasTintList; } private static class ForegroundInfo { private Drawable mDrawable; private TintInfo mTintInfo; private int mGravity = Gravity.FILL; private boolean mInsidePadding = true; private boolean mBoundsChanged = true; private final Rect mSelfBounds = new Rect(); private final Rect mOverlayBounds = new Rect(); } static class ListenerInfo { @UnsupportedAppUsage ListenerInfo() { } @UnsupportedAppUsage protected OnFocusChangeListener mOnFocusChangeListener; private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; protected OnScrollChangeListener mOnScrollChangeListener; private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; @UnsupportedAppUsage public OnClickListener mOnClickListener; @UnsupportedAppUsage protected OnLongClickListener mOnLongClickListener; protected OnContextClickListener mOnContextClickListener; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) protected OnCreateContextMenuListener mOnCreateContextMenuListener; @UnsupportedAppUsage private OnKeyListener mOnKeyListener; @UnsupportedAppUsage private OnTouchListener mOnTouchListener; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private OnHoverListener mOnHoverListener; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private OnGenericMotionListener mOnGenericMotionListener; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private OnDragListener mOnDragListener; private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; OnCapturedPointerListener mOnCapturedPointerListener; private ArrayList<OnUnhandledKeyEventListener> mUnhandledKeyListeners; WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback; private List<Rect> mSystemGestureExclusionRects = null; private List<Rect> mKeepClearRects = null; private List<Rect> mUnrestrictedKeepClearRects = null; private boolean mPreferKeepClear = false; private Rect mHandwritingArea = null; public RenderNode.PositionUpdateListener mPositionUpdateListener; private Runnable mPositionChangedUpdate; ScrollCaptureCallback mScrollCaptureCallback; @Nullable private OnReceiveContentListener mOnReceiveContentListener; } @UnsupportedAppUsage ListenerInfo mListenerInfo; private static class TooltipInfo { @Nullable CharSequence mTooltipText; int mAnchorX; int mAnchorY; @Nullable TooltipPopup mTooltipPopup; boolean mTooltipFromLongClick; Runnable mShowTooltipRunnable; Runnable mHideTooltipRunnable; int mHoverSlop; private boolean updateAnchorPos(MotionEvent event) { final int newAnchorX = (int) event.getX(); final int newAnchorY = (int) event.getY(); if (Math.abs(newAnchorX - mAnchorX) <= mHoverSlop && Math.abs(newAnchorY - mAnchorY) <= mHoverSlop) { return false; } mAnchorX = newAnchorX; mAnchorY = newAnchorY; return true; } private void clearAnchorPos() { mAnchorX = Integer.MAX_VALUE; mAnchorY = Integer.MAX_VALUE; } } TooltipInfo mTooltipInfo; private float mLongClickX = Float.NaN; private float mLongClickY = Float.NaN; @ViewDebug.ExportedProperty(deepExport = true) @UnsupportedAppUsage @UiContext protected Context mContext; @UnsupportedAppUsage private final Resources mResources; @UnsupportedAppUsage private ScrollabilityCache mScrollCache; private int[] mDrawableState = null; ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; private StateListAnimator mStateListAnimator; private int mNextFocusLeftId = View.NO_ID; private int mNextFocusRightId = View.NO_ID; private int mNextFocusUpId = View.NO_ID; private int mNextFocusDownId = View.NO_ID; int mNextFocusForwardId = View.NO_ID; int mNextClusterForwardId = View.NO_ID; boolean mDefaultFocusHighlightEnabled = true; private CheckForLongPress mPendingCheckForLongPress; @UnsupportedAppUsage private CheckForTap mPendingCheckForTap = null; private PerformClick mPerformClick; private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; private SendAccessibilityEventThrottle mSendStateChangedAccessibilityEvent; private UnsetPressedState mUnsetPressedState; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private boolean mHasPerformedLongPress; private boolean mInContextButtonPress; private boolean mIgnoreNextUpEvent; @ViewDebug.ExportedProperty(category = "measurement") @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private int mMinHeight; @ViewDebug.ExportedProperty(category = "measurement") @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private int mMinWidth; private TouchDelegate mTouchDelegate = null; private boolean mHoveringTouchDelegate = false; private Runnable mHandwritingDelegatorCallback; private String mAllowedHandwritingDelegatePackageName; private boolean mIsHandwritingDelegate; private String mAllowedHandwritingDelegatorPackageName; private @InputMethodManager.HandwritingDelegateFlags int mHandwritingDelegateFlags; private int mDrawingCacheBackgroundColor = 0; private ViewTreeObserver mFloatingTreeObserver; private int mTouchSlop; private float mAmbiguousGestureMultiplier; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private ViewPropertyAnimator mAnimator = null; private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; public static final int DRAG_FLAG_GLOBAL = 1 << 8; public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; public static final int DRAG_FLAG_OPAQUE = 1 << 9; public static final int DRAG_FLAG_ACCESSIBILITY_ACTION = 1 << 10; public static final int DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION = 1 << 11; @FlaggedApi(FLAG_DELEGATE_UNHANDLED_DRAGS) public static final int DRAG_FLAG_GLOBAL_SAME_APPLICATION = 1 << 12; @FlaggedApi(FLAG_DELEGATE_UNHANDLED_DRAGS) public static final int DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG = 1 << 13; private float mVerticalScrollFactor; @UnsupportedAppUsage private int mVerticalScrollbarPosition; public static final int SCROLLBAR_POSITION_DEFAULT = 0; public static final int SCROLLBAR_POSITION_LEFT = 1; public static final int SCROLLBAR_POSITION_RIGHT = 2; public static final int LAYER_TYPE_NONE = 0; public static final int LAYER_TYPE_SOFTWARE = 1; public static final int LAYER_TYPE_HARDWARE = 2; @IntDef(prefix = { "LAYER_TYPE_" }, value = { LAYER_TYPE_NONE, LAYER_TYPE_SOFTWARE, LAYER_TYPE_HARDWARE }) @Retention(RetentionPolicy.SOURCE) public @interface LayerType {} int mLayerType = LAYER_TYPE_NONE; Paint mLayerPaint; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean mCachingFailed; @UnsupportedAppUsage private Bitmap mDrawingCache; @UnsupportedAppUsage private Bitmap mUnscaledDrawingCache; @UnsupportedAppUsage final RenderNode mRenderNode; private boolean mSendingHoverAccessibilityEvents; @UnsupportedAppUsage AccessibilityDelegate mAccessibilityDelegate; ViewOverlay mOverlay; private ViewParent mNestedScrollingParent; protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = InputEventConsistencyVerifier.isInstrumentationEnabled() ? new InputEventConsistencyVerifier(this, 0) : null; private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); private int[] mTempNestedScrollConsumed; GhostView mGhostView; @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) public String[] mAttributes; private static SparseArray<String> mAttributeMap; private HandlerActionQueue mRunQueue; private PointerIcon mMousePointerIcon; private Vibrator mVibrator; @UnsupportedAppUsage String mStartActivityRequestWho; @Nullable private RoundScrollbarRenderer mRoundScrollbarRenderer; private Handler mVisibilityChangeForAutofillHandler; @Nullable private ContentCaptureSession mContentCaptureSession; private boolean mContentCaptureSessionCached; @LayoutRes private int mSourceLayoutId = ID_NULL; @Nullable private SparseIntArray mAttributeSourceResId; @Nullable private SparseArray<int[]> mAttributeResolutionStacks; @StyleRes private int mExplicitStyle; @InputSourceClass int mUnbufferedInputSource = InputDevice.SOURCE_CLASS_NONE; @Nullable private String[] mReceiveContentMimeTypes; @Nullable private ViewTranslationCallback mViewTranslationCallback; private float mFrameContentVelocity = -1; @Nullable private ViewTranslationResponse mViewTranslationResponse; private static final float FRAME_RATE_SQUARE_SMALL_SIZE_DP = 40f; private static final float FRAME_RATE_NARROW_SIZE_DP = 10f; private static final float FRAME_RATE_SIZE_PERCENTAGE_THRESHOLD = 0.07f; static final float MAX_FRAME_RATE = 120; 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; public View(Context context) { mContext = context; mResources = context != null ? context.getResources() : null; mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO; mPrivateFlags2 = (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); final ViewConfiguration configuration = ViewConfiguration.get(context); mTouchSlop = configuration.getScaledTouchSlop(); mAmbiguousGestureMultiplier = configuration.getScaledAmbiguousGestureMultiplier(); setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); mUserPaddingStart = UNDEFINED_PADDING; mUserPaddingEnd = UNDEFINED_PADDING; mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this)); if (!sCompatibilityDone && context != null) { final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; sAlwaysRemeasureExactly = targetSdkVersion <= Build.VERSION_CODES.M; sTextureViewIgnoresDrawableSetters = targetSdkVersion <= Build.VERSION_CODES.M; sPreserveMarginParamsInLayoutParamConversion = targetSdkVersion >= Build.VERSION_CODES.N; sCascadedDragDrop = targetSdkVersion < Build.VERSION_CODES.N; sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O; sAutoFocusableOffUIThreadWontNotifyParents = targetSdkVersion < Build.VERSION_CODES.O; sUseDefaultFocusHighlight = context.getResources().getBoolean( com.android.internal.R.bool.config_useDefaultFocusHighlight); sThrowOnInvalidFloatProperties = targetSdkVersion >= Build.VERSION_CODES.P; sCanFocusZeroSized = targetSdkVersion < Build.VERSION_CODES.P; sAlwaysAssignFocus = targetSdkVersion < Build.VERSION_CODES.P; sAcceptZeroSizeDragShadow = targetSdkVersion < Build.VERSION_CODES.P; sBrokenInsetsDispatch = targetSdkVersion < Build.VERSION_CODES.R; sBrokenWindowBackground = targetSdkVersion < Build.VERSION_CODES.Q; GradientDrawable.sWrapNegativeAngleMeasurements = targetSdkVersion >= Build.VERSION_CODES.Q; sForceLayoutWhenInsetsChanged = targetSdkVersion < Build.VERSION_CODES.R; sCompatibilityDone = true; } } public View(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { this(context); mSourceLayoutId = Resources.getAttributeSetSourceResId(attrs); final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); retrieveExplicitStyle(context.getTheme(), attrs); saveAttributeDataForStyleable(context, com.android.internal.R.styleable.View, attrs, a, defStyleAttr, defStyleRes); if (sDebugViewAttributes) { saveAttributeData(attrs, a); } Drawable background = null; int leftPadding = -1; int topPadding = -1; int rightPadding = -1; int bottomPadding = -1; int startPadding = UNDEFINED_PADDING; int endPadding = UNDEFINED_PADDING; int padding = -1; int paddingHorizontal = -1; int paddingVertical = -1; int viewFlagValues = 0; int viewFlagMasks = 0; boolean setScrollContainer = false; int x = 0; int y = 0; float tx = 0; float ty = 0; float tz = 0; float elevation = 0; float rotation = 0; float rotationX = 0; float rotationY = 0; float sx = 1f; float sy = 1f; boolean transformSet = false; int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; int overScrollMode = mOverScrollMode; boolean initializeScrollbars = false; boolean initializeScrollIndicators = false; boolean startPaddingDefined = false; boolean endPaddingDefined = false; boolean leftPaddingDefined = false; boolean rightPaddingDefined = false; viewFlagValues |= FOCUSABLE_AUTO; viewFlagMasks |= FOCUSABLE_AUTO; final int N = a.getIndexCount(); for (int i = 0; i < N; i++) { int attr = a.getIndex(i); switch (attr) { case com.android.internal.R.styleable.View_background: background = a.getDrawable(attr); break; case com.android.internal.R.styleable.View_padding: padding = a.getDimensionPixelSize(attr, -1); mUserPaddingLeftInitial = padding; mUserPaddingRightInitial = padding; leftPaddingDefined = true; rightPaddingDefined = true; break; case com.android.internal.R.styleable.View_paddingHorizontal: paddingHorizontal = a.getDimensionPixelSize(attr, -1); mUserPaddingLeftInitial = paddingHorizontal; mUserPaddingRightInitial = paddingHorizontal; leftPaddingDefined = true; rightPaddingDefined = true; break; case com.android.internal.R.styleable.View_paddingVertical: paddingVertical = a.getDimensionPixelSize(attr, -1); break; case com.android.internal.R.styleable.View_paddingLeft: leftPadding = a.getDimensionPixelSize(attr, -1); mUserPaddingLeftInitial = leftPadding; leftPaddingDefined = true; break; case com.android.internal.R.styleable.View_paddingTop: topPadding = a.getDimensionPixelSize(attr, -1); break; case com.android.internal.R.styleable.View_paddingRight: rightPadding = a.getDimensionPixelSize(attr, -1); mUserPaddingRightInitial = rightPadding; rightPaddingDefined = true; break; case com.android.internal.R.styleable.View_paddingBottom: bottomPadding = a.getDimensionPixelSize(attr, -1); break; case com.android.internal.R.styleable.View_paddingStart: startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); startPaddingDefined = (startPadding != UNDEFINED_PADDING); break; case com.android.internal.R.styleable.View_paddingEnd: endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); endPaddingDefined = (endPadding != UNDEFINED_PADDING); break; case com.android.internal.R.styleable.View_scrollX: x = a.getDimensionPixelOffset(attr, 0); break; case com.android.internal.R.styleable.View_scrollY: y = a.getDimensionPixelOffset(attr, 0); break; case com.android.internal.R.styleable.View_alpha: setAlpha(a.getFloat(attr, 1f)); break; case com.android.internal.R.styleable.View_transformPivotX: setPivotX(a.getDimension(attr, 0)); break; case com.android.internal.R.styleable.View_transformPivotY: setPivotY(a.getDimension(attr, 0)); break; case com.android.internal.R.styleable.View_translationX: tx = a.getDimension(attr, 0); transformSet = true; break; case com.android.internal.R.styleable.View_translationY: ty = a.getDimension(attr, 0); transformSet = true; break; case com.android.internal.R.styleable.View_translationZ: tz = a.getDimension(attr, 0); transformSet = true; break; case com.android.internal.R.styleable.View_elevation: elevation = a.getDimension(attr, 0); transformSet = true; break; case com.android.internal.R.styleable.View_rotation: rotation = a.getFloat(attr, 0); transformSet = true; break; case com.android.internal.R.styleable.View_rotationX: rotationX = a.getFloat(attr, 0); transformSet = true; break; case com.android.internal.R.styleable.View_rotationY: rotationY = a.getFloat(attr, 0); transformSet = true; break; case com.android.internal.R.styleable.View_scaleX: sx = a.getFloat(attr, 1f); transformSet = true; break; case com.android.internal.R.styleable.View_scaleY: sy = a.getFloat(attr, 1f); transformSet = true; break; case com.android.internal.R.styleable.View_id: mID = a.getResourceId(attr, NO_ID); break; case com.android.internal.R.styleable.View_tag: mTag = a.getText(attr); break; case com.android.internal.R.styleable.View_fitsSystemWindows: if (a.getBoolean(attr, false)) { viewFlagValues |= FITS_SYSTEM_WINDOWS; viewFlagMasks |= FITS_SYSTEM_WINDOWS; } break; case com.android.internal.R.styleable.View_focusable: viewFlagValues = (viewFlagValues & ~FOCUSABLE_MASK) | getFocusableAttribute(a); if ((viewFlagValues & FOCUSABLE_AUTO) == 0) { viewFlagMasks |= FOCUSABLE_MASK; } break; case com.android.internal.R.styleable.View_focusableInTouchMode: if (a.getBoolean(attr, false)) { viewFlagValues &= ~FOCUSABLE_AUTO; viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; } break; case com.android.internal.R.styleable.View_clickable: if (a.getBoolean(attr, false)) { viewFlagValues |= CLICKABLE; viewFlagMasks |= CLICKABLE; } break; case com.android.internal.R.styleable.View_allowClickWhenDisabled: setAllowClickWhenDisabled(a.getBoolean(attr, false)); break; case com.android.internal.R.styleable.View_longClickable: if (a.getBoolean(attr, false)) { viewFlagValues |= LONG_CLICKABLE; viewFlagMasks |= LONG_CLICKABLE; } break; case com.android.internal.R.styleable.View_contextClickable: if (a.getBoolean(attr, false)) { viewFlagValues |= CONTEXT_CLICKABLE; viewFlagMasks |= CONTEXT_CLICKABLE; } break; case com.android.internal.R.styleable.View_saveEnabled: if (!a.getBoolean(attr, true)) { viewFlagValues |= SAVE_DISABLED; viewFlagMasks |= SAVE_DISABLED_MASK; } break; case com.android.internal.R.styleable.View_duplicateParentState: if (a.getBoolean(attr, false)) { viewFlagValues |= DUPLICATE_PARENT_STATE; viewFlagMasks |= DUPLICATE_PARENT_STATE; } break; case com.android.internal.R.styleable.View_visibility: final int visibility = a.getInt(attr, 0); if (visibility != 0) { viewFlagValues |= VISIBILITY_FLAGS[visibility]; viewFlagMasks |= VISIBILITY_MASK; } break; case com.android.internal.R.styleable.View_layoutDirection: mPrivateFlags2 &= ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); final int layoutDirection = a.getInt(attr, -1); final int value = (layoutDirection != -1) ? LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); break; case com.android.internal.R.styleable.View_drawingCacheQuality: final int cacheQuality = a.getInt(attr, 0); if (cacheQuality != 0) { viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; } break; case com.android.internal.R.styleable.View_contentDescription: setContentDescription(a.getString(attr)); break; case com.android.internal.R.styleable.View_accessibilityTraversalBefore: setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); break; case com.android.internal.R.styleable.View_accessibilityTraversalAfter: setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); break; case com.android.internal.R.styleable.View_labelFor: setLabelFor(a.getResourceId(attr, NO_ID)); break; case com.android.internal.R.styleable.View_soundEffectsEnabled: if (!a.getBoolean(attr, true)) { viewFlagValues &= ~SOUND_EFFECTS_ENABLED; viewFlagMasks |= SOUND_EFFECTS_ENABLED; } break; case com.android.internal.R.styleable.View_hapticFeedbackEnabled: if (!a.getBoolean(attr, true)) { viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; } break; case R.styleable.View_scrollbars: final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); if (scrollbars != SCROLLBARS_NONE) { viewFlagValues |= scrollbars; viewFlagMasks |= SCROLLBARS_MASK; initializeScrollbars = true; } break; case R.styleable.View_fadingEdge: break; case R.styleable.View_requiresFadingEdge: final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); if (fadingEdge != FADING_EDGE_NONE) { viewFlagValues |= fadingEdge; viewFlagMasks |= FADING_EDGE_MASK; initializeFadingEdgeInternal(a); } break; case R.styleable.View_scrollbarStyle: scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; viewFlagMasks |= SCROLLBARS_STYLE_MASK; } break; case R.styleable.View_isScrollContainer: setScrollContainer = true; if (a.getBoolean(attr, false)) { setScrollContainer(true); } break; case com.android.internal.R.styleable.View_keepScreenOn: if (a.getBoolean(attr, false)) { viewFlagValues |= KEEP_SCREEN_ON; viewFlagMasks |= KEEP_SCREEN_ON; } break; case R.styleable.View_filterTouchesWhenObscured: if (a.getBoolean(attr, false)) { viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; } break; case R.styleable.View_nextFocusLeft: mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); break; case R.styleable.View_nextFocusRight: mNextFocusRightId = a.getResourceId(attr, View.NO_ID); break; case R.styleable.View_nextFocusUp: mNextFocusUpId = a.getResourceId(attr, View.NO_ID); break; case R.styleable.View_nextFocusDown: mNextFocusDownId = a.getResourceId(attr, View.NO_ID); break; case R.styleable.View_nextFocusForward: mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); break; case R.styleable.View_nextClusterForward: mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); break; case R.styleable.View_minWidth: mMinWidth = a.getDimensionPixelSize(attr, 0); break; case R.styleable.View_minHeight: mMinHeight = a.getDimensionPixelSize(attr, 0); break; case R.styleable.View_onClick: if (context.isRestricted()) { throw new IllegalStateException("The android:onClick attribute cannot " + "be used within a restricted context"); } final String handlerName = a.getString(attr); if (handlerName != null) { setOnClickListener(new DeclaredOnClickListener(this, handlerName)); } break; case R.styleable.View_overScrollMode: overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); break; case R.styleable.View_verticalScrollbarPosition: mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); break; case R.styleable.View_layerType: setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); break; case R.styleable.View_textDirection: mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; final int textDirection = a.getInt(attr, -1); if (textDirection != -1) { mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; } break; case R.styleable.View_textAlignment: mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; break; case R.styleable.View_importantForAccessibility: 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; case R.styleable.View_transitionName: setTransitionName(a.getString(attr)); break; case R.styleable.View_nestedScrollingEnabled: setNestedScrollingEnabled(a.getBoolean(attr, false)); break; case R.styleable.View_stateListAnimator: setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, a.getResourceId(attr, 0))); break; case R.styleable.View_backgroundTint: if (mBackgroundTint == null) { mBackgroundTint = new TintInfo(); } mBackgroundTint.mTintList = a.getColorStateList( R.styleable.View_backgroundTint); mBackgroundTint.mHasTintList = true; break; case R.styleable.View_backgroundTintMode: if (mBackgroundTint == null) { mBackgroundTint = new TintInfo(); } mBackgroundTint.mBlendMode = Drawable.parseBlendMode(a.getInt( R.styleable.View_backgroundTintMode, -1), null); mBackgroundTint.mHasTintMode = true; break; case R.styleable.View_outlineProvider: setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, PROVIDER_BACKGROUND)); break; case R.styleable.View_foreground: setForeground(a.getDrawable(attr)); break; case R.styleable.View_foregroundGravity: setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); break; case R.styleable.View_foregroundTintMode: setForegroundTintBlendMode( Drawable.parseBlendMode(a.getInt(attr, -1), null)); break; case R.styleable.View_foregroundTint: setForegroundTintList(a.getColorStateList(attr)); break; case R.styleable.View_foregroundInsidePadding: if (mForegroundInfo == null) { mForegroundInfo = new ForegroundInfo(); } mForegroundInfo.mInsidePadding = a.getBoolean(attr, mForegroundInfo.mInsidePadding); break; case R.styleable.View_scrollIndicators: final int scrollIndicators = (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) & SCROLL_INDICATORS_PFLAG3_MASK; if (scrollIndicators != 0) { mPrivateFlags3 |= scrollIndicators; initializeScrollIndicators = true; } break; case R.styleable.View_pointerIcon: final int resourceId = a.getResourceId(attr, 0); if (resourceId != 0) { setPointerIcon(PointerIcon.load( context.getResources(), resourceId)); } else { final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); } } break; case R.styleable.View_forceHasOverlappingRendering: if (a.peekValue(attr) != null) { forceHasOverlappingRendering(a.getBoolean(attr, true)); } break; case R.styleable.View_tooltipText: setTooltipText(a.getText(attr)); break; case R.styleable.View_keyboardNavigationCluster: if (a.peekValue(attr) != null) { setKeyboardNavigationCluster(a.getBoolean(attr, true)); } break; case R.styleable.View_focusedByDefault: if (a.peekValue(attr) != null) { setFocusedByDefault(a.getBoolean(attr, true)); } break; case R.styleable.View_autofillHints: if (a.peekValue(attr) != null) { CharSequence[] rawHints = null; String rawString = null; if (a.getType(attr) == TypedValue.TYPE_REFERENCE) { int resId = a.getResourceId(attr, 0); try { rawHints = a.getTextArray(attr); } catch (Resources.NotFoundException e) { rawString = getResources().getString(resId); } } else { rawString = a.getString(attr); } if (rawHints == null) { if (rawString == null) { throw new IllegalArgumentException( "Could not resolve autofillHints"); } else { rawHints = rawString.split(","); } } String[] hints = new String[rawHints.length]; int numHints = rawHints.length; for (int rawHintNum = 0; rawHintNum < numHints; rawHintNum++) { hints[rawHintNum] = rawHints[rawHintNum].toString().trim(); } setAutofillHints(hints); } break; case R.styleable.View_importantForAutofill: if (a.peekValue(attr) != null) { setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO)); } break; case R.styleable.View_importantForContentCapture: if (a.peekValue(attr) != null) { 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)); } break; case R.styleable.View_screenReaderFocusable: if (a.peekValue(attr) != null) { setScreenReaderFocusable(a.getBoolean(attr, false)); } break; case R.styleable.View_accessibilityPaneTitle: if (a.peekValue(attr) != null) { setAccessibilityPaneTitle(a.getString(attr)); } break; case R.styleable.View_outlineSpotShadowColor: setOutlineSpotShadowColor(a.getColor(attr, Color.BLACK)); break; case R.styleable.View_outlineAmbientShadowColor: setOutlineAmbientShadowColor(a.getColor(attr, Color.BLACK)); break; case com.android.internal.R.styleable.View_accessibilityHeading: setAccessibilityHeading(a.getBoolean(attr, false)); break; case R.styleable.View_forceDarkAllowed: mRenderNode.setForceDarkAllowed(a.getBoolean(attr, true)); break; case R.styleable.View_scrollCaptureHint: setScrollCaptureHint((a.getInt(attr, SCROLL_CAPTURE_HINT_AUTO))); break; case R.styleable.View_clipToOutline: setClipToOutline(a.getBoolean(attr, false)); break; case R.styleable.View_preferKeepClear: setPreferKeepClear(a.getBoolean(attr, false)); break; case R.styleable.View_autoHandwritingEnabled: 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; } } setOverScrollMode(overScrollMode); mUserPaddingStart = startPadding; mUserPaddingEnd = endPadding; if (background != null) { setBackground(background); } mLeftPaddingDefined = leftPaddingDefined; mRightPaddingDefined = rightPaddingDefined; if (padding >= 0) { leftPadding = padding; topPadding = padding; rightPadding = padding; bottomPadding = padding; mUserPaddingLeftInitial = padding; mUserPaddingRightInitial = padding; } else { if (paddingHorizontal >= 0) { leftPadding = paddingHorizontal; rightPadding = paddingHorizontal; mUserPaddingLeftInitial = paddingHorizontal; mUserPaddingRightInitial = paddingHorizontal; } if (paddingVertical >= 0) { topPadding = paddingVertical; bottomPadding = paddingVertical; } } if (isRtlCompatibilityMode()) { if (!mLeftPaddingDefined && startPaddingDefined) { leftPadding = startPadding; } mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; if (!mRightPaddingDefined && endPaddingDefined) { rightPadding = endPadding; } mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; } else { final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; if (mLeftPaddingDefined && !hasRelativePadding) { mUserPaddingLeftInitial = leftPadding; } if (mRightPaddingDefined && !hasRelativePadding) { mUserPaddingRightInitial = rightPadding; } } internalSetPadding( mUserPaddingLeftInitial, topPadding >= 0 ? topPadding : mPaddingTop, mUserPaddingRightInitial, bottomPadding >= 0 ? bottomPadding : mPaddingBottom); if (viewFlagMasks != 0) { setFlags(viewFlagValues, viewFlagMasks); } if (initializeScrollbars) { initializeScrollbarsInternal(a); } if (initializeScrollIndicators) { initializeScrollIndicatorsInternal(); } a.recycle(); if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { recomputePadding(); } if (x != 0 || y != 0) { scrollTo(x, y); } if (transformSet) { setTranslationX(tx); setTranslationY(ty); setTranslationZ(tz); setElevation(elevation); setRotation(rotation); setRotationX(rotationX); setRotationY(rotationY); setScaleX(sx); setScaleY(sy); } if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { setScrollContainer(true); } computeOpaqueFlags(); } @NonNull public int[] getAttributeResolutionStack(@AttrRes int attribute) { if (!sDebugViewAttributes || mAttributeResolutionStacks == null || mAttributeResolutionStacks.get(attribute) == null) { return new int[0]; } int[] attributeResolutionStack = mAttributeResolutionStacks.get(attribute); int stackSize = attributeResolutionStack.length; if (mSourceLayoutId != ID_NULL) { stackSize++; } int currentIndex = 0; int[] stack = new int[stackSize]; if (mSourceLayoutId != ID_NULL) { stack[currentIndex] = mSourceLayoutId; currentIndex++; } for (int i = 0; i < attributeResolutionStack.length; i++) { stack[currentIndex] = attributeResolutionStack[i]; currentIndex++; } return stack; } @NonNull @SuppressWarnings("AndroidFrameworkEfficientCollections") public Map<Integer, Integer> getAttributeSourceResourceMap() { HashMap<Integer, Integer> map = new HashMap<>(); if (!sDebugViewAttributes || mAttributeSourceResId == null) { return map; } for (int i = 0; i < mAttributeSourceResId.size(); i++) { map.put(mAttributeSourceResId.keyAt(i), mAttributeSourceResId.valueAt(i)); } return map; } @StyleRes public int getExplicitStyle() { if (!sDebugViewAttributes) { return ID_NULL; } return mExplicitStyle; } private static class DeclaredOnClickListener implements OnClickListener { private final View mHostView; private final String mMethodName; private Method mResolvedMethod; private Context mResolvedContext; public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { mHostView = hostView; mMethodName = methodName; } @Override public void onClick(@NonNull View v) { if (mResolvedMethod == null) { resolveMethod(mHostView.getContext(), mMethodName); } try { mResolvedMethod.invoke(mResolvedContext, v); } catch (IllegalAccessException e) { throw new IllegalStateException( "Could not execute non-public method for android:onClick", e); } catch (InvocationTargetException e) { throw new IllegalStateException( "Could not execute method for android:onClick", e); } } @NonNull private void resolveMethod(@Nullable Context context, @NonNull String name) { while (context != null) { try { if (!context.isRestricted()) { final Method method = context.getClass().getMethod(mMethodName, View.class); if (method != null) { mResolvedMethod = method; mResolvedContext = context; return; } } } catch (NoSuchMethodException e) { } if (context instanceof ContextWrapper) { context = ((ContextWrapper) context).getBaseContext(); } else { context = null; } } final int id = mHostView.getId(); final String idText = id == NO_ID ? "" : " with id '" + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; throw new IllegalStateException("Could not find method " + mMethodName + "(View) in a parent or ancestor Context for android:onClick " + "attribute defined on view " + mHostView.getClass() + idText); } } @UnsupportedAppUsage View() { mResources = null; mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this)); } public final boolean isShowingLayoutBounds() { return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; } @TestApi public final void setShowingLayoutBounds(boolean debugLayout) { if (mAttachInfo != null) { mAttachInfo.mDebugLayout = debugLayout; } } private static SparseArray<String> getAttributeMap() { if (mAttributeMap == null) { mAttributeMap = new SparseArray<>(); } return mAttributeMap; } private void retrieveExplicitStyle(@NonNull Resources.Theme theme, @Nullable AttributeSet attrs) { if (!sDebugViewAttributes) { return; } mExplicitStyle = theme.getExplicitStyle(attrs); } public final void saveAttributeDataForStyleable(@NonNull Context context, @NonNull int[] styleable, @Nullable AttributeSet attrs, @NonNull TypedArray t, int defStyleAttr, int defStyleRes) { if (!sDebugViewAttributes) { return; } int[] attributeResolutionStack = context.getTheme().getAttributeResolutionStack( defStyleAttr, defStyleRes, mExplicitStyle); if (mAttributeResolutionStacks == null) { mAttributeResolutionStacks = new SparseArray<>(); } if (mAttributeSourceResId == null) { mAttributeSourceResId = new SparseIntArray(); } final int indexCount = t.getIndexCount(); for (int j = 0; j < indexCount; ++j) { final int index = t.getIndex(j); mAttributeSourceResId.append(styleable[index], t.getSourceResourceId(index, 0)); mAttributeResolutionStacks.append(styleable[index], attributeResolutionStack); } } private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); final int indexCount = t.getIndexCount(); int i = 0; for (int j = 0; j < attrsCount; ++j) { attributes[i] = attrs.getAttributeName(j); attributes[i + 1] = attrs.getAttributeValue(j); i += 2; } final Resources res = t.getResources(); final SparseArray<String> attributeMap = getAttributeMap(); for (int j = 0; j < indexCount; ++j) { final int index = t.getIndex(j); if (!t.hasValueOrEmpty(index)) { continue; } final int resourceId = t.getResourceId(index, 0); if (resourceId == 0) { continue; } String resourceName = attributeMap.get(resourceId); if (resourceName == null) { try { resourceName = res.getResourceName(resourceId); } catch (Resources.NotFoundException e) { resourceName = "0x" + Integer.toHexString(resourceId); } attributeMap.put(resourceId, resourceName); } attributes[i] = resourceName; attributes[i + 1] = t.getString(index); i += 2; } final String[] trimmed = new String[i]; System.arraycopy(attributes, 0, trimmed, 0, i); mAttributes = trimmed; } @Override public String toString() { StringBuilder out = new StringBuilder(256); out.append(getClass().getName()); out.append('{'); out.append(Integer.toHexString(System.identityHashCode(this))); out.append(' '); switch (mViewFlags&VISIBILITY_MASK) { case VISIBLE: out.append('V'); break; case INVISIBLE: out.append('I'); break; case GONE: out.append('G'); break; default: out.append('.'); break; } out.append((mViewFlags & FOCUSABLE) == FOCUSABLE ? 'F' : '.'); out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); out.append(' '); out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { out.append('p'); } else { out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); } out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); out.append(' '); out.append(mLeft); out.append(','); out.append(mTop); out.append('-'); 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(" #"); out.append(Integer.toHexString(id)); final Resources r = mResources; if (id > 0 && Resources.resourceHasPackage(id) && r != null) { try { String pkgname; switch (id&0xff000000) { case 0x7f000000: pkgname="app"; break; case 0x01000000: pkgname="android"; break; default: pkgname = r.getResourcePackageName(id); break; } String typename = r.getResourceTypeName(id); String entryname = r.getResourceEntryName(id); out.append(" "); out.append(pkgname); out.append(":"); out.append(typename); out.append("/"); out.append(entryname); } catch (Resources.NotFoundException e) { } } } } protected void initializeFadingEdge(TypedArray a) { TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); initializeFadingEdgeInternal(arr); arr.recycle(); } protected void initializeFadingEdgeInternal(TypedArray a) { initScrollCache(); mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( R.styleable.View_fadingEdgeLength, ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); } public int getVerticalFadingEdgeLength() { if (isVerticalFadingEdgeEnabled()) { ScrollabilityCache cache = mScrollCache; if (cache != null) { return cache.fadingEdgeLength; } } return 0; } public void setFadingEdgeLength(int length) { initScrollCache(); mScrollCache.fadingEdgeLength = length; } @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; } @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) public void setPendingCredentialRequest(@NonNull GetCredentialRequest request, @NonNull OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) { Preconditions.checkNotNull(request, "request must not be null"); Preconditions.checkNotNull(callback, "callback must not be null"); for (CredentialOption option : request.getCredentialOptions()) { ArrayList<AutofillId> 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); } @Nullable public ViewCredentialHandler getViewCredentialHandler() { return mViewCredentialHandler; } public int getHorizontalFadingEdgeLength() { if (isHorizontalFadingEdgeEnabled()) { ScrollabilityCache cache = mScrollCache; if (cache != null) { return cache.fadingEdgeLength; } } return 0; } public int getVerticalScrollbarWidth() { ScrollabilityCache cache = mScrollCache; if (cache != null) { ScrollBarDrawable scrollBar = cache.scrollBar; if (scrollBar != null) { int size = scrollBar.getSize(true); if (size <= 0) { size = cache.scrollBarSize; } return size; } return 0; } return 0; } protected int getHorizontalScrollbarHeight() { ScrollabilityCache cache = mScrollCache; if (cache != null) { ScrollBarDrawable scrollBar = cache.scrollBar; if (scrollBar != null) { int size = scrollBar.getSize(false); if (size <= 0) { size = cache.scrollBarSize; } return size; } return 0; } return 0; } protected void initializeScrollbars(TypedArray a) { TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); initializeScrollbarsInternal(arr); arr.recycle(); } private void initializeScrollBarDrawable() { initScrollCache(); if (mScrollCache.scrollBar == null) { mScrollCache.scrollBar = new ScrollBarDrawable(); mScrollCache.scrollBar.setState(getDrawableState()); mScrollCache.scrollBar.setCallback(this); } } @UnsupportedAppUsage protected void initializeScrollbarsInternal(TypedArray a) { initScrollCache(); final ScrollabilityCache scrollabilityCache = mScrollCache; if (scrollabilityCache.scrollBar == null) { scrollabilityCache.scrollBar = new ScrollBarDrawable(); scrollabilityCache.scrollBar.setState(getDrawableState()); scrollabilityCache.scrollBar.setCallback(this); } final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); if (!fadeScrollbars) { scrollabilityCache.state = ScrollabilityCache.ON; } scrollabilityCache.fadeScrollBars = fadeScrollbars; scrollabilityCache.scrollBarFadeDuration = a.getInt( R.styleable.View_scrollbarFadeDuration, ViewConfiguration .getScrollBarFadeDuration()); scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( R.styleable.View_scrollbarDefaultDelayBeforeFade, ViewConfiguration.getScrollDefaultDelay()); scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( com.android.internal.R.styleable.View_scrollbarSize, ViewConfiguration.get(mContext).getScaledScrollBarSize()); Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); if (thumb != null) { scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); } boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, false); if (alwaysDraw) { scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); } track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); if (thumb != null) { scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); } alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, false); if (alwaysDraw) { scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); } final int layoutDirection = getLayoutDirection(); if (track != null) { track.setLayoutDirection(layoutDirection); } if (thumb != null) { thumb.setLayoutDirection(layoutDirection); } resolvePadding(); } public void setVerticalScrollbarThumbDrawable(@Nullable Drawable drawable) { initializeScrollBarDrawable(); mScrollCache.scrollBar.setVerticalThumbDrawable(drawable); } public void setVerticalScrollbarTrackDrawable(@Nullable Drawable drawable) { initializeScrollBarDrawable(); mScrollCache.scrollBar.setVerticalTrackDrawable(drawable); } public void setHorizontalScrollbarThumbDrawable(@Nullable Drawable drawable) { initializeScrollBarDrawable(); mScrollCache.scrollBar.setHorizontalThumbDrawable(drawable); } public void setHorizontalScrollbarTrackDrawable(@Nullable Drawable drawable) { initializeScrollBarDrawable(); mScrollCache.scrollBar.setHorizontalTrackDrawable(drawable); } public @Nullable Drawable getVerticalScrollbarThumbDrawable() { return mScrollCache != null ? mScrollCache.scrollBar.getVerticalThumbDrawable() : null; } public @Nullable Drawable getVerticalScrollbarTrackDrawable() { return mScrollCache != null ? mScrollCache.scrollBar.getVerticalTrackDrawable() : null; } public @Nullable Drawable getHorizontalScrollbarThumbDrawable() { return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalThumbDrawable() : null; } public @Nullable Drawable getHorizontalScrollbarTrackDrawable() { return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalTrackDrawable() : null; } private void initializeScrollIndicatorsInternal() { if (mScrollIndicatorDrawable == null) { mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); } } private void initScrollCache() { if (mScrollCache == null) { mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); } } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private ScrollabilityCache getScrollCache() { initScrollCache(); return mScrollCache; } public void setVerticalScrollbarPosition(int position) { if (mVerticalScrollbarPosition != position) { mVerticalScrollbarPosition = position; computeOpaqueFlags(); resolvePadding(); } } public int getVerticalScrollbarPosition() { return mVerticalScrollbarPosition; } boolean isOnScrollbar(float x, float y) { if (mScrollCache == null) { return false; } x += getScrollX(); y += getScrollY(); final boolean canScrollVertically = computeVerticalScrollRange() > computeVerticalScrollExtent(); if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden() && canScrollVertically) { final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; getVerticalScrollBarBounds(null, touchBounds); if (touchBounds.contains((int) x, (int) y)) { return true; } } final boolean canScrollHorizontally = computeHorizontalScrollRange() > computeHorizontalScrollExtent(); if (isHorizontalScrollBarEnabled() && canScrollHorizontally) { final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; getHorizontalScrollBarBounds(null, touchBounds); if (touchBounds.contains((int) x, (int) y)) { return true; } } return false; } @UnsupportedAppUsage boolean isOnScrollbarThumb(float x, float y) { return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); } private boolean isOnVerticalScrollbarThumb(float x, float y) { if (mScrollCache == null || !isVerticalScrollBarEnabled() || isVerticalScrollBarHidden()) { return false; } final int range = computeVerticalScrollRange(); final int extent = computeVerticalScrollExtent(); if (range > extent) { x += getScrollX(); y += getScrollY(); final Rect bounds = mScrollCache.mScrollBarBounds; final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; getVerticalScrollBarBounds(bounds, touchBounds); final int offset = computeVerticalScrollOffset(); final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), extent, range); final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, extent, range, offset); final int thumbTop = bounds.top + thumbOffset; final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; if (x >= touchBounds.left && x <= touchBounds.right && y >= thumbTop - adjust && y <= thumbTop + thumbLength + adjust) { return true; } } return false; } private boolean isOnHorizontalScrollbarThumb(float x, float y) { if (mScrollCache == null || !isHorizontalScrollBarEnabled()) { return false; } final int range = computeHorizontalScrollRange(); final int extent = computeHorizontalScrollExtent(); if (range > extent) { x += getScrollX(); y += getScrollY(); final Rect bounds = mScrollCache.mScrollBarBounds; final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; getHorizontalScrollBarBounds(bounds, touchBounds); final int offset = computeHorizontalScrollOffset(); final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), extent, range); final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, extent, range, offset); final int thumbLeft = bounds.left + thumbOffset; final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; if (x >= thumbLeft - adjust && x <= thumbLeft + thumbLength + adjust && y >= touchBounds.top && y <= touchBounds.bottom) { return true; } } return false; } @UnsupportedAppUsage boolean isDraggingScrollBar() { return mScrollCache != null && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; } @RemotableViewMethod public void setScrollIndicators(@ScrollIndicators int indicators) { setScrollIndicators(indicators, SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); } public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; mask &= SCROLL_INDICATORS_PFLAG3_MASK; indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; indicators &= mask; final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); if (mPrivateFlags3 != updatedFlags) { mPrivateFlags3 = updatedFlags; if (indicators != 0) { initializeScrollIndicatorsInternal(); } invalidate(); } } @InspectableProperty(flagMapping = { @FlagEntry(target = SCROLL_INDICATORS_NONE, mask = 0xffff_ffff, name = "none"), @FlagEntry(target = SCROLL_INDICATOR_TOP, name = "top"), @FlagEntry(target = SCROLL_INDICATOR_BOTTOM, name = "bottom"), @FlagEntry(target = SCROLL_INDICATOR_LEFT, name = "left"), @FlagEntry(target = SCROLL_INDICATOR_RIGHT, name = "right"), @FlagEntry(target = SCROLL_INDICATOR_START, name = "start"), @FlagEntry(target = SCROLL_INDICATOR_END, name = "end") }) @ScrollIndicators public int getScrollIndicators() { return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; } @UnsupportedAppUsage ListenerInfo getListenerInfo() { if (mListenerInfo != null) { return mListenerInfo; } mListenerInfo = new ListenerInfo(); return mListenerInfo; } public void setOnScrollChangeListener(OnScrollChangeListener l) { getListenerInfo().mOnScrollChangeListener = l; } public void setOnFocusChangeListener(OnFocusChangeListener l) { getListenerInfo().mOnFocusChangeListener = l; } public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { ListenerInfo li = getListenerInfo(); if (li.mOnLayoutChangeListeners == null) { li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); } if (!li.mOnLayoutChangeListeners.contains(listener)) { li.mOnLayoutChangeListeners.add(listener); } } public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { ListenerInfo li = mListenerInfo; if (li == null || li.mOnLayoutChangeListeners == null) { return; } li.mOnLayoutChangeListeners.remove(listener); } public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { ListenerInfo li = getListenerInfo(); if (li.mOnAttachStateChangeListeners == null) { li.mOnAttachStateChangeListeners = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); } li.mOnAttachStateChangeListeners.add(listener); } public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { ListenerInfo li = mListenerInfo; if (li == null || li.mOnAttachStateChangeListeners == null) { return; } li.mOnAttachStateChangeListeners.remove(listener); } public OnFocusChangeListener getOnFocusChangeListener() { ListenerInfo li = mListenerInfo; return li != null ? li.mOnFocusChangeListener : null; } public void setOnClickListener(@Nullable OnClickListener l) { if (!isClickable()) { setClickable(true); } getListenerInfo().mOnClickListener = l; } public boolean hasOnClickListeners() { ListenerInfo li = mListenerInfo; return (li != null && li.mOnClickListener != null); } public void setOnLongClickListener(@Nullable OnLongClickListener l) { if (!isLongClickable()) { setLongClickable(true); } getListenerInfo().mOnLongClickListener = l; } public boolean hasOnLongClickListeners() { ListenerInfo li = mListenerInfo; return (li != null && li.mOnLongClickListener != null); } @Nullable public OnLongClickListener getOnLongClickListener() { ListenerInfo li = mListenerInfo; return (li != null) ? li.mOnLongClickListener : null; } public void setOnContextClickListener(@Nullable OnContextClickListener l) { if (!isContextClickable()) { setContextClickable(true); } getListenerInfo().mOnContextClickListener = l; } public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { if (!isLongClickable()) { setLongClickable(true); } getListenerInfo().mOnCreateContextMenuListener = l; } public void addFrameMetricsListener(Window window, Window.OnFrameMetricsAvailableListener listener, Handler handler) { if (mAttachInfo != null) { if (mAttachInfo.mThreadedRenderer != null) { if (mFrameMetricsObservers == null) { mFrameMetricsObservers = new ArrayList<>(); } FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener); mFrameMetricsObservers.add(fmo); mAttachInfo.mThreadedRenderer.addObserver(fmo.getRendererObserver()); } else { Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); } } else { if (mFrameMetricsObservers == null) { mFrameMetricsObservers = new ArrayList<>(); } FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener); mFrameMetricsObservers.add(fmo); } } public void removeFrameMetricsListener( Window.OnFrameMetricsAvailableListener listener) { ThreadedRenderer renderer = getThreadedRenderer(); FrameMetricsObserver fmo = findFrameMetricsObserver(listener); if (fmo == null) { throw new IllegalArgumentException( "attempt to remove OnFrameMetricsAvailableListener that was never added"); } if (mFrameMetricsObservers != null) { mFrameMetricsObservers.remove(fmo); if (renderer != null) { renderer.removeObserver(fmo.getRendererObserver()); } } } private void registerPendingFrameMetricsObservers() { if (mFrameMetricsObservers != null) { ThreadedRenderer renderer = getThreadedRenderer(); if (renderer != null) { for (FrameMetricsObserver fmo : mFrameMetricsObservers) { renderer.addObserver(fmo.getRendererObserver()); } } else { Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); } } } private FrameMetricsObserver findFrameMetricsObserver( Window.OnFrameMetricsAvailableListener listener) { if (mFrameMetricsObservers != null) { for (int i = 0; i < mFrameMetricsObservers.size(); i++) { FrameMetricsObserver observer = mFrameMetricsObservers.get(i); if (observer.mListener == listener) { return observer; } } } return null; } public void setNotifyAutofillManagerOnClick(boolean notify) { if (notify) { mPrivateFlags |= PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; } else { mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; } } private void notifyAutofillManagerOnClick() { if ((mPrivateFlags & PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK) != 0) { try { getAutofillManager().notifyViewClicked(this); } finally { mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; } } } private boolean performClickInternal() { notifyAutofillManagerOnClick(); return performClick(); } public boolean performClick() { notifyAutofillManagerOnClick(); final boolean result; final ListenerInfo li = mListenerInfo; if (li != null && li.mOnClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); li.mOnClickListener.onClick(this); result = true; } else { result = false; } sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); notifyEnterOrExitForAutoFillIfNeeded(true); return result; } public boolean callOnClick() { ListenerInfo li = mListenerInfo; if (li != null && li.mOnClickListener != null) { li.mOnClickListener.onClick(this); return true; } return false; } public boolean performLongClick() { return performLongClickInternal(mLongClickX, mLongClickY); } public boolean performLongClick(float x, float y) { mLongClickX = x; mLongClickY = y; final boolean handled = performLongClick(); mLongClickX = Float.NaN; mLongClickY = Float.NaN; return handled; } private boolean performLongClickInternal(float x, float y) { sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); boolean handled = false; 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); handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); } if ((mViewFlags & TOOLTIP) == TOOLTIP) { if (!handled) { handled = showLongClickTooltip((int) x, (int) y); } } if (handled && shouldPerformHapticFeedback) { performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); } return handled; } public boolean performContextClick(float x, float y) { return performContextClick(); } public boolean performContextClick() { sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); boolean handled = false; ListenerInfo li = mListenerInfo; if (li != null && li.mOnContextClickListener != null) { handled = li.mOnContextClickListener.onContextClick(View.this); } if (handled) { performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); } return handled; } protected boolean performButtonActionOnTouchDown(MotionEvent event) { if (event.isFromSource(InputDevice.SOURCE_MOUSE) && (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { showContextMenu(event.getX(), event.getY()); mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; return true; } return false; } public boolean showContextMenu() { return getParent().showContextMenuForChild(this); } public boolean showContextMenu(float x, float y) { return getParent().showContextMenuForChild(this, x, y); } public ActionMode startActionMode(ActionMode.Callback callback) { return startActionMode(callback, ActionMode.TYPE_PRIMARY); } public ActionMode startActionMode(ActionMode.Callback callback, int type) { ViewParent parent = getParent(); if (parent == null) return null; try { return parent.startActionModeForChild(this, callback, type); } catch (AbstractMethodError ame) { return parent.startActionModeForChild(this, callback); } } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public void startActivityForResult(Intent intent, int requestCode) { mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); } public boolean dispatchActivityResult( String who, int requestCode, int resultCode, Intent data) { if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { onActivityResult(requestCode, resultCode, data); mStartActivityRequestWho = null; return true; } return false; } public void onActivityResult(int requestCode, int resultCode, Intent data) { } public void setOnKeyListener(OnKeyListener l) { getListenerInfo().mOnKeyListener = l; } public void setOnTouchListener(OnTouchListener l) { getListenerInfo().mOnTouchListener = l; } public void setOnGenericMotionListener(OnGenericMotionListener l) { getListenerInfo().mOnGenericMotionListener = l; } public void setOnHoverListener(OnHoverListener l) { getListenerInfo().mOnHoverListener = l; } public void setOnDragListener(OnDragListener l) { getListenerInfo().mOnDragListener = l; } void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { if (DBG) { System.out.println(this + " requestFocus()"); } if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { mPrivateFlags |= PFLAG_FOCUSED; View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; if (mParent != null) { mParent.requestChildFocus(this, this); updateFocusedInCluster(oldFocus, direction); } if (mAttachInfo != null) { mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); } onFocusChanged(true, direction, previouslyFocusedRect); refreshDrawableState(); } } public final void setRevealOnFocusHint(boolean revealOnFocus) { if (revealOnFocus) { mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; } else { mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; } } public final boolean getRevealOnFocusHint() { return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; } public void getHotspotBounds(Rect outRect) { final Drawable background = getBackground(); if (background != null) { background.getHotspotBounds(outRect); } else { getBoundsOnScreen(outRect); } } public boolean requestRectangleOnScreen(Rect rectangle) { return requestRectangleOnScreen(rectangle, false); } public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { if (mParent == null) { return false; } View child = this; RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); position.set(rectangle); ViewParent parent = mParent; boolean scrolled = false; while (parent != null) { rectangle.set((int) position.left, (int) position.top, (int) position.right, (int) position.bottom); scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); if (!(parent instanceof View)) { break; } position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); child = (View) parent; parent = child.getParent(); } return scrolled; } public void clearFocus() { if (DBG) { System.out.println(this + " clearFocus()"); } final boolean refocus = sAlwaysAssignFocus || !isInTouchMode(); clearFocusInternal(null, true, refocus); } public void clearFocusInternal(View focused, boolean propagate, boolean refocus) { if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { mPrivateFlags &= ~PFLAG_FOCUSED; clearParentsWantFocus(); if (propagate && mParent != null) { mParent.clearChildFocus(this); } onFocusChanged(false, 0, null); refreshDrawableState(); if (propagate && (!refocus || !rootViewRequestFocus())) { notifyGlobalFocusCleared(this); } } } void notifyGlobalFocusCleared(View oldFocus) { if (oldFocus != null && mAttachInfo != null) { mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); } } boolean rootViewRequestFocus() { final View root = getRootView(); return root != null && root.requestFocus(); } void unFocus(View focused) { if (DBG) { System.out.println(this + " unFocus()"); } clearFocusInternal(focused, false, false); } @ViewDebug.ExportedProperty(category = "focus") public boolean hasFocus() { return (mPrivateFlags & PFLAG_FOCUSED) != 0; } public boolean hasFocusable() { return hasFocusable(!sHasFocusableExcludeAutoFocusable, false); } public boolean hasExplicitFocusable() { return hasFocusable(false, true); } boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) { if (!isFocusableInTouchMode()) { for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { final ViewGroup g = (ViewGroup) p; if (g.shouldBlockFocusForTouchscreen()) { return false; } } } if ((mViewFlags & VISIBILITY_MASK) != VISIBLE || (mViewFlags & ENABLED_MASK) != ENABLED) { return false; } if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) { return true; } return false; } @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 { notifyViewAccessibilityStateChangedIfNeeded( AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } switchDefaultFocusHighlight(); if (!gainFocus) { if (isPressed()) { setPressed(false); } if (hasWindowFocus()) { } onFocusLost(); } else if (hasWindowFocus()) { ViewRootImpl viewRoot = getViewRootImpl(); if (viewRoot != null) { if (mIsHandwritingDelegate) { viewRoot.getHandwritingInitiator().onDelegateViewFocused(this); } else if (initiationWithoutInputConnection() && onCheckIsTextEditor()) { viewRoot.getHandwritingInitiator().onEditorFocused(this); } } } invalidate(true); ListenerInfo li = mListenerInfo; if (li != null && li.mOnFocusChangeListener != null) { li.mOnFocusChangeListener.onFocusChange(this, gainFocus); } if (mAttachInfo != null) { mAttachInfo.mKeyDispatchState.reset(this); } if (mParent != null) { mParent.onDescendantUnbufferedRequested(); } notifyEnterOrExitForAutoFillIfNeeded(gainFocus); updatePreferKeepClearForFocus(); } private void notifyFocusChangeToImeFocusController(boolean hasFocus) { if (mAttachInfo == null) { return; } mAttachInfo.mViewRootImpl.getImeFocusController().onViewFocusChanged(this, hasFocus); } public void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { if (canNotifyAutofillEnterExitEvent()) { AutofillManager afm = getAutofillManager(); if (afm != null) { if (DBG) { Log.d(VIEW_LOG_TAG, this + " afm is not null"); } if (enter) { 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()) { afm.notifyViewEntered(this); } else { afm.notifyViewEnteredForFillDialog(this); } } } else if (!isFocused()) { afm.notifyViewExited(this); } } } } public void setAccessibilityPaneTitle(@Nullable CharSequence accessibilityPaneTitle) { if (!TextUtils.equals(accessibilityPaneTitle, mAccessibilityPaneTitle)) { boolean currentPaneTitleEmpty = mAccessibilityPaneTitle == null; boolean newPaneTitleEmpty = accessibilityPaneTitle == null; mAccessibilityPaneTitle = accessibilityPaneTitle; if (mAccessibilityPaneTitle != null && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); } if (currentPaneTitleEmpty) { notifyViewAccessibilityStateChangedIfNeeded( AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED); } else if (newPaneTitleEmpty) { notifyViewAccessibilityStateChangedIfNeeded( AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); } else { notifyViewAccessibilityStateChangedIfNeeded( AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_TITLE); } } } @InspectableProperty @Nullable public CharSequence getAccessibilityPaneTitle() { return mAccessibilityPaneTitle; } private boolean isAccessibilityPane() { return mAccessibilityPaneTitle != null; } public void sendAccessibilityEvent(int eventType) { if (mAccessibilityDelegate != null) { mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); } else { sendAccessibilityEventInternal(eventType); } } public void announceForAccessibility(CharSequence text) { if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { AccessibilityEvent event = AccessibilityEvent.obtain( AccessibilityEvent.TYPE_ANNOUNCEMENT); onInitializeAccessibilityEvent(event); event.getText().add(text); event.setContentDescription(null); mParent.requestSendAccessibilityEvent(this, event); } } public void sendAccessibilityEventInternal(int eventType) { if (AccessibilityManager.getInstance(mContext).isEnabled()) { sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); } } public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { if (mAccessibilityDelegate != null) { mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); } else { sendAccessibilityEventUncheckedInternal(event); } } public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { boolean isWindowStateChanged = (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); boolean isWindowDisappearedEvent = isWindowStateChanged && ((event.getContentChangeTypes() & AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED) != 0); boolean detached = detached(); if (!isShown() && !isWindowDisappearedEvent && !detached) { return; } onInitializeAccessibilityEvent(event); if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { dispatchPopulateAccessibilityEvent(event); } SendAccessibilityEventThrottle throttle = getThrottleForAccessibilityEvent(event); if (throttle != null) { throttle.post(event); } else if (!isWindowDisappearedEvent && detached) { postDelayed(() -> { if (AccessibilityManager.getInstance(mContext).isEnabled() && isShown()) { requestParentSendAccessibilityEvent(event); } }, ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); } else { requestParentSendAccessibilityEvent(event); } } private void requestParentSendAccessibilityEvent(AccessibilityEvent event) { ViewParent parent = getParent(); if (parent != null) { getParent().requestSendAccessibilityEvent(this, event); } } private SendAccessibilityEventThrottle getThrottleForAccessibilityEvent( AccessibilityEvent event) { if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { if (mSendViewScrolledAccessibilityEvent == null) { mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); } return mSendViewScrolledAccessibilityEvent; } boolean isStateContentChanged = (event.getContentChangeTypes() & AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION) != 0; if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED && isStateContentChanged) { if (mSendStateChangedAccessibilityEvent == null) { mSendStateChangedAccessibilityEvent = new SendAccessibilityEventThrottle(); } return mSendStateChangedAccessibilityEvent; } return null; } private void clearAccessibilityThrottles() { cancel(mSendViewScrolledAccessibilityEvent); cancel(mSendStateChangedAccessibilityEvent); } public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { if (mAccessibilityDelegate != null) { return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); } else { return dispatchPopulateAccessibilityEventInternal(event); } } public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { onPopulateAccessibilityEvent(event); return false; } @CallSuper public void onPopulateAccessibilityEvent(AccessibilityEvent event) { if (mAccessibilityDelegate != null) { mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); } else { onPopulateAccessibilityEventInternal(event); } } public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { if ((event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) && isAccessibilityPane()) { event.getText().add(getAccessibilityPaneTitle()); } } @CallSuper public void onInitializeAccessibilityEvent(AccessibilityEvent event) { if (mAccessibilityDelegate != null) { mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); } else { onInitializeAccessibilityEventInternal(event); } } @UnsupportedAppUsage public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { event.setSource(this); event.setClassName(getAccessibilityClassName()); event.setPackageName(getContext().getPackageName()); event.setEnabled(isEnabled()); event.setContentDescription(mContentDescription); event.setScrollX(getScrollX()); event.setScrollY(getScrollY()); switch (event.getEventType()) { case AccessibilityEvent.TYPE_VIEW_FOCUSED: { ArrayList<View> focusablesTempList = (mAttachInfo != null) ? mAttachInfo.mTempArrayList : new ArrayList<View>(); getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); event.setItemCount(focusablesTempList.size()); event.setCurrentItemIndex(focusablesTempList.indexOf(this)); if (mAttachInfo != null) { focusablesTempList.clear(); } } break; case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { CharSequence text = getIterableTextForAccessibility(); if (text != null && text.length() > 0) { event.setFromIndex(getAccessibilitySelectionStart()); event.setToIndex(getAccessibilitySelectionEnd()); event.setItemCount(text.length()); } } break; } } public AccessibilityNodeInfo createAccessibilityNodeInfo() { if (mAccessibilityDelegate != null) { return mAccessibilityDelegate.createAccessibilityNodeInfo(this); } else { return createAccessibilityNodeInfoInternal(); } } public @Nullable AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); if (provider != null) { return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); } else { AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); onInitializeAccessibilityNodeInfo(info); return info; } } @CallSuper public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { if (mAccessibilityDelegate != null) { mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); } else { onInitializeAccessibilityNodeInfoInternal(info); } } @UnsupportedAppUsage public void getBoundsOnScreen(Rect outRect) { getBoundsOnScreen(outRect, false); } @UnsupportedAppUsage @TestApi public void getBoundsOnScreen(@NonNull Rect outRect, boolean clipToParent) { if (mAttachInfo == null) { return; } RectF position = mAttachInfo.mTmpTransformRect; getBoundsToScreenInternal(position, clipToParent); outRect.set(Math.round(position.left), Math.round(position.top), Math.round(position.right), Math.round(position.bottom)); mAttachInfo.mViewRootImpl.applyViewBoundsSandboxingIfNeeded(outRect); } public void getBoundsOnScreen(RectF outRect, boolean clipToParent) { if (mAttachInfo == null) { return; } RectF position = mAttachInfo.mTmpTransformRect; getBoundsToScreenInternal(position, clipToParent); outRect.set(position.left, position.top, position.right, position.bottom); } 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); } public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) { mapRectFromViewToWindowCoords(rect, clipToParent); rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); } public void mapRectFromViewToWindowCoords(RectF rect, boolean clipToParent) { if (!hasIdentityMatrix()) { getMatrix().mapRect(rect); } rect.offset(mLeft, mTop); ViewParent parent = mParent; while (parent instanceof View) { View parentView = (View) parent; rect.offset(-parentView.mScrollX, -parentView.mScrollY); if (clipToParent) { rect.left = Math.max(rect.left, 0); rect.top = Math.max(rect.top, 0); rect.right = Math.min(rect.right, parentView.getWidth()); rect.bottom = Math.min(rect.bottom, parentView.getHeight()); } if (!parentView.hasIdentityMatrix()) { parentView.getMatrix().mapRect(rect); } rect.offset(parentView.mLeft, parentView.mTop); parent = parentView.mParent; } if (parent instanceof ViewRootImpl) { ViewRootImpl viewRootImpl = (ViewRootImpl) parent; rect.offset(0, -viewRootImpl.mCurScrollY); } } public CharSequence getAccessibilityClassName() { return View.class.getName(); } public void onProvideStructure(ViewStructure structure) { } public void onProvideAutofillStructure(ViewStructure structure, @AutofillFlags int flags) { onProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); } public void onProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) { onProvideStructure(structure, VIEW_STRUCTURE_FOR_CONTENT_CAPTURE, flags); } protected void onProvideStructure(@NonNull ViewStructure structure, @ViewStructureType int viewFor, int flags) { final int id = mID; if (id != NO_ID && !isViewIdGenerated(id)) { String pkg, type, entry; try { final Resources res = getResources(); entry = res.getResourceEntryName(id); type = res.getResourceTypeName(id); pkg = res.getResourcePackageName(id); } catch (Resources.NotFoundException e) { entry = type = pkg = null; } structure.setId(id, pkg, type, entry); } else { structure.setId(id, null, null, null); } if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { final @AutofillType int autofillType = getAutofillType(); if (autofillType != AUTOFILL_TYPE_NONE) { 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()); } int ignoredParentLeft = 0; int ignoredParentTop = 0; if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL && (flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) { View parentGroup = null; ViewParent viewParent = getParent(); if (viewParent instanceof View) { parentGroup = (View) viewParent; } while (parentGroup != null && !parentGroup.isImportantForAutofill()) { ignoredParentLeft += parentGroup.mLeft - parentGroup.mScrollX; ignoredParentTop += parentGroup.mTop - parentGroup.mScrollY; viewParent = parentGroup.getParent(); if (viewParent instanceof View) { parentGroup = (View) viewParent; } else { break; } } } structure.setDimens(ignoredParentLeft + mLeft, ignoredParentTop + mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop); if (viewFor == VIEW_STRUCTURE_FOR_ASSIST) { if (!hasIdentityMatrix()) { structure.setTransformation(getMatrix()); } structure.setElevation(getZ()); } structure.setVisibility(getVisibility()); structure.setEnabled(isEnabled()); if (isClickable()) { structure.setClickable(true); } if (isFocusable()) { structure.setFocusable(true); } if (isFocused()) { structure.setFocused(true); } if (isAccessibilityFocused()) { structure.setAccessibilityFocused(true); } if (isSelected()) { structure.setSelected(true); } if (isActivated()) { structure.setActivated(true); } if (isLongClickable()) { structure.setLongClickable(true); } if (this instanceof Checkable) { structure.setCheckable(true); if (((Checkable)this).isChecked()) { structure.setChecked(true); } } if (isOpaque()) { structure.setOpaque(true); } if (isContextClickable()) { structure.setContextClickable(true); } structure.setClassName(getAccessibilityClassName().toString()); structure.setContentDescription(getContentDescription()); } public void onProvideVirtualStructure(ViewStructure structure) { onProvideVirtualStructureCompat(structure, false); } private void onProvideVirtualStructureCompat(ViewStructure structure, boolean forAutofill) { final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); if (provider != null) { if (forAutofill && Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { Log.v(AUTOFILL_LOG_TAG, "onProvideVirtualStructureCompat() for " + this); } final AccessibilityNodeInfo info = createAccessibilityNodeInfo(); structure.setChildCount(1); final ViewStructure root = structure.newChild(0); if (info != null) { populateVirtualStructure(root, provider, info, forAutofill); info.recycle(); } else { Log.w(AUTOFILL_LOG_TAG, "AccessibilityNodeInfo is null."); } } } public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) { if (mContext.isAutofillCompatibilityEnabled()) { onProvideVirtualStructureCompat(structure, true); } } public void setOnReceiveContentListener( @SuppressLint("NullableCollection") @Nullable String[] mimeTypes, @Nullable OnReceiveContentListener listener) { if (listener != null) { Preconditions.checkArgument(mimeTypes != null && mimeTypes.length > 0, "When the listener is set, MIME types must also be set"); } if (mimeTypes != null) { } mReceiveContentMimeTypes = ArrayUtils.isEmpty(mimeTypes) ? null : mimeTypes; getListenerInfo().mOnReceiveContentListener = listener; } @Nullable public ContentInfo performReceiveContent(@NonNull ContentInfo payload) { final OnReceiveContentListener listener = (mListenerInfo == null) ? null : getListenerInfo().mOnReceiveContentListener; if (listener != null) { final ContentInfo remaining = listener.onReceiveContent(this, payload); return (remaining == null) ? null : onReceiveContent(remaining); } return onReceiveContent(payload); } @Nullable public ContentInfo onReceiveContent(@NonNull ContentInfo payload) { return payload; } @SuppressLint("NullableCollection") @Nullable public String[] getReceiveContentMimeTypes() { return mReceiveContentMimeTypes; } public void autofill(@SuppressWarnings("unused") AutofillValue value) { } public void autofill(@NonNull @SuppressWarnings("unused") SparseArray<AutofillValue> values) { if (!mContext.isAutofillCompatibilityEnabled()) { return; } final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); if (provider == null) { return; } final int valueCount = values.size(); for (int i = 0; i < valueCount; i++) { final AutofillValue value = values.valueAt(i); if (value.isText()) { final int virtualId = values.keyAt(i); final CharSequence text = value.getTextValue(); final Bundle arguments = new Bundle(); arguments.putCharSequence( AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text); provider.performAction(virtualId, AccessibilityNodeInfo.ACTION_SET_TEXT, arguments); } } } public void onGetCredentialResponse(GetCredentialResponse response) { if (getPendingCredentialCallback() == null) { Log.w(AUTOFILL_LOG_TAG, "onGetCredentialResponse called but no callback found"); return; } getPendingCredentialCallback().onResult(response); } 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)); } public final AutofillId getAutofillId() { if (mAutofillId == null) { mAutofillId = new AutofillId(getAutofillViewId()); } return mAutofillId; } @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) @Nullable public final GetCredentialRequest getPendingCredentialRequest() { if (mViewCredentialHandler == null) { return null; } return mViewCredentialHandler.getRequest(); } @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) @Nullable public final OutcomeReceiver<GetCredentialResponse, GetCredentialException> getPendingCredentialCallback() { if (mViewCredentialHandler == null) { return null; } return mViewCredentialHandler.getCallback(); } public void setAutofillId(@Nullable AutofillId id) { if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { Log.v(AUTOFILL_LOG_TAG, "setAutofill(): from " + mAutofillId + " to " + id); } if (isAttachedToWindow()) { throw new IllegalStateException("Cannot set autofill id when view is attached"); } if (id != null && !id.isNonVirtual()) { throw new IllegalStateException("Cannot set autofill id assigned to virtual views"); } if (id == null && (mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) == 0) { return; } mAutofillId = id; if (id != null) { mAutofillViewId = id.getViewId(); mPrivateFlags3 |= PFLAG3_AUTOFILLID_EXPLICITLY_SET; } else { mAutofillViewId = NO_ID; mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET; } } public void resetSubtreeAutofillIds() { if (mAutofillViewId == NO_ID) { return; } if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { Log.v(CONTENT_CAPTURE_LOG_TAG, "resetAutofillId() for " + mAutofillViewId); } else if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { Log.v(AUTOFILL_LOG_TAG, "resetAutofillId() for " + mAutofillViewId); } mAutofillId = null; mAutofillViewId = NO_ID; mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET; } public @AutofillType int getAutofillType() { return AUTOFILL_TYPE_NONE; } @ViewDebug.ExportedProperty() @InspectableProperty @Nullable public String[] getAutofillHints() { return mAutofillHints; } @TestApi public boolean isAutofilled() { return (mPrivateFlags3 & PFLAG3_IS_AUTOFILLED) != 0; } public boolean hideAutofillHighlight() { return (mPrivateFlags4 & PFLAG4_AUTOFILL_HIDE_HIGHLIGHT) != 0; } @Nullable public AutofillValue getAutofillValue() { return null; } @ViewDebug.ExportedProperty(mapping = { @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_AUTO, to = "auto"), @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES, to = "yes"), @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO, to = "no"), @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, to = "yesExcludeDescendants"), @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, to = "noExcludeDescendants")}) @InspectableProperty(enumMapping = { @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_AUTO, name = "auto"), @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES, name = "yes"), @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO, name = "no"), @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, name = "yesExcludeDescendants"), @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, name = "noExcludeDescendants"), }) public @AutofillImportance int getImportantForAutofill() { return (mPrivateFlags3 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK) >> PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; } public void setImportantForAutofill(@AutofillImportance int mode) { mPrivateFlags3 &= ~PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; mPrivateFlags3 |= (mode << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT) & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; } public final boolean isImportantForAutofill() { ViewParent parent = mParent; while (parent instanceof View) { final int parentImportance = ((View) parent).getImportantForAutofill(); if (parentImportance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS || parentImportance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS) { if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { Log.v(AUTOFILL_LOG_TAG, "View (" + this + ") is not important for autofill " + "because parent " + parent + "'s importance is " + parentImportance); } return false; } parent = parent.getParent(); } final int importance = getImportantForAutofill(); if (importance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS || importance == IMPORTANT_FOR_AUTOFILL_YES) { return true; } if (importance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS || importance == IMPORTANT_FOR_AUTOFILL_NO) { if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { Log.v(AUTOFILL_LOG_TAG, "View (" + this + ") is not important for autofill " + "because its importance is " + importance); } return false; } if (importance != IMPORTANT_FOR_AUTOFILL_AUTO) { Log.w(AUTOFILL_LOG_TAG, "invalid autofill importance (" + importance + " on view " + this); return false; } final int id = mID; if (id != NO_ID && !isViewIdGenerated(id)) { final Resources res = getResources(); String entry = null; String pkg = null; try { entry = res.getResourceEntryName(id); pkg = res.getResourcePackageName(id); } catch (Resources.NotFoundException e) { } if (entry != null && pkg != null && pkg.equals(mContext.getPackageName())) { return true; } } if (getAutofillHints() != null) { return true; } return false; } @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()); } } @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) public @ContentSensitivity final int getContentSensitivity() { return (mPrivateFlags4 & PFLAG4_CONTENT_SENSITIVITY_MASK) >> PFLAG4_CONTENT_SENSITIVITY_SHIFT; } @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; } 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(); } } } @ViewDebug.ExportedProperty(mapping = { @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, to = "auto"), @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES, to = "yes"), @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO, to = "no"), @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, to = "yesExcludeDescendants"), @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, to = "noExcludeDescendants")}) @InspectableProperty(enumMapping = { @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, name = "auto"), @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES, name = "yes"), @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO, name = "no"), @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, name = "yesExcludeDescendants"), @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, name = "noExcludeDescendants"), }) public @ContentCaptureImportance int getImportantForContentCapture() { return mPrivateFlags4 & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; } public void setImportantForContentCapture(@ContentCaptureImportance int mode) { mPrivateFlags4 &= ~PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; mPrivateFlags4 |= (mode & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK); } public final boolean isImportantForContentCapture() { boolean isImportant; if ((mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED) != 0) { isImportant = (mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE) != 0; return isImportant; } isImportant = calculateIsImportantForContentCapture(); mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; if (isImportant) { mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; } mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED; return isImportant; } private boolean calculateIsImportantForContentCapture() { ViewParent parent = mParent; while (parent instanceof View) { final int parentImportance = ((View) parent).getImportantForContentCapture(); if (parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS || parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS) { if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for " + "content capture because parent " + parent + "'s importance is " + parentImportance); } return false; } parent = parent.getParent(); } final int importance = getImportantForContentCapture(); if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS || importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES) { return true; } if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS || importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO) { if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for content " + "capture because its importance is " + importance); } return false; } if (importance != IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) { Log.w(CONTENT_CAPTURE_LOG_TAG, "invalid content capture importance (" + importance + " on view " + this); return false; } if (this instanceof ViewGroup) { final ViewGroup group = (ViewGroup) this; for (int i = 0; i < group.getChildCount(); i++) { final View child = group.getChildAt(i); if (child.isImportantForContentCapture()) { return true; } } } if (getAutofillHints() != null) { return true; } return false; } private void notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared) { AttachInfo ai = mAttachInfo; if (ai != null && !ai.mReadyForContentCaptureUpdates) return; if (mContext.getContentCaptureOptions() == null) return; if (appeared) { final boolean isRecycledWithoutRelayout = getNotifiedContentCaptureDisappeared() && getVisibility() == VISIBLE && !isLayoutRequested(); if (getVisibility() != VISIBLE || getNotifiedContentCaptureAppeared() || !(isLaidOut() || isRecycledWithoutRelayout)) { if (DEBUG_CONTENT_CAPTURE) { Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'appeared' on " + this + ": laid=" + isLaidOut() + ", visibleToUser=" + isVisibleToUser() + ", visible=" + (getVisibility() == VISIBLE) + ": alreadyNotifiedAppeared=" + getNotifiedContentCaptureAppeared() + ", alreadyNotifiedDisappeared=" + getNotifiedContentCaptureDisappeared()); } return; } } else { if (!getNotifiedContentCaptureAppeared() || getNotifiedContentCaptureDisappeared()) { if (DEBUG_CONTENT_CAPTURE) { Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'disappeared' on " + this + ": laid=" + isLaidOut() + ", visibleToUser=" + isVisibleToUser() + ", visible=" + (getVisibility() == VISIBLE) + ": alreadyNotifiedAppeared=" + getNotifiedContentCaptureAppeared() + ", alreadyNotifiedDisappeared=" + getNotifiedContentCaptureDisappeared()); } return; } } ContentCaptureSession session = getContentCaptureSession(); if (session == null) return; if (!isImportantForContentCapture()) return; if (appeared) { setNotifiedContentCaptureAppeared(); if (ai != null) { makeParentImportantAndNotifyAppearedEventIfNeed(); ai.delayNotifyContentCaptureEvent(session, this, appeared); } else { if (DEBUG_CONTENT_CAPTURE) { Log.w(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on appeared for " + this); } } } else { mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; if (ai != null) { ai.delayNotifyContentCaptureEvent(session, this, appeared); } else { if (DEBUG_CONTENT_CAPTURE) { Log.v(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on disappeared for " + this); } } if (!isTemporarilyDetached()) { clearTranslationState(); } } } private void makeParentImportantAndNotifyAppearedEventIfNeed() { final ViewParent parent = getParent(); if (parent instanceof View) { View p = ((View) parent); if (p.getNotifiedContentCaptureAppeared()) { return; } p.mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK; } } private void setNotifiedContentCaptureAppeared() { mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; } protected boolean getNotifiedContentCaptureAppeared() { return (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0; } private boolean getNotifiedContentCaptureDisappeared() { return (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0; } public void setContentCaptureSession(@Nullable ContentCaptureSession contentCaptureSession) { mContentCaptureSession = contentCaptureSession; } @Nullable public final ContentCaptureSession getContentCaptureSession() { if (mContentCaptureSessionCached) { return mContentCaptureSession; } mContentCaptureSession = getAndCacheContentCaptureSession(); mContentCaptureSessionCached = true; return mContentCaptureSession; } @Nullable private ContentCaptureSession getAndCacheContentCaptureSession() { if (mContentCaptureSession != null) { return mContentCaptureSession; } ContentCaptureSession session = null; if (mParent instanceof View) { session = ((View) mParent).getContentCaptureSession(); } if (session == null) { final ContentCaptureManager ccm = mContext .getSystemService(ContentCaptureManager.class); return ccm == null ? null : ccm.getMainContentCaptureSession(); } return session; } @Nullable private AutofillManager getAutofillManager() { return mContext.getSystemService(AutofillManager.class); } final boolean isActivityDeniedForAutofillForUnimportantView() { final AutofillManager afm = getAutofillManager(); if (afm == null) return false; return afm.isActivityDeniedForAutofill(); } final boolean isMatchingAutofillableHeuristics() { final AutofillManager afm = getAutofillManager(); if (afm == null) return false; return afm.isTriggerFillRequestOnUnimportantViewEnabled() ? afm.isAutofillable(this) : false; } private boolean isAutofillable() { 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; } final AutofillManager afm = getAutofillManager(); if (afm == null) { if (DBG) { Log.d(VIEW_LOG_TAG, "AutofillManager is null"); } return false; } if (getAutofillViewId() <= LAST_APP_AUTOFILL_ID) { if (DBG) { Log.d(VIEW_LOG_TAG, "getAutofillViewId()<=LAST_APP_AUTOFILL_ID"); } return false; } 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 (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; } 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) { structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), null, null, info.getViewIdResourceName()); Rect rect = structure.getTempRect(); info.getBoundsInParent(rect); structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); structure.setVisibility(VISIBLE); structure.setEnabled(info.isEnabled()); if (info.isClickable()) { structure.setClickable(true); } if (info.isFocusable()) { structure.setFocusable(true); } if (info.isFocused()) { structure.setFocused(true); } if (info.isAccessibilityFocused()) { structure.setAccessibilityFocused(true); } if (info.isSelected()) { structure.setSelected(true); } if (info.isLongClickable()) { structure.setLongClickable(true); } if (info.isCheckable()) { structure.setCheckable(true); if (info.isChecked()) { structure.setChecked(true); } } if (info.isContextClickable()) { structure.setContextClickable(true); } if (forAutofill) { 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()); if (forAutofill) { final int maxTextLength = info.getMaxTextLength(); if (maxTextLength != -1) { structure.setMaxTextLength(maxTextLength); } structure.setHint(info.getHintText()); } CharSequence text = info.getText(); boolean hasText = text != null || info.getError() != null; if (hasText) { structure.setText(text, info.getTextSelectionStart(), info.getTextSelectionEnd()); } if (forAutofill) { if (info.isEditable()) { structure.setDataIsSensitive(true); if (hasText) { structure.setAutofillType(AUTOFILL_TYPE_TEXT); structure.setAutofillValue(AutofillValue.forText(text)); } int inputType = info.getInputType(); if (inputType == 0 && info.isPassword()) { inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD; } structure.setInputType(inputType); } else { structure.setDataIsSensitive(false); } } final int NCHILDREN = info.getChildCount(); if (NCHILDREN > 0) { structure.setChildCount(NCHILDREN); for (int i=0; i<NCHILDREN; i++) { if (AccessibilityNodeInfo.getVirtualDescendantId(info.getChildNodeIds().get(i)) == AccessibilityNodeProvider.HOST_VIEW_ID) { Log.e(VIEW_LOG_TAG, "Virtual view pointing to its host. Ignoring"); continue; } AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); if (cinfo != null) { ViewStructure child = structure.newChild(i); populateVirtualStructure(child, provider, cinfo, forAutofill); cinfo.recycle(); } } } } public void dispatchProvideStructure(ViewStructure structure) { } public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure, @AutofillFlags int flags) { dispatchProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); } private void dispatchProvideStructure(@NonNull ViewStructure structure, @ViewStructureType int viewFor, @AutofillFlags int flags) { if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) { structure.setAutofillId(getAutofillId()); onProvideAutofillStructure(structure, flags); onProvideAutofillVirtualStructure(structure, flags); } else if (!isAssistBlocked()) { onProvideStructure(structure); onProvideVirtualStructure(structure); } else { structure.setClassName(getAccessibilityClassName().toString()); structure.setAssistBlocked(true); } } public void dispatchInitialProvideContentCaptureStructure() { AttachInfo ai = mAttachInfo; if (ai == null) { Log.w(CONTENT_CAPTURE_LOG_TAG, "dispatchProvideContentCaptureStructure(): no AttachInfo for " + this); return; } ContentCaptureManager ccm = ai.mContentCaptureManager; if (ccm == null) { Log.w(CONTENT_CAPTURE_LOG_TAG, "dispatchProvideContentCaptureStructure(): " + "no ContentCaptureManager for " + this); return; } ai.mReadyForContentCaptureUpdates = true; if (!isImportantForContentCapture()) { if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { Log.d(CONTENT_CAPTURE_LOG_TAG, "dispatchProvideContentCaptureStructure(): decorView is not important"); } return; } ai.mContentCaptureManager = ccm; ContentCaptureSession session = getContentCaptureSession(); if (session == null) { if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { Log.d(CONTENT_CAPTURE_LOG_TAG, "dispatchProvideContentCaptureStructure(): no session for " + this); } return; } try { dispatchProvideContentCaptureStructure(); } finally { } } void dispatchProvideContentCaptureStructure() { ContentCaptureSession session = getContentCaptureSession(); if (session != null) { ViewStructure structure = session.newViewStructure(this); setNotifiedContentCaptureAppeared(); session.notifyViewAppeared(structure); } } public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { if (mAttachInfo == null) { return; } Rect bounds = mAttachInfo.mTmpInvalRect; getDrawingRect(bounds); info.setBoundsInParent(bounds); getBoundsOnScreen(bounds, true); info.setBoundsInScreen(bounds); getBoundsInWindow(bounds, true); info.setBoundsInWindow(bounds); ViewParent parent = getParentForAccessibility(); if (parent instanceof View) { info.setParent((View) parent); } if (mID != View.NO_ID) { View rootView = getRootView(); if (rootView == null) { rootView = this; } View label = rootView.findLabelForView(this, mID); if (label != null) { info.setLabeledBy(label); } if ((mAttachInfo.mAccessibilityFetchFlags & AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_REPORT_VIEW_IDS) != 0 && Resources.resourceHasPackage(mID)) { try { String viewId = getResources().getResourceName(mID); info.setViewIdResourceName(viewId); } catch (Resources.NotFoundException nfe) { } } } if (mLabelForId != View.NO_ID) { View rootView = getRootView(); if (rootView == null) { rootView = this; } View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); if (labeled != null) { info.setLabelFor(labeled); } } if (mAccessibilityTraversalBeforeId != View.NO_ID) { View rootView = getRootView(); if (rootView == null) { rootView = this; } View next = rootView.findViewInsideOutShouldExist(this, mAccessibilityTraversalBeforeId); if (next != null && next.includeForAccessibility()) { info.setTraversalBefore(next); } } if (mAccessibilityTraversalAfterId != View.NO_ID) { View rootView = getRootView(); if (rootView == null) { rootView = this; } View next = rootView.findViewInsideOutShouldExist(this, mAccessibilityTraversalAfterId); if (next != null && next.includeForAccessibility()) { info.setTraversalAfter(next); } } info.setVisibleToUser(isVisibleToUser()); info.setImportantForAccessibility(isImportantForAccessibility()); info.setAccessibilityDataSensitive(isAccessibilityDataSensitive()); info.setPackageName(mContext.getPackageName()); info.setClassName(getAccessibilityClassName()); info.setStateDescription(getStateDescription()); info.setContentDescription(getContentDescription()); info.setEnabled(isEnabled()); info.setClickable(isClickable()); info.setFocusable(isFocusable()); info.setScreenReaderFocusable(isScreenReaderFocusable()); info.setFocused(isFocused()); info.setAccessibilityFocused(isAccessibilityFocused()); info.setSelected(isSelected()); info.setLongClickable(isLongClickable()); info.setContextClickable(isContextClickable()); info.setLiveRegion(getAccessibilityLiveRegion()); if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipText != null)) { info.setTooltipText(mTooltipInfo.mTooltipText); info.addAction((mTooltipInfo.mTooltipPopup == null) ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_TOOLTIP : AccessibilityNodeInfo.AccessibilityAction.ACTION_HIDE_TOOLTIP); } info.addAction(AccessibilityNodeInfo.ACTION_SELECT); info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); if (isFocusable()) { if (isFocused()) { info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); } else { info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); } } if (!isAccessibilityFocused()) { info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); } else { info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); } if (isClickable() && isEnabled()) { info.addAction(AccessibilityNodeInfo.ACTION_CLICK); } if (isLongClickable() && isEnabled()) { info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); } if (isContextClickable() && isEnabled()) { info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); } CharSequence text = getIterableTextForAccessibility(); if (text != null && text.length() > 0) { info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); } info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); populateAccessibilityNodeInfoDrawingOrderInParent(info); info.setPaneTitle(mAccessibilityPaneTitle); info.setHeading(isAccessibilityHeading()); if (mTouchDelegate != null) { info.setTouchDelegateInfo(mTouchDelegate.getTouchDelegateInfo()); } if (startedSystemDragForAccessibility()) { info.addAction(AccessibilityAction.ACTION_DRAG_CANCEL); } if (canAcceptAccessibilityDrop()) { info.addAction(AccessibilityAction.ACTION_DRAG_DROP); } } public void addExtraDataToAccessibilityNodeInfo( @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, @Nullable Bundle arguments) { } private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { info.setDrawingOrder(0); return; } int drawingOrderInParent = 1; View viewAtDrawingLevel = this; final ViewParent parent = getParentForAccessibility(); while (viewAtDrawingLevel != parent) { final ViewParent currentParent = viewAtDrawingLevel.getParent(); if (!(currentParent instanceof ViewGroup)) { drawingOrderInParent = 0; break; } else { final ViewGroup parentGroup = (ViewGroup) currentParent; final int childCount = parentGroup.getChildCount(); if (childCount > 1) { List<View> preorderedList = parentGroup.buildOrderedChildList(); if (preorderedList != null) { final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); for (int i = 0; i < childDrawIndex; i++) { drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); } preorderedList.clear(); } else { final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup .getChildDrawingOrder(childCount, childIndex) : childIndex; final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; if (childDrawIndex != 0) { for (int i = 0; i < numChildrenToIterate; i++) { final int otherDrawIndex = (customOrder ? parentGroup.getChildDrawingOrder(childCount, i) : i); if (otherDrawIndex < childDrawIndex) { drawingOrderInParent += numViewsForAccessibility(parentGroup.getChildAt(i)); } } } } } } viewAtDrawingLevel = (View) currentParent; } info.setDrawingOrder(drawingOrderInParent); } private static int numViewsForAccessibility(View view) { if (view != null) { if (view.includeForAccessibility()) { return 1; } else if (view instanceof ViewGroup) { return ((ViewGroup) view).getNumChildrenForAccessibility(); } } return 0; } private View findLabelForView(View view, int labeledId) { if (mMatchLabelForPredicate == null) { mMatchLabelForPredicate = new MatchLabelForPredicate(); } mMatchLabelForPredicate.mLabeledId = labeledId; return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); } public boolean isVisibleToUserForAutofill(int virtualId) { if (mContext.isAutofillCompatibilityEnabled()) { final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); if (provider != null) { final AccessibilityNodeInfo node = provider.createAccessibilityNodeInfo(virtualId); if (node != null) { return node.isVisibleToUser(); } } else { Log.w(VIEW_LOG_TAG, "isVisibleToUserForAutofill(" + virtualId + "): no provider"); } return false; } return true; } @UnsupportedAppUsage public boolean isVisibleToUser() { return isVisibleToUser(null); } @UnsupportedAppUsage(trackingBug = 171933273) protected boolean isVisibleToUser(Rect boundInView) { if (mAttachInfo != null) { if (mAttachInfo.mWindowVisibility != View.VISIBLE) { return false; } Object current = this; while (current instanceof View) { View view = (View) current; if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || view.getVisibility() != VISIBLE) { return false; } current = view.mParent; } Rect visibleRect = mAttachInfo.mTmpInvalRect; Point offset = mAttachInfo.mPoint; if (!getGlobalVisibleRect(visibleRect, offset)) { return false; } if (boundInView != null) { visibleRect.offset(-offset.x, -offset.y); return boundInView.intersect(visibleRect); } return true; } return false; } public AccessibilityDelegate getAccessibilityDelegate() { return mAccessibilityDelegate; } public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { mAccessibilityDelegate = delegate; } public AccessibilityNodeProvider getAccessibilityNodeProvider() { if (mAccessibilityDelegate != null) { return mAccessibilityDelegate.getAccessibilityNodeProvider(this); } else { return null; } } @UnsupportedAppUsage public int getAccessibilityViewId() { if (mAccessibilityViewId == NO_ID) { mAccessibilityViewId = sNextAccessibilityViewId++; } return mAccessibilityViewId; } public int getAutofillViewId() { if (mAutofillViewId == NO_ID) { mAutofillViewId = mContext.getNextAutofillId(); } return mAutofillViewId; } public int getAccessibilityWindowId() { return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId : AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; } @ViewDebug.ExportedProperty(category = "accessibility") public final @Nullable CharSequence getStateDescription() { return mStateDescription; } @ViewDebug.ExportedProperty(category = "accessibility") @InspectableProperty public CharSequence getContentDescription() { return mContentDescription; } @RemotableViewMethod public void setStateDescription(@Nullable CharSequence stateDescription) { if (mStateDescription == null) { if (stateDescription == null) { return; } } else if (mStateDescription.equals(stateDescription)) { return; } mStateDescription = stateDescription; if (!TextUtils.isEmpty(stateDescription) && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); } if (AccessibilityManager.getInstance(mContext).isEnabled()) { AccessibilityEvent event = AccessibilityEvent.obtain(); event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); event.setContentChangeTypes(AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION); sendAccessibilityEventUnchecked(event); } } @RemotableViewMethod public void setContentDescription(CharSequence contentDescription) { if (mContentDescription == null) { if (contentDescription == null) { return; } } else if (mContentDescription.equals(contentDescription)) { return; } mContentDescription = contentDescription; final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); notifySubtreeAccessibilityStateChangedIfNeeded(); } else { notifyViewAccessibilityStateChangedIfNeeded( AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); } } @RemotableViewMethod public void setAccessibilityTraversalBefore(@IdRes int beforeId) { if (mAccessibilityTraversalBeforeId == beforeId) { return; } mAccessibilityTraversalBeforeId = beforeId; notifyViewAccessibilityStateChangedIfNeeded( AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } @IdRes @InspectableProperty public int getAccessibilityTraversalBefore() { return mAccessibilityTraversalBeforeId; } @RemotableViewMethod public void setAccessibilityTraversalAfter(@IdRes int afterId) { if (mAccessibilityTraversalAfterId == afterId) { return; } mAccessibilityTraversalAfterId = afterId; notifyViewAccessibilityStateChangedIfNeeded( AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } @IdRes @InspectableProperty public int getAccessibilityTraversalAfter() { return mAccessibilityTraversalAfterId; } @IdRes @ViewDebug.ExportedProperty(category = "accessibility") @InspectableProperty public int getLabelFor() { return mLabelForId; } @RemotableViewMethod public void setLabelFor(@IdRes int id) { if (mLabelForId == id) { return; } mLabelForId = id; if (mLabelForId != View.NO_ID && mID == View.NO_ID) { mID = generateViewId(); } notifyViewAccessibilityStateChangedIfNeeded( AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } @CallSuper @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) protected void onFocusLost() { resetPressedState(); } private void resetPressedState() { if ((mViewFlags & ENABLED_MASK) == DISABLED) { return; } if (isPressed()) { setPressed(false); if (!mHasPerformedLongPress) { removeLongPressCallback(); } } } @ViewDebug.ExportedProperty(category = "focus") @InspectableProperty(hasAttributeId = false) public boolean isFocused() { return (mPrivateFlags & PFLAG_FOCUSED) != 0; } public View findFocus() { return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; } @InspectableProperty(name = "isScrollContainer") public boolean isScrollContainer() { return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; } public void setScrollContainer(boolean isScrollContainer) { if (isScrollContainer) { if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { mAttachInfo.mScrollContainers.add(this); mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; } mPrivateFlags |= PFLAG_SCROLL_CONTAINER; } else { if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { mAttachInfo.mScrollContainers.remove(this); } mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); } } @Deprecated @DrawingCacheQuality @InspectableProperty(enumMapping = { @EnumEntry(value = DRAWING_CACHE_QUALITY_LOW, name = "low"), @EnumEntry(value = DRAWING_CACHE_QUALITY_HIGH, name = "high"), @EnumEntry(value = DRAWING_CACHE_QUALITY_AUTO, name = "auto") }) public int getDrawingCacheQuality() { return mViewFlags & DRAWING_CACHE_QUALITY_MASK; } @Deprecated public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { setFlags(quality, DRAWING_CACHE_QUALITY_MASK); } @InspectableProperty public boolean getKeepScreenOn() { return (mViewFlags & KEEP_SCREEN_ON) != 0; } public void setKeepScreenOn(boolean keepScreenOn) { setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); } @IdRes @InspectableProperty(name = "nextFocusLeft") public int getNextFocusLeftId() { return mNextFocusLeftId; } public void setNextFocusLeftId(@IdRes int nextFocusLeftId) { mNextFocusLeftId = nextFocusLeftId; } @IdRes @InspectableProperty(name = "nextFocusRight") public int getNextFocusRightId() { return mNextFocusRightId; } public void setNextFocusRightId(@IdRes int nextFocusRightId) { mNextFocusRightId = nextFocusRightId; } @IdRes @InspectableProperty(name = "nextFocusUp") public int getNextFocusUpId() { return mNextFocusUpId; } public void setNextFocusUpId(@IdRes int nextFocusUpId) { mNextFocusUpId = nextFocusUpId; } @IdRes @InspectableProperty(name = "nextFocusDown") public int getNextFocusDownId() { return mNextFocusDownId; } public void setNextFocusDownId(@IdRes int nextFocusDownId) { mNextFocusDownId = nextFocusDownId; } @IdRes @InspectableProperty(name = "nextFocusForward") public int getNextFocusForwardId() { return mNextFocusForwardId; } public void setNextFocusForwardId(@IdRes int nextFocusForwardId) { mNextFocusForwardId = nextFocusForwardId; } @IdRes @InspectableProperty(name = "nextClusterForward") public int getNextClusterForwardId() { return mNextClusterForwardId; } public void setNextClusterForwardId(@IdRes int nextClusterForwardId) { mNextClusterForwardId = nextClusterForwardId; } public boolean isShown() { View current = this; do { if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { return false; } ViewParent parent = current.mParent; if (parent == null) { return false; } if (!(parent instanceof View)) { return true; } current = (View) parent; } while (current != null); return false; } private boolean detached() { View current = this; do { if ((current.mPrivateFlags4 & PFLAG4_DETACHED) != 0) { return true; } ViewParent parent = current.mParent; if (parent == null) { return false; } if (!(parent instanceof View)) { return false; } current = (View) parent; } while (current != null); return false; } @Deprecated protected boolean fitSystemWindows(Rect insets) { if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { if (insets == null) { return false; } try { mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); } finally { mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; } } else { return fitSystemWindowsInt(insets); } } private boolean fitSystemWindowsInt(Rect insets) { if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { Rect localInsets = sThreadLocal.get(); boolean res = computeFitSystemWindows(insets, localInsets); applyInsets(localInsets); return res; } return false; } private void applyInsets(Rect insets) { mUserPaddingStart = UNDEFINED_PADDING; mUserPaddingEnd = UNDEFINED_PADDING; mUserPaddingLeftInitial = insets.left; mUserPaddingRightInitial = insets.right; internalSetPadding(insets.left, insets.top, insets.right, insets.bottom); } public WindowInsets onApplyWindowInsets(WindowInsets insets) { if ((mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0 && (mViewFlags & FITS_SYSTEM_WINDOWS) != 0) { return onApplyFrameworkOptionalFitSystemWindows(insets); } if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { if (fitSystemWindows(insets.getSystemWindowInsetsAsRect())) { return insets.consumeSystemWindowInsets(); } } else { if (fitSystemWindowsInt(insets.getSystemWindowInsetsAsRect())) { return insets.consumeSystemWindowInsets(); } } return insets; } private WindowInsets onApplyFrameworkOptionalFitSystemWindows(WindowInsets insets) { Rect localInsets = sThreadLocal.get(); WindowInsets result = computeSystemWindowInsets(insets, localInsets); applyInsets(localInsets); return result; } public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { getListenerInfo().mOnApplyWindowInsetsListener = listener; } public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { try { mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); } else { return onApplyWindowInsets(insets); } } finally { mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; } } public void setWindowInsetsAnimationCallback( @Nullable WindowInsetsAnimation.Callback callback) { getListenerInfo().mWindowInsetsAnimationCallback = callback; } public boolean hasWindowInsetsAnimationCallback() { return getListenerInfo().mWindowInsetsAnimationCallback != null; } public void dispatchWindowInsetsAnimationPrepare( @NonNull WindowInsetsAnimation animation) { if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { mListenerInfo.mWindowInsetsAnimationCallback.onPrepare(animation); } } @NonNull public Bounds dispatchWindowInsetsAnimationStart( @NonNull WindowInsetsAnimation animation, @NonNull Bounds bounds) { if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { return mListenerInfo.mWindowInsetsAnimationCallback.onStart(animation, bounds); } return bounds; } @NonNull public WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets, @NonNull List<WindowInsetsAnimation> runningAnimations) { if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { return mListenerInfo.mWindowInsetsAnimationCallback.onProgress(insets, runningAnimations); } else { return insets; } } public void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation) { if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { mListenerInfo.mWindowInsetsAnimationCallback.onEnd(animation); } } public void setSystemGestureExclusionRects(@NonNull List<Rect> rects) { if (rects.isEmpty() && mListenerInfo == null) return; final ListenerInfo info = getListenerInfo(); if (info.mSystemGestureExclusionRects != null) { info.mSystemGestureExclusionRects.clear(); info.mSystemGestureExclusionRects.addAll(rects); } else { info.mSystemGestureExclusionRects = new ArrayList<>(rects); } updatePositionUpdateListener(); postUpdate(this::updateSystemGestureExclusionRects); } private void updatePositionUpdateListener() { final ListenerInfo info = getListenerInfo(); if (getSystemGestureExclusionRects().isEmpty() && collectPreferKeepClearRects().isEmpty() && collectUnrestrictedPreferKeepClearRects().isEmpty() && (info.mHandwritingArea == null || !shouldTrackHandwritingArea())) { if (info.mPositionUpdateListener != null) { mRenderNode.removePositionUpdateListener(info.mPositionUpdateListener); info.mPositionUpdateListener = null; info.mPositionChangedUpdate = null; } } else { if (info.mPositionUpdateListener == null) { info.mPositionChangedUpdate = () -> { updateSystemGestureExclusionRects(); updateKeepClearRects(); updateHandwritingArea(); }; info.mPositionUpdateListener = new RenderNode.PositionUpdateListener() { @Override public void positionChanged(long n, int l, int t, int r, int b) { postUpdate(info.mPositionChangedUpdate); } @Override public void positionLost(long frameNumber) { postUpdate(info.mPositionChangedUpdate); } }; mRenderNode.addPositionUpdateListener(info.mPositionUpdateListener); } } } private void postUpdate(Runnable r) { final Handler h = getHandler(); if (h != null) { h.postAtFrontOfQueue(r); } } void updateSystemGestureExclusionRects() { final AttachInfo ai = mAttachInfo; if (ai != null) { ai.mViewRootImpl.updateSystemGestureExclusionRectsForView(this); } } @NonNull public List<Rect> getSystemGestureExclusionRects() { final ListenerInfo info = mListenerInfo; if (info != null) { final List<Rect> list = info.mSystemGestureExclusionRects; if (list != null) { return list; } } return Collections.emptyList(); } public final void setPreferKeepClear(boolean preferKeepClear) { getListenerInfo().mPreferKeepClear = preferKeepClear; updatePositionUpdateListener(); postUpdate(this::updateKeepClearRects); } public final boolean isPreferKeepClear() { return mListenerInfo != null && mListenerInfo.mPreferKeepClear; } public final void setPreferKeepClearRects(@NonNull List<Rect> rects) { final ListenerInfo info = getListenerInfo(); if (info.mKeepClearRects != null) { info.mKeepClearRects.clear(); info.mKeepClearRects.addAll(rects); } else { info.mKeepClearRects = new ArrayList<>(rects); } updatePositionUpdateListener(); postUpdate(this::updateKeepClearRects); } @NonNull public final List<Rect> getPreferKeepClearRects() { final ListenerInfo info = mListenerInfo; if (info != null && info.mKeepClearRects != null) { return new ArrayList(info.mKeepClearRects); } return Collections.emptyList(); } @SystemApi @RequiresPermission(android.Manifest.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS) public final void setUnrestrictedPreferKeepClearRects(@NonNull List<Rect> rects) { final ListenerInfo info = getListenerInfo(); if (info.mUnrestrictedKeepClearRects != null) { info.mUnrestrictedKeepClearRects.clear(); info.mUnrestrictedKeepClearRects.addAll(rects); } else { info.mUnrestrictedKeepClearRects = new ArrayList<>(rects); } updatePositionUpdateListener(); postUpdate(this::updateKeepClearRects); } @SystemApi @NonNull public final List<Rect> getUnrestrictedPreferKeepClearRects() { final ListenerInfo info = mListenerInfo; if (info != null && info.mUnrestrictedKeepClearRects != null) { return new ArrayList(info.mUnrestrictedKeepClearRects); } return Collections.emptyList(); } void updateKeepClearRects() { final AttachInfo ai = mAttachInfo; if (ai != null) { ai.mViewRootImpl.updateKeepClearRectsForView(this); } } @NonNull List<Rect> collectPreferKeepClearRects() { ListenerInfo info = mListenerInfo; boolean keepClearForFocus = isFocused() && ViewConfiguration.get(mContext).isPreferKeepClearForFocusEnabled(); boolean keepBoundsClear = (info != null && info.mPreferKeepClear) || keepClearForFocus; boolean hasCustomKeepClearRects = info != null && info.mKeepClearRects != null; if (!keepBoundsClear && !hasCustomKeepClearRects) { return Collections.emptyList(); } else if (keepBoundsClear && !hasCustomKeepClearRects) { return Collections.singletonList(new Rect(0, 0, getWidth(), getHeight())); } final List<Rect> list = new ArrayList<>(); if (keepBoundsClear) { list.add(new Rect(0, 0, getWidth(), getHeight())); } if (hasCustomKeepClearRects) { list.addAll(info.mKeepClearRects); } return list; } private void updatePreferKeepClearForFocus() { if (ViewConfiguration.get(mContext).isPreferKeepClearForFocusEnabled()) { updatePositionUpdateListener(); post(this::updateKeepClearRects); } } @NonNull List<Rect> collectUnrestrictedPreferKeepClearRects() { final ListenerInfo info = mListenerInfo; if (info != null && info.mUnrestrictedKeepClearRects != null) { return info.mUnrestrictedKeepClearRects; } return Collections.emptyList(); } public void setHandwritingBoundsOffsets(float offsetLeft, float offsetTop, float offsetRight, float offsetBottom) { mHandwritingBoundsOffsetLeft = offsetLeft; mHandwritingBoundsOffsetTop = offsetTop; mHandwritingBoundsOffsetRight = offsetRight; mHandwritingBoundsOffsetBottom = offsetBottom; } public float getHandwritingBoundsOffsetLeft() { return mHandwritingBoundsOffsetLeft; } public float getHandwritingBoundsOffsetTop() { return mHandwritingBoundsOffsetTop; } public float getHandwritingBoundsOffsetRight() { return mHandwritingBoundsOffsetRight; } public float getHandwritingBoundsOffsetBottom() { return mHandwritingBoundsOffsetBottom; } public void setHandwritingArea(@Nullable Rect rect) { final ListenerInfo info = getListenerInfo(); info.mHandwritingArea = rect; updatePositionUpdateListener(); postUpdate(this::updateHandwritingArea); } @Nullable public Rect getHandwritingArea() { final ListenerInfo info = mListenerInfo; if (info != null && info.mHandwritingArea != null) { return new Rect(info.mHandwritingArea); } return null; } void updateHandwritingArea() { if (!shouldTrackHandwritingArea()) return; final AttachInfo ai = mAttachInfo; if (ai != null) { ai.mViewRootImpl.getHandwritingInitiator().updateHandwritingAreasForView(this); } } boolean shouldInitiateHandwriting() { return isAutoHandwritingEnabled() || getHandwritingDelegatorCallback() != null; } public boolean shouldTrackHandwritingArea() { return shouldInitiateHandwriting(); } public void setHandwritingDelegatorCallback(@Nullable Runnable callback) { mHandwritingDelegatorCallback = callback; if (callback != null) { setHandwritingArea(new Rect(0, 0, getWidth(), getHeight())); } } @Nullable public Runnable getHandwritingDelegatorCallback() { return mHandwritingDelegatorCallback; } public void setAllowedHandwritingDelegatePackage(@Nullable String allowedPackageName) { mAllowedHandwritingDelegatePackageName = allowedPackageName; } @Nullable public String getAllowedHandwritingDelegatePackageName() { return mAllowedHandwritingDelegatePackageName; } public void setIsHandwritingDelegate(boolean isHandwritingDelegate) { mIsHandwritingDelegate = isHandwritingDelegate; } public boolean isHandwritingDelegate() { return mIsHandwritingDelegate; } public void setAllowedHandwritingDelegatorPackage(@Nullable String allowedPackageName) { mAllowedHandwritingDelegatorPackageName = allowedPackageName; } @Nullable public String getAllowedHandwritingDelegatorPackageName() { return mAllowedHandwritingDelegatorPackageName; } @FlaggedApi(FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR) public void setHandwritingDelegateFlags( @InputMethodManager.HandwritingDelegateFlags int flags) { mHandwritingDelegateFlags = flags; } @FlaggedApi(FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR) public @InputMethodManager.HandwritingDelegateFlags int getHandwritingDelegateFlags() { return mHandwritingDelegateFlags; } public void getLocationInSurface(@NonNull @Size(2) int[] location) { getLocationInWindow(location); if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; } } public WindowInsets getRootWindowInsets() { if (mAttachInfo != null) { } return null; } public @Nullable WindowInsetsController getWindowInsetsController() { if (mAttachInfo != null) { return mAttachInfo.mViewRootImpl.getInsetsController(); } ViewParent parent = getParent(); if (parent instanceof View) { return ((View) parent).getWindowInsetsController(); } else if (parent instanceof ViewRootImpl) { return ((ViewRootImpl) parent).getInsetsController(); } return null; } @Nullable public final OnBackInvokedDispatcher findOnBackInvokedDispatcher() { ViewParent parent = getParent(); if (parent != null) { return parent.findOnBackInvokedDispatcherForChild(this, this); } return null; } @Deprecated @UnsupportedAppUsage protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { WindowInsets innerInsets = computeSystemWindowInsets(new WindowInsets(inoutInsets), outLocalInsets); inoutInsets.set(innerInsets.getSystemWindowInsetsAsRect()); return innerInsets.isSystemWindowInsetsConsumed(); } public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { boolean isOptionalFitSystemWindows = (mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) != 0 || (mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0; if (isOptionalFitSystemWindows && mAttachInfo != null) { OnContentApplyWindowInsetsListener listener = mAttachInfo.mContentOnApplyWindowInsetsListener; if (listener == null) { outLocalInsets.setEmpty(); return in; } Pair<Insets, WindowInsets> result = listener.onContentApplyWindowInsets(this, in); outLocalInsets.set(result.first.toRect()); return result.second; } else { outLocalInsets.set(in.getSystemWindowInsetsAsRect()); return in.consumeSystemWindowInsets().inset(outLocalInsets); } } protected boolean hasContentOnApplyWindowInsetsListener() { return mAttachInfo != null && mAttachInfo.mContentOnApplyWindowInsetsListener != null; } public void setFitsSystemWindows(boolean fitSystemWindows) { setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); } @ViewDebug.ExportedProperty @InspectableProperty public boolean getFitsSystemWindows() { return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean fitsSystemWindows() { return getFitsSystemWindows(); } @Deprecated public void requestFitSystemWindows() { if (mParent != null) { mParent.requestFitSystemWindows(); } } public void requestApplyInsets() { requestFitSystemWindows(); } @UnsupportedAppUsage public void makeOptionalFitsSystemWindows() { setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); } public void makeFrameworkOptionalFitsSystemWindows() { mPrivateFlags4 |= PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS; } public boolean isFrameworkOptionalFitsSystemWindows() { return (mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0; } @ViewDebug.ExportedProperty(mapping = { @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), @ViewDebug.IntToString(from = GONE, to = "GONE") }) @InspectableProperty(enumMapping = { @EnumEntry(value = VISIBLE, name = "visible"), @EnumEntry(value = INVISIBLE, name = "invisible"), @EnumEntry(value = GONE, name = "gone") }) @Visibility public int getVisibility() { return mViewFlags & VISIBILITY_MASK; } @RemotableViewMethod public void setVisibility(@Visibility int visibility) { setFlags(visibility, VISIBILITY_MASK); } @ViewDebug.ExportedProperty @InspectableProperty public boolean isEnabled() { return (mViewFlags & ENABLED_MASK) == ENABLED; } @RemotableViewMethod public void setEnabled(boolean enabled) { if (enabled == isEnabled()) return; setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); refreshDrawableState(); invalidate(true); if (!enabled) { cancelPendingInputEvents(); } notifyViewAccessibilityStateChangedIfNeeded( AccessibilityEvent.CONTENT_CHANGE_TYPE_ENABLED); } @RemotableViewMethod public void setFocusable(boolean focusable) { setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE); } @RemotableViewMethod public void setFocusable(@Focusable int focusable) { if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) { setFlags(0, FOCUSABLE_IN_TOUCH_MODE); } setFlags(focusable, FOCUSABLE_MASK); } @RemotableViewMethod public void setFocusableInTouchMode(boolean focusableInTouchMode) { setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); if (focusableInTouchMode) { setFlags(FOCUSABLE, FOCUSABLE_MASK); } } public void setAutofillHints(@Nullable String... autofillHints) { if (autofillHints == null || autofillHints.length == 0) { mAutofillHints = null; } else { mAutofillHints = autofillHints; } if (sensitiveContentAppProtection()) { if (getContentSensitivity() == CONTENT_SENSITIVITY_AUTO) { updateSensitiveViewsCountIfNeeded(isAggregatedVisible()); } } } @TestApi public void setAutofilled(boolean isAutofilled, boolean hideHighlight) { boolean wasChanged = isAutofilled != isAutofilled(); if (wasChanged) { if (isAutofilled) { mPrivateFlags3 |= PFLAG3_IS_AUTOFILLED; } else { mPrivateFlags3 &= ~PFLAG3_IS_AUTOFILLED; } if (hideHighlight) { mPrivateFlags4 |= PFLAG4_AUTOFILL_HIDE_HIGHLIGHT; } else { mPrivateFlags4 &= ~PFLAG4_AUTOFILL_HIDE_HIGHLIGHT; } invalidate(); } } public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); } @ViewDebug.ExportedProperty @InspectableProperty public boolean isSoundEffectsEnabled() { return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); } public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); } @ViewDebug.ExportedProperty @InspectableProperty public boolean isHapticFeedbackEnabled() { return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); } @ViewDebug.ExportedProperty(category = "layout", mapping = { @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") }) @InspectableProperty(hasAttributeId = false, enumMapping = { @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl"), @EnumEntry(value = LAYOUT_DIRECTION_INHERIT, name = "inherit"), @EnumEntry(value = LAYOUT_DIRECTION_LOCALE, name = "locale") }) @LayoutDir public int getRawLayoutDirection() { return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; } @RemotableViewMethod public void setLayoutDirection(@LayoutDir int layoutDirection) { if (getRawLayoutDirection() != layoutDirection) { mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; resetRtlProperties(); mPrivateFlags2 |= ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); resolveRtlPropertiesIfNeeded(); requestLayout(); invalidate(true); } } @ViewDebug.ExportedProperty(category = "layout", mapping = { @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") }) @InspectableProperty(enumMapping = { @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl") }) @ResolvedLayoutDir public int getLayoutDirection() { return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; } @ViewDebug.ExportedProperty(category = "layout") @UnsupportedAppUsage public boolean isLayoutRtl() { return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); } @ViewDebug.ExportedProperty(category = "layout") public boolean hasTransientState() { return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; } public void setHasTransientState(boolean hasTransientState) { final boolean oldHasTransientState = hasTransientState(); mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : mTransientStateCount - 1; if (mTransientStateCount < 0) { mTransientStateCount = 0; Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + "unmatched pair of setHasTransientState calls"); } else if ((hasTransientState && mTransientStateCount == 1) || (!hasTransientState && mTransientStateCount == 0)) { mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); final boolean newHasTransientState = hasTransientState(); if (mParent != null && newHasTransientState != oldHasTransientState) { try { mParent.childHasTransientStateChanged(this, newHasTransientState); } catch (AbstractMethodError e) { Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + " does not fully implement ViewParent", e); } } } } public void setHasTranslationTransientState(boolean hasTranslationTransientState) { if (hasTranslationTransientState) { mPrivateFlags4 |= PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; } else { mPrivateFlags4 &= ~PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; } } public boolean hasTranslationTransientState() { return (mPrivateFlags4 & PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE) == PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; } public void clearTranslationState() { if (mViewTranslationCallback != null) { mViewTranslationCallback.onClearTranslation(this); } clearViewTranslationResponse(); if (hasTranslationTransientState()) { setHasTransientState(false); setHasTranslationTransientState(false); } } public boolean isAttachedToWindow() { return mAttachInfo != null; } public boolean isLaidOut() { return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; } boolean isLayoutValid() { return isLaidOut() && ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == 0); } public void setWillNotDraw(boolean willNotDraw) { setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); } @ViewDebug.ExportedProperty(category = "drawing") public boolean willNotDraw() { return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; } @Deprecated public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); } @ViewDebug.ExportedProperty(category = "drawing") @Deprecated public boolean willNotCacheDrawing() { return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; } @ViewDebug.ExportedProperty @InspectableProperty public boolean isClickable() { return (mViewFlags & CLICKABLE) == CLICKABLE; } public void setClickable(boolean clickable) { setFlags(clickable ? CLICKABLE : 0, CLICKABLE); } public void setAllowClickWhenDisabled(boolean clickableWhenDisabled) { if (clickableWhenDisabled) { mPrivateFlags4 |= PFLAG4_ALLOW_CLICK_WHEN_DISABLED; } else { mPrivateFlags4 &= ~PFLAG4_ALLOW_CLICK_WHEN_DISABLED; } } @InspectableProperty public boolean isLongClickable() { return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; } public void setLongClickable(boolean longClickable) { setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); } @InspectableProperty public boolean isContextClickable() { return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; } public void setContextClickable(boolean contextClickable) { setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); } private void setPressed(boolean pressed, float x, float y) { if (pressed) { drawableHotspotChanged(x, y); } setPressed(pressed); } public void setPressed(boolean pressed) { final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); if (pressed) { mPrivateFlags |= PFLAG_PRESSED; } else { mPrivateFlags &= ~PFLAG_PRESSED; } if (needsRefresh) { refreshDrawableState(); } dispatchSetPressed(pressed); } protected void dispatchSetPressed(boolean pressed) { } @ViewDebug.ExportedProperty @InspectableProperty(hasAttributeId = false) public boolean isPressed() { return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; } public boolean isAssistBlocked() { return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; } @UnsupportedAppUsage public void setAssistBlocked(boolean enabled) { if (enabled) { mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; } else { mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; } } @InspectableProperty public boolean isSaveEnabled() { return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; } public void setSaveEnabled(boolean enabled) { setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); } @ViewDebug.ExportedProperty @InspectableProperty public boolean getFilterTouchesWhenObscured() { return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; } public void setFilterTouchesWhenObscured(boolean enabled) { setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, FILTER_TOUCHES_WHEN_OBSCURED); calculateAccessibilityDataSensitive(); } public boolean isSaveFromParentEnabled() { return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; } public void setSaveFromParentEnabled(boolean enabled) { setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); } @ViewDebug.ExportedProperty(category = "focus") public final boolean isFocusable() { return FOCUSABLE == (mViewFlags & FOCUSABLE); } @ViewDebug.ExportedProperty(mapping = { @ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"), @ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"), @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO") }, category = "focus") @InspectableProperty(enumMapping = { @EnumEntry(value = NOT_FOCUSABLE, name = "false"), @EnumEntry(value = FOCUSABLE, name = "true"), @EnumEntry(value = FOCUSABLE_AUTO, name = "auto") }) @Focusable public int getFocusable() { return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE; } @ViewDebug.ExportedProperty(category = "focus") @InspectableProperty public final boolean isFocusableInTouchMode() { return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); } @InspectableProperty public boolean isScreenReaderFocusable() { return (mPrivateFlags3 & PFLAG3_SCREEN_READER_FOCUSABLE) != 0; } public void setScreenReaderFocusable(boolean screenReaderFocusable) { updatePflags3AndNotifyA11yIfChanged(PFLAG3_SCREEN_READER_FOCUSABLE, screenReaderFocusable); } @InspectableProperty public boolean isAccessibilityHeading() { return (mPrivateFlags3 & PFLAG3_ACCESSIBILITY_HEADING) != 0; } public void setAccessibilityHeading(boolean isHeading) { updatePflags3AndNotifyA11yIfChanged(PFLAG3_ACCESSIBILITY_HEADING, isHeading); } private void updatePflags3AndNotifyA11yIfChanged(int mask, boolean newValue) { int pflags3 = mPrivateFlags3; if (newValue) { pflags3 |= mask; } else { pflags3 &= ~mask; } if (pflags3 != mPrivateFlags3) { mPrivateFlags3 = pflags3; notifyViewAccessibilityStateChangedIfNeeded( AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } } public View focusSearch(@FocusRealDirection int direction) { if (mParent != null) { return mParent.focusSearch(this, direction); } else { return null; } } @ViewDebug.ExportedProperty(category = "focus") @InspectableProperty public final boolean isKeyboardNavigationCluster() { return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; } View findKeyboardNavigationCluster() { if (mParent instanceof View) { View cluster = ((View) mParent).findKeyboardNavigationCluster(); if (cluster != null) { return cluster; } else if (isKeyboardNavigationCluster()) { return this; } } return null; } public void setKeyboardNavigationCluster(boolean isCluster) { if (isCluster) { mPrivateFlags3 |= PFLAG3_CLUSTER; } else { mPrivateFlags3 &= ~PFLAG3_CLUSTER; } } @TestApi public final void setFocusedInCluster() { setFocusedInCluster(findKeyboardNavigationCluster()); } private void setFocusedInCluster(View cluster) { if (this instanceof ViewGroup) { ((ViewGroup) this).mFocusedInCluster = null; } if (cluster == this) { return; } ViewParent parent = mParent; View child = this; while (parent instanceof ViewGroup) { ((ViewGroup) parent).mFocusedInCluster = child; if (parent == cluster) { break; } child = (View) parent; parent = parent.getParent(); } } private void updateFocusedInCluster(View oldFocus, @FocusDirection int direction) { if (oldFocus != null) { View oldCluster = oldFocus.findKeyboardNavigationCluster(); View cluster = findKeyboardNavigationCluster(); if (oldCluster != cluster) { oldFocus.setFocusedInCluster(oldCluster); if (!(oldFocus.mParent instanceof ViewGroup)) { return; } if (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD) { ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); } else if (oldFocus instanceof ViewGroup && ((ViewGroup) oldFocus).getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS && ViewRootImpl.isViewDescendantOf(this, oldFocus)) { ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); } } } } @ViewDebug.ExportedProperty(category = "focus") @InspectableProperty public final boolean isFocusedByDefault() { return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0; } @RemotableViewMethod public void setFocusedByDefault(boolean isFocusedByDefault) { if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) { return; } if (isFocusedByDefault) { mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT; } else { mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT; } if (mParent instanceof ViewGroup) { if (isFocusedByDefault) { ((ViewGroup) mParent).setDefaultFocus(this); } else { ((ViewGroup) mParent).clearDefaultFocus(this); } } } boolean hasDefaultFocus() { return isFocusedByDefault(); } public View keyboardNavigationClusterSearch(View currentCluster, @FocusDirection int direction) { if (isKeyboardNavigationCluster()) { currentCluster = this; } if (isRootNamespace()) { return FocusFinder.getInstance().findNextKeyboardNavigationCluster( this, currentCluster, direction); } else if (mParent != null) { return mParent.keyboardNavigationClusterSearch(currentCluster, direction); } return null; } public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { return false; } public void setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled) { mDefaultFocusHighlightEnabled = defaultFocusHighlightEnabled; } @ViewDebug.ExportedProperty(category = "focus") @InspectableProperty public final boolean getDefaultFocusHighlightEnabled() { return mDefaultFocusHighlightEnabled; } View findUserSetNextFocus(View root, @FocusDirection int direction) { switch (direction) { case FOCUS_LEFT: if (mNextFocusLeftId == View.NO_ID) return null; return findViewInsideOutShouldExist(root, mNextFocusLeftId); case FOCUS_RIGHT: if (mNextFocusRightId == View.NO_ID) return null; return findViewInsideOutShouldExist(root, mNextFocusRightId); case FOCUS_UP: if (mNextFocusUpId == View.NO_ID) return null; return findViewInsideOutShouldExist(root, mNextFocusUpId); case FOCUS_DOWN: if (mNextFocusDownId == View.NO_ID) return null; return findViewInsideOutShouldExist(root, mNextFocusDownId); case FOCUS_FORWARD: if (mNextFocusForwardId == View.NO_ID) return null; return findViewInsideOutShouldExist(root, mNextFocusForwardId); case FOCUS_BACKWARD: { if (mID == View.NO_ID) return null; final View rootView = root; final View startView = this; return root.findViewByPredicateInsideOut(startView, t -> findViewInsideOutShouldExist(rootView, t, t.mNextFocusForwardId) == startView); } } return null; } View findUserSetNextKeyboardNavigationCluster(View root, @FocusDirection int direction) { switch (direction) { case FOCUS_FORWARD: if (mNextClusterForwardId == View.NO_ID) return null; return findViewInsideOutShouldExist(root, mNextClusterForwardId); case FOCUS_BACKWARD: { if (mID == View.NO_ID) return null; final int id = mID; return root.findViewByPredicateInsideOut(this, (Predicate<View>) t -> t.mNextClusterForwardId == id); } } return null; } private View findViewInsideOutShouldExist(View root, int id) { return findViewInsideOutShouldExist(root, this, id); } private View findViewInsideOutShouldExist(View root, View start, int id) { if (mMatchIdPredicate == null) { mMatchIdPredicate = new MatchIdPredicate(); } mMatchIdPredicate.mId = id; View result = root.findViewByPredicateInsideOut(start, mMatchIdPredicate); if (result == null) { Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); } return result; } public ArrayList<View> getFocusables(@FocusDirection int direction) { ArrayList<View> result = new ArrayList<View>(24); addFocusables(result, direction); return result; } public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); } public void addFocusables(ArrayList<View> views, @FocusDirection int direction, @FocusableMode int focusableMode) { if (views == null) { return; } if (!canTakeFocus()) { return; } if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE && !isFocusableInTouchMode()) { return; } views.add(this); } public void addKeyboardNavigationClusters( @NonNull Collection<View> views, int direction) { if (!isKeyboardNavigationCluster()) { return; } if (!hasFocusable()) { return; } views.add(this); } public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, @FindViewFlags int flags) { if (getAccessibilityNodeProvider() != null) { if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { outViews.add(this); } } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 && (searched != null && searched.length() > 0) && (mContentDescription != null && mContentDescription.length() > 0)) { String searchedLowerCase = searched.toString().toLowerCase(); String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); if (contentDescriptionLowerCase.contains(searchedLowerCase)) { outViews.add(this); } } } public ArrayList<View> getTouchables() { ArrayList<View> result = new ArrayList<View>(); addTouchables(result); return result; } public void addTouchables(ArrayList<View> views) { final int viewFlags = mViewFlags; if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) && (viewFlags & ENABLED_MASK) == ENABLED) { views.add(this); } } @InspectableProperty(hasAttributeId = false) public boolean isAccessibilityFocused() { return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; } @UnsupportedAppUsage public boolean requestAccessibilityFocus() { AccessibilityManager manager = AccessibilityManager.getInstance(mContext); if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { return false; } if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { return false; } if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; ViewRootImpl viewRootImpl = getViewRootImpl(); if (viewRootImpl != null) { viewRootImpl.setAccessibilityFocus(this, null); } invalidate(); sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); return true; } return false; } @UnsupportedAppUsage public void clearAccessibilityFocus() { clearAccessibilityFocusNoCallbacks(0); final ViewRootImpl viewRootImpl = getViewRootImpl(); if (viewRootImpl != null) { final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { viewRootImpl.setAccessibilityFocus(null, null); } } } private void sendAccessibilityHoverEvent(int eventType) { View source = this; while (true) { if (source.includeForAccessibility(false)) { source.sendAccessibilityEvent(eventType); return; } ViewParent parent = source.getParent(); if (parent instanceof View) { source = (View) parent; } else { return; } } } void clearAccessibilityFocusNoCallbacks(int action) { if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; invalidate(); if (AccessibilityManager.getInstance(mContext).isEnabled()) { AccessibilityEvent event = AccessibilityEvent.obtain( AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); event.setAction(action); if (mAccessibilityDelegate != null) { mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); } else { sendAccessibilityEventUnchecked(event); } } updatePreferKeepClearForFocus(); } } public final boolean requestFocus() { return requestFocus(View.FOCUS_DOWN); } @TestApi public boolean restoreFocusInCluster(@FocusRealDirection int direction) { if (restoreDefaultFocus()) { return true; } return requestFocus(direction); } @TestApi public boolean restoreFocusNotInCluster() { return requestFocus(View.FOCUS_DOWN); } public boolean restoreDefaultFocus() { return requestFocus(View.FOCUS_DOWN); } public final boolean requestFocus(int direction) { return requestFocus(direction, null); } public boolean requestFocus(int direction, Rect previouslyFocusedRect) { return requestFocusNoSearch(direction, previouslyFocusedRect); } private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { if (!canTakeFocus()) { return false; } if (isInTouchMode() && (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { return false; } if (hasAncestorThatBlocksDescendantFocus()) { return false; } if (!isLayoutValid()) { mPrivateFlags |= PFLAG_WANTS_FOCUS; } else { clearParentsWantFocus(); } handleFocusGainInternal(direction, previouslyFocusedRect); return true; } void clearParentsWantFocus() { if (mParent instanceof View) { ((View) mParent).mPrivateFlags &= ~PFLAG_WANTS_FOCUS; ((View) mParent).clearParentsWantFocus(); } } public final boolean requestFocusFromTouch() { if (isInTouchMode()) { ViewRootImpl viewRoot = getViewRootImpl(); if (viewRoot != null) { viewRoot.ensureTouchMode(false); } } return requestFocus(View.FOCUS_DOWN); } private boolean hasAncestorThatBlocksDescendantFocus() { final boolean focusableInTouchMode = isFocusableInTouchMode(); ViewParent ancestor = mParent; while (ancestor instanceof ViewGroup) { final ViewGroup vgAncestor = (ViewGroup) ancestor; if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { return true; } else { ancestor = vgAncestor.getParent(); } } return false; } @ViewDebug.ExportedProperty(category = "accessibility", mapping = { @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, to = "noHideDescendants") }) @InspectableProperty(enumMapping = { @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_AUTO, name = "auto"), @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_YES, name = "yes"), @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO, name = "no"), @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, name = "noHideDescendants"), }) public int getImportantForAccessibility() { return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; } public void setAccessibilityLiveRegion(int mode) { if (mode != getAccessibilityLiveRegion()) { mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; notifyViewAccessibilityStateChangedIfNeeded( AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } } @InspectableProperty(enumMapping = { @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_NONE, name = "none"), @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_POLITE, name = "polite"), @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_ASSERTIVE, name = "assertive") }) public int getAccessibilityLiveRegion() { return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; } public void setImportantForAccessibility(int mode) { final int oldMode = getImportantForAccessibility(); if (mode != oldMode) { final boolean hideDescendants = mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { final View focusHost = findAccessibilityFocusHost(hideDescendants); if (focusHost != null) { focusHost.clearAccessibilityFocus(); } } final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; final boolean oldIncludeForAccessibility = maySkipNotify && includeForAccessibility(false); mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility(false)) { notifySubtreeAccessibilityStateChangedIfNeeded(); } else { notifyViewAccessibilityStateChangedIfNeeded( AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } } } private View findAccessibilityFocusHost(boolean searchDescendants) { if (isAccessibilityFocusedViewOrHost()) { return this; } if (searchDescendants) { final ViewRootImpl viewRoot = getViewRootImpl(); if (viewRoot != null) { final View focusHost = viewRoot.getAccessibilityFocusedHost(); if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { return focusHost; } } } return null; } public boolean isImportantForAccessibility() { final int mode = getImportantForAccessibility(); if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { return false; } ViewParent parent = mParent; while (parent instanceof View) { if (((View) parent).getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { return false; } parent = parent.getParent(); } return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null || getAccessibilityDelegate() != null || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE || isAccessibilityPane() || isAccessibilityHeading(); } public ViewParent getParentForAccessibility() { if (mParent instanceof View) { View parentView = (View) mParent; if (parentView.includeForAccessibility()) { return mParent; } else { return mParent.getParentForAccessibility(); } } return null; } @Nullable View getSelfOrParentImportantForA11y() { if (isImportantForAccessibility()) return this; ViewParent parent = getParentForAccessibility(); if (parent instanceof View) return (View) parent; return null; } public void addChildrenForAccessibility(ArrayList<View> outChildren) { } @UnsupportedAppUsage public boolean includeForAccessibility() { return includeForAccessibility(true); } public boolean includeForAccessibility(boolean forNodeTree) { if (mAttachInfo == null) { return false; } if (forNodeTree) { if (!AccessibilityManager.getInstance(mContext).isRequestFromAccessibilityTool() && isAccessibilityDataSensitive()) { return false; } } return (mAttachInfo.mAccessibilityFetchFlags & AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 || isImportantForAccessibility(); } @ViewDebug.ExportedProperty(category = "accessibility") public boolean isAccessibilityDataSensitive() { if (mInferredAccessibilityDataSensitive == ACCESSIBILITY_DATA_SENSITIVE_AUTO) { calculateAccessibilityDataSensitive(); } return mInferredAccessibilityDataSensitive == ACCESSIBILITY_DATA_SENSITIVE_YES; } void calculateAccessibilityDataSensitive() { if (mExplicitAccessibilityDataSensitive != ACCESSIBILITY_DATA_SENSITIVE_AUTO) { mInferredAccessibilityDataSensitive = mExplicitAccessibilityDataSensitive; } else if (getFilterTouchesWhenObscured()) { mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_YES; } else if (mParent instanceof View && ((View) mParent).isAccessibilityDataSensitive()) { mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_YES; } else { mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_NO; } } public void setAccessibilityDataSensitive( @AccessibilityDataSensitive int accessibilityDataSensitive) { mExplicitAccessibilityDataSensitive = accessibilityDataSensitive; calculateAccessibilityDataSensitive(); } public boolean isActionableForAccessibility() { return (isClickable() || isLongClickable() || isFocusable() || isContextClickable() || isScreenReaderFocusable()); } private boolean hasListenersForAccessibility() { ListenerInfo info = getListenerInfo(); return mTouchDelegate != null || info.mOnKeyListener != null || info.mOnTouchListener != null || info.mOnGenericMotionListener != null || info.mOnHoverListener != null || info.mOnDragListener != null; } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { return; } if ((changeType != AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) && (isAccessibilityPane() || (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED) && isAggregatedVisible())) { if ((isAggregatedVisible()) || (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED)) { final AccessibilityEvent event = AccessibilityEvent.obtain(); onInitializeAccessibilityEvent(event); event.setEventType(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); event.setContentChangeTypes(changeType); event.setSource(this); onPopulateAccessibilityEvent(event); if (mParent != null) { try { mParent.requestSendAccessibilityEvent(this, event); } catch (AbstractMethodError e) { Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + " does not fully implement ViewParent", e); } } return; } } if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) { final AccessibilityEvent event = AccessibilityEvent.obtain(); event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); event.setContentChangeTypes(changeType); sendAccessibilityEventUnchecked(event); } else if (mParent != null) { try { mParent.notifySubtreeAccessibilityStateChanged(this, this, changeType); } catch (AbstractMethodError e) { Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + " does not fully implement ViewParent", e); } } } @UnsupportedAppUsage public void notifySubtreeAccessibilityStateChangedIfNeeded() { if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { return; } if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; if (mParent != null) { try { mParent.notifySubtreeAccessibilityStateChanged( this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); } catch (AbstractMethodError e) { Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + " does not fully implement ViewParent", e); } } } } private void notifySubtreeAccessibilityStateChangedByParentIfNeeded() { if (!AccessibilityManager.getInstance(mContext).isEnabled()) { return; } final View sendA11yEventView = (View) getParentForAccessibility(); if (sendA11yEventView != null && sendA11yEventView.isShown()) { sendA11yEventView.notifySubtreeAccessibilityStateChangedIfNeeded(); } } public void setTransitionVisibility(@Visibility int visibility) { mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; } void resetSubtreeAccessibilityStateChanged() { mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; } public boolean dispatchNestedPrePerformAccessibilityAction(int action, @Nullable Bundle arguments) { for (ViewParent p = getParent(); p != null; p = p.getParent()) { if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { return true; } } return false; } public boolean performAccessibilityAction(int action, @Nullable Bundle arguments) { if (mAccessibilityDelegate != null) { return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); } else { return performAccessibilityActionInternal(action, arguments); } } @UnsupportedAppUsage public boolean performAccessibilityActionInternal(int action, @Nullable Bundle arguments) { if (isNestedScrollingEnabled() && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD || action == R.id.accessibilityActionScrollUp || action == R.id.accessibilityActionScrollLeft || action == R.id.accessibilityActionScrollDown || action == R.id.accessibilityActionScrollRight)) { if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { return true; } } switch (action) { case AccessibilityNodeInfo.ACTION_CLICK: { if (isClickable()) { performClickInternal(); return true; } } break; case AccessibilityNodeInfo.ACTION_LONG_CLICK: { if (isLongClickable()) { performLongClick(); return true; } } break; case AccessibilityNodeInfo.ACTION_FOCUS: { if (!hasFocus()) { getViewRootImpl().ensureTouchMode(false); return requestFocus(); } } break; case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { if (hasFocus()) { clearFocus(); return !isFocused(); } } break; case AccessibilityNodeInfo.ACTION_SELECT: { if (!isSelected()) { setSelected(true); return isSelected(); } } break; case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { if (isSelected()) { setSelected(false); return !isSelected(); } } break; case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { if (!isAccessibilityFocused()) { return requestAccessibilityFocus(); } } break; case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { if (isAccessibilityFocused()) { clearAccessibilityFocus(); return true; } } break; case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { if (arguments != null) { final int granularity = arguments.getInt( AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); final boolean extendSelection = arguments.getBoolean( AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); return traverseAtGranularity(granularity, true, extendSelection); } } break; case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { if (arguments != null) { final int granularity = arguments.getInt( AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); final boolean extendSelection = arguments.getBoolean( AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); return traverseAtGranularity(granularity, false, extendSelection); } } break; case AccessibilityNodeInfo.ACTION_SET_SELECTION: { CharSequence text = getIterableTextForAccessibility(); if (text == null) { return false; } final int start = (arguments != null) ? arguments.getInt( AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; final int end = (arguments != null) ? arguments.getInt( AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; if ((getAccessibilitySelectionStart() != start || getAccessibilitySelectionEnd() != end) && (start == end)) { setAccessibilitySelection(start, end); notifyViewAccessibilityStateChangedIfNeeded( AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); return true; } } break; case R.id.accessibilityActionShowOnScreen: { if (mAttachInfo != null) { final Rect r = mAttachInfo.mTmpInvalRect; getDrawingRect(r); return requestRectangleOnScreen(r, true); } } break; case R.id.accessibilityActionContextClick: { if (isContextClickable()) { performContextClick(); return true; } } break; case R.id.accessibilityActionShowTooltip: { if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipPopup != null)) { return false; } return showLongClickTooltip(0, 0); } case R.id.accessibilityActionHideTooltip: { if ((mTooltipInfo == null) || (mTooltipInfo.mTooltipPopup == null)) { return false; } hideTooltip(); return true; } case R.id.accessibilityActionDragDrop: { if (!canAcceptAccessibilityDrop()) { return false; } try { if (mAttachInfo != null && mAttachInfo.mSession != null) { final int[] location = new int[2]; getLocationInWindow(location); final int centerX = location[0] + getWidth() / 2; final int centerY = location[1] + getHeight() / 2; return mAttachInfo.mSession.dropForAccessibility(mAttachInfo.mWindow, centerX, centerY); } } catch (RemoteException e) { Log.e(VIEW_LOG_TAG, "Unable to drop for accessibility", e); } return false; } case R.id.accessibilityActionDragCancel: { if (!startedSystemDragForAccessibility()) { return false; } if (mAttachInfo != null && mAttachInfo.mDragToken != null) { cancelDragAndDrop(); return true; } return false; } } return false; } private boolean canAcceptAccessibilityDrop() { if (!canAcceptDrag()) { return false; } ListenerInfo li = mListenerInfo; return (li != null) && (li.mOnDragListener != null || li.mOnReceiveContentListener != null); } private boolean traverseAtGranularity(int granularity, boolean forward, boolean extendSelection) { CharSequence text = getIterableTextForAccessibility(); if (text == null || text.length() == 0) { return false; } TextSegmentIterator iterator = getIteratorForGranularity(granularity); if (iterator == null) { return false; } int current = getAccessibilitySelectionEnd(); if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { current = forward ? 0 : text.length(); } final int[] range = forward ? iterator.following(current) : iterator.preceding(current); if (range == null) { return false; } final int segmentStart = range[0]; final int segmentEnd = range[1]; int selectionStart; int selectionEnd; if (extendSelection && isAccessibilitySelectionExtendable()) { prepareForExtendedAccessibilitySelection(); selectionStart = getAccessibilitySelectionStart(); if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { selectionStart = forward ? segmentStart : segmentEnd; } selectionEnd = forward ? segmentEnd : segmentStart; } else { selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; } setAccessibilitySelection(selectionStart, selectionEnd); final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); return true; } @UnsupportedAppUsage public CharSequence getIterableTextForAccessibility() { return getContentDescription(); } public boolean isAccessibilitySelectionExtendable() { return false; } public void prepareForExtendedAccessibilitySelection() { return; } public int getAccessibilitySelectionStart() { return mAccessibilityCursorPosition; } public int getAccessibilitySelectionEnd() { return getAccessibilitySelectionStart(); } public void setAccessibilitySelection(int start, int end) { if (start == end && end == mAccessibilityCursorPosition) { return; } if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { mAccessibilityCursorPosition = start; } else { mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; } sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); } private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, int fromIndex, int toIndex) { if (mParent == null) { return; } AccessibilityEvent event = AccessibilityEvent.obtain( AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); onInitializeAccessibilityEvent(event); onPopulateAccessibilityEvent(event); event.setFromIndex(fromIndex); event.setToIndex(toIndex); event.setAction(action); event.setMovementGranularity(granularity); mParent.requestSendAccessibilityEvent(this, event); } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public TextSegmentIterator getIteratorForGranularity(int granularity) { switch (granularity) { case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { CharSequence text = getIterableTextForAccessibility(); if (text != null && text.length() > 0) { CharacterTextSegmentIterator iterator = CharacterTextSegmentIterator.getInstance( mContext.getResources().getConfiguration().locale); iterator.initialize(text.toString()); return iterator; } } break; case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { CharSequence text = getIterableTextForAccessibility(); if (text != null && text.length() > 0) { WordTextSegmentIterator iterator = WordTextSegmentIterator.getInstance( mContext.getResources().getConfiguration().locale); iterator.initialize(text.toString()); return iterator; } } break; case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { CharSequence text = getIterableTextForAccessibility(); if (text != null && text.length() > 0) { ParagraphTextSegmentIterator iterator = ParagraphTextSegmentIterator.getInstance(); iterator.initialize(text.toString()); return iterator; } } break; } return null; } public final boolean isTemporarilyDetached() { return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; } @CallSuper public void dispatchStartTemporaryDetach() { mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; notifyEnterOrExitForAutoFillIfNeeded(false); notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); onStartTemporaryDetach(); } public void onStartTemporaryDetach() { removeUnsetPressCallback(); mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; } @CallSuper public void dispatchFinishTemporaryDetach() { mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; onFinishTemporaryDetach(); if (hasWindowFocus() && hasFocus()) { } notifyEnterOrExitForAutoFillIfNeeded(true); notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); } public void onFinishTemporaryDetach() { } public KeyEvent.DispatcherState getKeyDispatcherState() { return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; } public boolean dispatchKeyEventPreIme(KeyEvent event) { return onKeyPreIme(event.getKeyCode(), event); } public boolean dispatchKeyEvent(KeyEvent event) { if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onKeyEvent(event, 0); } ListenerInfo li = mListenerInfo; if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { return true; } if (event.dispatch(this, mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null, this)) { return true; } if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); } return false; } public boolean dispatchKeyShortcutEvent(KeyEvent event) { return onKeyShortcut(event.getKeyCode(), event); } public boolean dispatchTouchEvent(MotionEvent event) { if (event.isTargetAccessibilityFocus()) { if (!isAccessibilityFocusedViewOrHost()) { return false; } event.setTargetAccessibilityFocus(false); } boolean result = false; if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onTouchEvent(event, 0); } final int actionMasked = event.getActionMasked(); if (actionMasked == MotionEvent.ACTION_DOWN) { stopNestedScroll(); } if (onFilterTouchEventForSecurity(event)) { result = performOnTouchCallback(event); } if (!result && mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); } if (actionMasked == MotionEvent.ACTION_UP || actionMasked == MotionEvent.ACTION_CANCEL || (actionMasked == MotionEvent.ACTION_DOWN && !result)) { stopNestedScroll(); } return result; } private boolean performOnTouchCallback(MotionEvent event) { boolean handled = false; if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { handled = true; } ListenerInfo li = mListenerInfo; if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED) { try { Trace.traceBegin(TRACE_TAG_VIEW, "View.onTouchListener#onTouch"); handled = li.mOnTouchListener.onTouch(this, event); } finally { Trace.traceEnd(TRACE_TAG_VIEW); } } if (handled) { return true; } try { Trace.traceBegin(TRACE_TAG_VIEW, "View#onTouchEvent"); return onTouchEvent(event); } finally { Trace.traceEnd(TRACE_TAG_VIEW); } } boolean isAccessibilityFocusedViewOrHost() { return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() .getAccessibilityFocusedHost() == this); } protected boolean canReceivePointerEvents() { return (mViewFlags & VISIBILITY_MASK) == VISIBLE || getAnimation() != null; } public boolean onFilterTouchEventForSecurity(MotionEvent event) { if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { return false; } return true; } public boolean dispatchTrackballEvent(MotionEvent event) { if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onTrackballEvent(event, 0); } return onTrackballEvent(event); } public boolean dispatchCapturedPointerEvent(MotionEvent event) { if (!hasPointerCapture()) { return false; } ListenerInfo li = mListenerInfo; if (li != null && li.mOnCapturedPointerListener != null && li.mOnCapturedPointerListener.onCapturedPointer(this, event)) { return true; } return onCapturedPointerEvent(event); } public boolean dispatchGenericMotionEvent(MotionEvent event) { if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); } final int source = event.getSource(); if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { final int action = event.getAction(); if (action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE || action == MotionEvent.ACTION_HOVER_EXIT) { if (dispatchHoverEvent(event)) { return true; } } else if (dispatchGenericPointerEvent(event)) { return true; } } else if (dispatchGenericFocusedEvent(event)) { return true; } if (dispatchGenericMotionEventInternal(event)) { return true; } if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); } return false; } private boolean dispatchGenericMotionEventInternal(MotionEvent event) { final boolean isRotaryEncoderEvent = event.isFromSource(InputDevice.SOURCE_ROTARY_ENCODER); if (isRotaryEncoderEvent) { if ((mPrivateFlags4 & PFLAG4_ROTARY_HAPTICS_DETERMINED) == 0) { if (ViewConfiguration.get(mContext) .isViewBasedRotaryEncoderHapticScrollFeedbackEnabled()) { mPrivateFlags4 |= PFLAG4_ROTARY_HAPTICS_ENABLED; } mPrivateFlags4 |= PFLAG4_ROTARY_HAPTICS_DETERMINED; } } final boolean processForRotaryScrollHaptics = isRotaryEncoderEvent && ((mPrivateFlags4 & PFLAG4_ROTARY_HAPTICS_ENABLED) != 0); if (processForRotaryScrollHaptics) { mPrivateFlags4 &= ~PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT; mPrivateFlags4 |= PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT; } ListenerInfo li = mListenerInfo; if (li != null && li.mOnGenericMotionListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnGenericMotionListener.onGenericMotion(this, event)) { return true; } final boolean onGenericMotionEventResult = onGenericMotionEvent(event); if (processForRotaryScrollHaptics) { if ((mPrivateFlags4 & PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT) != 0) { doRotaryProgressForScrollHaptics(event); } else { doRotaryLimitForScrollHaptics(event); } } if (onGenericMotionEventResult) { return true; } final int actionButton = event.getActionButton(); switch (event.getActionMasked()) { case MotionEvent.ACTION_BUTTON_PRESS: if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY || actionButton == MotionEvent.BUTTON_SECONDARY)) { if (performContextClick(event.getX(), event.getY())) { mInContextButtonPress = true; setPressed(true, event.getX(), event.getY()); removeTapCallback(); removeLongPressCallback(); return true; } } break; case MotionEvent.ACTION_BUTTON_RELEASE: if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY || actionButton == MotionEvent.BUTTON_SECONDARY)) { mInContextButtonPress = false; mIgnoreNextUpEvent = true; } break; } if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); } return false; } protected boolean dispatchHoverEvent(MotionEvent event) { ListenerInfo li = mListenerInfo; if (li != null && li.mOnHoverListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnHoverListener.onHover(this, event)) { return true; } return onHoverEvent(event); } protected boolean hasHoveredChild() { return false; } protected boolean pointInHoveredChild(MotionEvent event) { return false; } protected boolean dispatchGenericPointerEvent(MotionEvent event) { return false; } protected boolean dispatchGenericFocusedEvent(MotionEvent event) { return false; } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public final boolean dispatchPointerEvent(MotionEvent event) { if (event.isTouchEvent()) { return dispatchTouchEvent(event); } else { return dispatchGenericMotionEvent(event); } } public void dispatchWindowFocusChanged(boolean hasFocus) { onWindowFocusChanged(hasFocus); } public void onWindowFocusChanged(boolean hasWindowFocus) { if (!hasWindowFocus) { if (isPressed()) { setPressed(false); } mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { } removeLongPressCallback(); removeTapCallback(); onFocusLost(); } else if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { ViewRootImpl viewRoot = getViewRootImpl(); if (viewRoot != null && initiationWithoutInputConnection() && onCheckIsTextEditor()) { viewRoot.getHandwritingInitiator().onEditorFocused(this); } } refreshDrawableState(); } public boolean hasWindowFocus() { return mAttachInfo != null && mAttachInfo.mHasWindowFocus; } public boolean hasImeFocus() { return getViewRootImpl() != null && getViewRootImpl().getImeFocusController().hasImeFocus(); } protected void dispatchVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { onVisibilityChanged(changedView, visibility); } protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { } public void dispatchDisplayHint(@Visibility int hint) { onDisplayHint(hint); } protected void onDisplayHint(@Visibility int hint) { } public void dispatchWindowVisibilityChanged(@Visibility int visibility) { onWindowVisibilityChanged(visibility); } protected void onWindowVisibilityChanged(@Visibility int visibility) { if (visibility == VISIBLE) { initialAwakenScrollBars(); } } public boolean isAggregatedVisible() { return (mPrivateFlags3 & PFLAG3_AGGREGATED_VISIBLE) != 0; } boolean dispatchVisibilityAggregated(boolean isVisible) { final boolean thisVisible = getVisibility() == VISIBLE; if (thisVisible || !isVisible) { onVisibilityAggregated(isVisible); } return thisVisible && isVisible; } @CallSuper public void onVisibilityAggregated(boolean isVisible) { boolean oldVisible = isAggregatedVisible(); mPrivateFlags3 = isVisible ? (mPrivateFlags3 | PFLAG3_AGGREGATED_VISIBLE) : (mPrivateFlags3 & ~PFLAG3_AGGREGATED_VISIBLE); if (isVisible && mAttachInfo != null) { initialAwakenScrollBars(); } final Drawable dr = mBackground; if (dr != null && isVisible != dr.isVisible()) { dr.setVisible(isVisible, false); } final Drawable hl = mDefaultFocusHighlight; if (hl != null && isVisible != hl.isVisible()) { hl.setVisible(isVisible, false); } final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; if (fg != null && isVisible != fg.isVisible()) { fg.setVisible(isVisible, false); } notifyAutofillManagerViewVisibilityChanged(isVisible); if (isVisible != oldVisible) { if (isAccessibilityPane()) { notifyViewAccessibilityStateChangedIfNeeded(isVisible ? AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED : AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); } notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible); updateSensitiveViewsCountIfNeeded(isVisible); if (!getSystemGestureExclusionRects().isEmpty()) { postUpdate(this::updateSystemGestureExclusionRects); } if (!collectPreferKeepClearRects().isEmpty()) { postUpdate(this::updateKeepClearRects); } } } private void notifyAutofillManagerViewVisibilityChanged(boolean isVisible) { if (isAutofillable()) { AutofillManager afm = getAutofillManager(); if (afm != null && getAutofillViewId() > LAST_APP_AUTOFILL_ID) { if (mVisibilityChangeForAutofillHandler != null) { mVisibilityChangeForAutofillHandler.removeMessages(0); } if (isVisible) { afm.notifyViewVisibilityChanged(this, true); } else { if (mVisibilityChangeForAutofillHandler == null) { mVisibilityChangeForAutofillHandler = new VisibilityChangeForAutofillHandler(afm, this); } mVisibilityChangeForAutofillHandler.obtainMessage(0, this).sendToTarget(); } } } } @Visibility public int getWindowVisibility() { return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; } public void getWindowVisibleDisplayFrame(Rect outRect) { if (mAttachInfo != null) { mAttachInfo.mViewRootImpl.getWindowVisibleDisplayFrame(outRect); return; } final WindowManager windowManager = mContext.getSystemService(WindowManager.class); final WindowMetrics metrics = windowManager.getMaximumWindowMetrics(); final Insets insets = metrics.getWindowInsets().getInsets( WindowInsets.Type.navigationBars() | WindowInsets.Type.displayCutout()); outRect.set(metrics.getBounds()); outRect.inset(insets); outRect.offsetTo(0, 0); } @UnsupportedAppUsage @TestApi public void getWindowDisplayFrame(@NonNull Rect outRect) { if (mAttachInfo != null) { mAttachInfo.mViewRootImpl.getDisplayFrame(outRect); return; } Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); d.getRectSize(outRect); } public void dispatchConfigurationChanged(Configuration newConfig) { onConfigurationChanged(newConfig); } protected void onConfigurationChanged(Configuration newConfig) { } void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { performCollectViewAttributes(attachInfo, visibility); } void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { if ((visibility & VISIBILITY_MASK) == VISIBLE) { if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { attachInfo.mKeepScreenOn = true; } attachInfo.mSystemUiVisibility |= mSystemUiVisibility; ListenerInfo li = mListenerInfo; if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { attachInfo.mHasSystemUiListeners = true; } } } void needGlobalAttributesUpdate(boolean force) { final AttachInfo ai = mAttachInfo; if (ai != null && !ai.mRecomputeGlobalAttributes) { if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) || ai.mHasSystemUiListeners) { ai.mRecomputeGlobalAttributes = true; } } } @ViewDebug.ExportedProperty public boolean isInTouchMode() { if (mAttachInfo != null) { return mAttachInfo.mInTouchMode; } return mResources.getBoolean(com.android.internal.R.bool.config_defaultInTouchMode); } @ViewDebug.CapturedViewProperty @UiContext public final Context getContext() { return mContext; } public boolean onKeyPreIme(int keyCode, KeyEvent event) { return false; } public boolean onKeyDown(int keyCode, KeyEvent event) { if (KeyEvent.isConfirmKey(keyCode) && event.hasNoModifiers()) { if ((mViewFlags & ENABLED_MASK) == DISABLED) { return true; } if (event.getRepeatCount() == 0) { final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { final float x = getWidth() / 2f; final float y = getHeight() / 2f; if (clickable) { setPressed(true, x, y); } checkForLongClick( ViewConfiguration.getLongPressTimeout(), x, y, TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION); return true; } } } return false; } public boolean onKeyLongPress(int keyCode, KeyEvent event) { return false; } public boolean onKeyUp(int keyCode, KeyEvent event) { if (KeyEvent.isConfirmKey(keyCode) && event.hasNoModifiers()) { if ((mViewFlags & ENABLED_MASK) == DISABLED) { return true; } if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { setPressed(false); if (!mHasPerformedLongPress) { removeLongPressCallback(); if (!event.isCanceled()) { return performClickInternal(); } } } } return false; } public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { return false; } public boolean onKeyShortcut(int keyCode, KeyEvent event) { return false; } public boolean onCheckIsTextEditor() { return false; } public InputConnection onCreateInputConnection(EditorInfo outAttrs) { return null; } public void onInputConnectionOpenedInternal(@NonNull InputConnection inputConnection, @NonNull EditorInfo editorInfo, @Nullable Handler handler) {} public void onInputConnectionClosedInternal() {} public boolean checkInputConnectionProxy(View view) { return false; } public void createContextMenu(ContextMenu menu) { ContextMenuInfo menuInfo = getContextMenuInfo(); ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); onCreateContextMenu(menu); ListenerInfo li = mListenerInfo; if (li != null && li.mOnCreateContextMenuListener != null) { li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); } ((MenuBuilder)menu).setCurrentMenuInfo(null); if (mParent != null) { mParent.createContextMenu(menu); } } protected ContextMenuInfo getContextMenuInfo() { return null; } protected void onCreateContextMenu(ContextMenu menu) { } public boolean onTrackballEvent(MotionEvent event) { return false; } public boolean onGenericMotionEvent(MotionEvent event) { return false; } private boolean dispatchTouchExplorationHoverEvent(MotionEvent event) { final AccessibilityManager manager = AccessibilityManager.getInstance(mContext); if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { return false; } final boolean oldHoveringTouchDelegate = mHoveringTouchDelegate; final int action = event.getActionMasked(); boolean pointInDelegateRegion = false; boolean handled = false; final AccessibilityNodeInfo.TouchDelegateInfo info = mTouchDelegate.getTouchDelegateInfo(); for (int i = 0; i < info.getRegionCount(); i++) { Region r = info.getRegionAt(i); if (r.contains((int) event.getX(), (int) event.getY())) { pointInDelegateRegion = true; } } if (!oldHoveringTouchDelegate) { if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) && !pointInHoveredChild(event) && pointInDelegateRegion) { mHoveringTouchDelegate = true; } } else { if (action == MotionEvent.ACTION_HOVER_EXIT || (action == MotionEvent.ACTION_HOVER_MOVE && (pointInHoveredChild(event) || !pointInDelegateRegion))) { mHoveringTouchDelegate = false; } } switch (action) { case MotionEvent.ACTION_HOVER_MOVE: if (oldHoveringTouchDelegate && mHoveringTouchDelegate) { handled = mTouchDelegate.onTouchExplorationHoverEvent(event); } else if (!oldHoveringTouchDelegate && mHoveringTouchDelegate) { MotionEvent eventNoHistory = (event.getHistorySize() == 0) ? event : MotionEvent.obtainNoHistory(event); eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER); handled = mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); eventNoHistory.setAction(action); handled |= mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); } else if (oldHoveringTouchDelegate && !mHoveringTouchDelegate) { final boolean hoverExitPending = event.isHoverExitPending(); event.setHoverExitPending(true); mTouchDelegate.onTouchExplorationHoverEvent(event); MotionEvent eventNoHistory = (event.getHistorySize() == 0) ? event : MotionEvent.obtainNoHistory(event); eventNoHistory.setHoverExitPending(hoverExitPending); eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT); mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); } break; case MotionEvent.ACTION_HOVER_ENTER: if (!oldHoveringTouchDelegate && mHoveringTouchDelegate) { handled = mTouchDelegate.onTouchExplorationHoverEvent(event); } break; case MotionEvent.ACTION_HOVER_EXIT: if (oldHoveringTouchDelegate) { mTouchDelegate.onTouchExplorationHoverEvent(event); } break; } return handled; } public boolean onHoverEvent(MotionEvent event) { if (mTouchDelegate != null && dispatchTouchExplorationHoverEvent(event)) { return true; } final int action = event.getActionMasked(); if (!mSendingHoverAccessibilityEvents) { if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) && !hasHoveredChild() && pointInView(event.getX(), event.getY())) { sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); mSendingHoverAccessibilityEvents = true; } } else { if (action == MotionEvent.ACTION_HOVER_EXIT || (action == MotionEvent.ACTION_HOVER_MOVE && !pointInView(event.getX(), event.getY()))) { mSendingHoverAccessibilityEvents = false; sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); } } if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) && event.isFromSource(InputDevice.SOURCE_MOUSE) && isOnScrollbar(event.getX(), event.getY())) { awakenScrollBars(); } if (isHoverable() || isHovered()) { switch (action) { case MotionEvent.ACTION_HOVER_ENTER: setHovered(true); break; case MotionEvent.ACTION_HOVER_EXIT: setHovered(false); break; } dispatchGenericMotionEventInternal(event); return true; } return false; } private boolean isHoverable() { final int viewFlags = mViewFlags; if ((viewFlags & ENABLED_MASK) == DISABLED) { return false; } return (viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; } @ViewDebug.ExportedProperty public boolean isHovered() { return (mPrivateFlags & PFLAG_HOVERED) != 0; } public void setHovered(boolean hovered) { if (hovered) { if ((mPrivateFlags & PFLAG_HOVERED) == 0) { mPrivateFlags |= PFLAG_HOVERED; refreshDrawableState(); onHoverChanged(true); } } else { if ((mPrivateFlags & PFLAG_HOVERED) != 0) { mPrivateFlags &= ~PFLAG_HOVERED; refreshDrawableState(); onHoverChanged(false); } } } public void onHoverChanged(boolean hovered) { } protected boolean handleScrollBarDragging(MotionEvent event) { if (mScrollCache == null) { return false; } final float x = event.getX(); final float y = event.getY(); final int action = event.getAction(); if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING && action != MotionEvent.ACTION_DOWN) || !event.isFromSource(InputDevice.SOURCE_MOUSE) || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; return false; } switch (action) { case MotionEvent.ACTION_MOVE: if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { return false; } if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { final Rect bounds = mScrollCache.mScrollBarBounds; getVerticalScrollBarBounds(bounds, null); final int range = computeVerticalScrollRange(); final int offset = computeVerticalScrollOffset(); final int extent = computeVerticalScrollExtent(); final int thumbLength = ScrollBarUtils.getThumbLength( bounds.height(), bounds.width(), extent, range); final int thumbOffset = ScrollBarUtils.getThumbOffset( bounds.height(), thumbLength, extent, range, offset); final float diff = y - mScrollCache.mScrollBarDraggingPos; final float maxThumbOffset = bounds.height() - thumbLength; final float newThumbOffset = Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); final int height = getHeight(); if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 && height > 0 && extent > 0) { final int newY = Math.round((range - extent) if (newY != getScrollY()) { mScrollCache.mScrollBarDraggingPos = y; setScrollY(newY); } } return true; } if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { final Rect bounds = mScrollCache.mScrollBarBounds; getHorizontalScrollBarBounds(bounds, null); final int range = computeHorizontalScrollRange(); final int offset = computeHorizontalScrollOffset(); final int extent = computeHorizontalScrollExtent(); final int thumbLength = ScrollBarUtils.getThumbLength( bounds.width(), bounds.height(), extent, range); final int thumbOffset = ScrollBarUtils.getThumbOffset( bounds.width(), thumbLength, extent, range, offset); final float diff = x - mScrollCache.mScrollBarDraggingPos; final float maxThumbOffset = bounds.width() - thumbLength; final float newThumbOffset = Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); final int width = getWidth(); if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 && width > 0 && extent > 0) { final int newX = Math.round((range - extent) if (newX != getScrollX()) { mScrollCache.mScrollBarDraggingPos = x; setScrollX(newX); } } return true; } case MotionEvent.ACTION_DOWN: if (mScrollCache.state == ScrollabilityCache.OFF) { return false; } if (isOnVerticalScrollbarThumb(x, y)) { mScrollCache.mScrollBarDraggingState = ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; mScrollCache.mScrollBarDraggingPos = y; return true; } if (isOnHorizontalScrollbarThumb(x, y)) { mScrollCache.mScrollBarDraggingState = ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; mScrollCache.mScrollBarDraggingPos = x; return true; } } mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; return false; } public boolean onTouchEvent(MotionEvent event) { final float x = event.getX(); final float y = event.getY(); final int viewFlags = mViewFlags; final int action = event.getAction(); final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; if ((viewFlags & ENABLED_MASK) == DISABLED && (mPrivateFlags4 & PFLAG4_ALLOW_CLICK_WHEN_DISABLED) == 0) { if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { setPressed(false); } mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; return clickable; } if (mTouchDelegate != null) { if (mTouchDelegate.onTouchEvent(event)) { return true; } } if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { switch (action) { case MotionEvent.ACTION_UP: mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; if ((viewFlags & TOOLTIP) == TOOLTIP) { handleTooltipUp(); } if (!clickable) { removeTapCallback(); removeLongPressCallback(); mInContextButtonPress = false; mHasPerformedLongPress = false; mIgnoreNextUpEvent = false; break; } boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { boolean focusTaken = false; if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { focusTaken = requestFocus(); } if (prepressed) { setPressed(true, x, y); } if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { removeLongPressCallback(); if (!focusTaken) { if (mPerformClick == null) { mPerformClick = new PerformClick(); } if (!post(mPerformClick)) { performClickInternal(); } } } if (mUnsetPressedState == null) { mUnsetPressedState = new UnsetPressedState(); } if (prepressed) { postDelayed(mUnsetPressedState, ViewConfiguration.getPressedStateDuration()); } else if (!post(mUnsetPressedState)) { mUnsetPressedState.run(); } removeTapCallback(); } mIgnoreNextUpEvent = false; break; case MotionEvent.ACTION_DOWN: if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { mPrivateFlags3 |= PFLAG3_FINGER_DOWN; } mHasPerformedLongPress = false; if (!clickable) { checkForLongClick( ViewConfiguration.getLongPressTimeout(), x, y, TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); break; } if (performButtonActionOnTouchDown(event)) { break; } boolean isInScrollingContainer = isInScrollingContainer(); if (isInScrollingContainer) { mPrivateFlags |= PFLAG_PREPRESSED; if (mPendingCheckForTap == null) { mPendingCheckForTap = new CheckForTap(); } mPendingCheckForTap.x = event.getX(); mPendingCheckForTap.y = event.getY(); postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); } else { setPressed(true, x, y); checkForLongClick( ViewConfiguration.getLongPressTimeout(), x, y, TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); } break; case MotionEvent.ACTION_CANCEL: if (clickable) { setPressed(false); } removeTapCallback(); removeLongPressCallback(); mInContextButtonPress = false; mHasPerformedLongPress = false; mIgnoreNextUpEvent = false; mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; break; case MotionEvent.ACTION_MOVE: if (clickable) { drawableHotspotChanged(x, y); } final int motionClassification = event.getClassification(); final boolean ambiguousGesture = motionClassification == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE; int touchSlop = mTouchSlop; if (ambiguousGesture && hasPendingLongPressCallback()) { if (!pointInView(x, y, touchSlop)) { removeLongPressCallback(); long delay = (long) (ViewConfiguration.getLongPressTimeout() delay -= event.getEventTime() - event.getDownTime(); checkForLongClick( delay, x, y, TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); } } if (!pointInView(x, y, touchSlop)) { removeTapCallback(); removeLongPressCallback(); if ((mPrivateFlags & PFLAG_PRESSED) != 0) { setPressed(false); } mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; } final boolean deepPress = motionClassification == MotionEvent.CLASSIFICATION_DEEP_PRESS; if (deepPress && hasPendingLongPressCallback()) { removeLongPressCallback(); checkForLongClick( x, y, TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS); } break; } return true; } return false; } private boolean hasExpensiveMeasuresDuringInputEvent() { final AttachInfo attachInfo = mAttachInfo; if (attachInfo == null || attachInfo.mRootView == null) { return false; } if (!attachInfo.mHandlingPointerEvent) { return false; } final ViewFrameInfo info = attachInfo.mViewRootImpl.mViewFrameInfo; final long durationFromVsyncTimeMs = (System.nanoTime() - Choreographer.getInstance().getLastFrameTimeNanos()) / TimeUtils.NANOS_PER_MS; return durationFromVsyncTimeMs > 3L || info.getAndIncreaseViewMeasuredCount() > 10; } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean isInScrollingContainer() { ViewParent p = getParent(); while (p != null && p instanceof ViewGroup) { if (((ViewGroup) p).shouldDelayChildPressedState()) { return true; } p = p.getParent(); } return false; } private void removeLongPressCallback() { if (mPendingCheckForLongPress != null) { removeCallbacks(mPendingCheckForLongPress); } } private boolean hasPendingLongPressCallback() { if (mPendingCheckForLongPress == null) { return false; } final AttachInfo attachInfo = mAttachInfo; if (attachInfo == null) { return false; } return attachInfo.mHandler.hasCallbacks(mPendingCheckForLongPress); } @UnsupportedAppUsage private void removePerformClickCallback() { if (mPerformClick != null) { removeCallbacks(mPerformClick); } } private void removeUnsetPressCallback() { if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { setPressed(false); removeCallbacks(mUnsetPressedState); } } private void removeTapCallback() { if (mPendingCheckForTap != null) { mPrivateFlags &= ~PFLAG_PREPRESSED; removeCallbacks(mPendingCheckForTap); } } public void cancelLongPress() { removeLongPressCallback(); removeTapCallback(); } public void setTouchDelegate(TouchDelegate delegate) { mTouchDelegate = delegate; } public TouchDelegate getTouchDelegate() { return mTouchDelegate; } public final void requestUnbufferedDispatch(MotionEvent event) { final int action = event.getAction(); if (mAttachInfo == null || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE || !event.isTouchEvent()) { return; } mAttachInfo.mUnbufferedDispatchRequested = true; } public final void requestUnbufferedDispatch(@InputSourceClass int source) { if (mUnbufferedInputSource == source) { return; } mUnbufferedInputSource = source; if (mParent != null) { mParent.onDescendantUnbufferedRequested(); } } private boolean hasSize() { return (mBottom > mTop) && (mRight > mLeft); } private boolean canTakeFocus() { return ((mViewFlags & VISIBILITY_MASK) == VISIBLE) && ((mViewFlags & FOCUSABLE) == FOCUSABLE) && ((mViewFlags & ENABLED_MASK) == ENABLED) && (sCanFocusZeroSized || !isLayoutValid() || hasSize()); } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) void setFlags(int flags, int mask) { final boolean accessibilityEnabled = AccessibilityManager.getInstance(mContext).isEnabled(); final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility(false); int old = mViewFlags; mViewFlags = (mViewFlags & ~mask) | (flags & mask); int changed = mViewFlags ^ old; if (changed == 0) { return; } int privateFlags = mPrivateFlags; boolean shouldNotifyFocusableAvailable = false; int focusableChangedByAuto = 0; if (((mViewFlags & FOCUSABLE_AUTO) != 0) && (changed & (FOCUSABLE_MASK | CLICKABLE)) != 0) { final int newFocus; if ((mViewFlags & CLICKABLE) != 0) { newFocus = FOCUSABLE; } else { newFocus = NOT_FOCUSABLE; } mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); changed = (changed & ~FOCUSABLE) | focusableChangedByAuto; } if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) { if (((old & FOCUSABLE) == FOCUSABLE) && ((privateFlags & PFLAG_FOCUSED) != 0)) { clearFocus(); if (mParent instanceof ViewGroup) { ((ViewGroup) mParent).clearFocusedInCluster(); } } else if (((old & FOCUSABLE) == NOT_FOCUSABLE) && ((privateFlags & PFLAG_FOCUSED) == 0)) { if (mParent != null) { ViewRootImpl viewRootImpl = getViewRootImpl(); if (!sAutoFocusableOffUIThreadWontNotifyParents || focusableChangedByAuto == 0 || viewRootImpl == null || viewRootImpl.mThread == Thread.currentThread()) { shouldNotifyFocusableAvailable = canTakeFocus(); } } } } final int newVisibility = flags & VISIBILITY_MASK; if (newVisibility == VISIBLE) { if ((changed & VISIBILITY_MASK) != 0) { mPrivateFlags |= PFLAG_DRAWN; invalidate(true); needGlobalAttributesUpdate(true); shouldNotifyFocusableAvailable = hasSize(); } } if ((changed & ENABLED_MASK) != 0) { if ((mViewFlags & ENABLED_MASK) == ENABLED) { shouldNotifyFocusableAvailable = canTakeFocus(); } else { if (isFocused()) clearFocus(); } } if (shouldNotifyFocusableAvailable && mParent != null) { mParent.focusableViewAvailable(this); } if ((changed & GONE) != 0) { needGlobalAttributesUpdate(false); requestLayout(); if (((mViewFlags & VISIBILITY_MASK) == GONE)) { if (hasFocus()) { clearFocus(); if (mParent instanceof ViewGroup) { ((ViewGroup) mParent).clearFocusedInCluster(); } } clearAccessibilityFocus(); destroyDrawingCache(); if (mParent instanceof View) { ((View) mParent).invalidate(true); } mPrivateFlags |= PFLAG_DRAWN; } if (mAttachInfo != null) { mAttachInfo.mViewVisibilityChanged = true; } } if ((changed & INVISIBLE) != 0) { needGlobalAttributesUpdate(false); mPrivateFlags |= PFLAG_DRAWN; if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { if (getRootView() != this) { if (hasFocus()) { clearFocus(); if (mParent instanceof ViewGroup) { ((ViewGroup) mParent).clearFocusedInCluster(); } } clearAccessibilityFocus(); } } if (mAttachInfo != null) { mAttachInfo.mViewVisibilityChanged = true; } } if ((changed & VISIBILITY_MASK) != 0) { if (newVisibility != VISIBLE && mAttachInfo != null) { cleanupDraw(); } if (mParent instanceof ViewGroup) { ViewGroup parent = (ViewGroup) mParent; parent.onChildVisibilityChanged(this, (changed & VISIBILITY_MASK), newVisibility); parent.invalidate(true); } else if (mParent != null) { mParent.invalidateChild(this, null); } if (mAttachInfo != null) { dispatchVisibilityChanged(this, newVisibility); if (mParent != null && getWindowVisibility() == VISIBLE && ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { dispatchVisibilityAggregated(newVisibility == VISIBLE); } if ((old & VISIBILITY_MASK) == VISIBLE) { notifySubtreeAccessibilityStateChangedByParentIfNeeded(); } else { notifySubtreeAccessibilityStateChangedIfNeeded(); } } } if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { destroyDrawingCache(); } if ((changed & DRAWING_CACHE_ENABLED) != 0) { destroyDrawingCache(); mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; invalidateParentCaches(); } if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { destroyDrawingCache(); mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; } if ((changed & DRAW_MASK) != 0) { if ((mViewFlags & WILL_NOT_DRAW) != 0) { if (mBackground != null || mDefaultFocusHighlight != null || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { mPrivateFlags &= ~PFLAG_SKIP_DRAW; } else { mPrivateFlags |= PFLAG_SKIP_DRAW; } } else { mPrivateFlags &= ~PFLAG_SKIP_DRAW; } requestLayout(); invalidate(true); } if ((changed & KEEP_SCREEN_ON) != 0) { if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { mParent.recomputeViewAttributes(this); } } if (accessibilityEnabled) { if (isAccessibilityPane()) { changed &= ~VISIBILITY_MASK; } if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 || (changed & CONTEXT_CLICKABLE) != 0) { if (oldIncludeForAccessibility != includeForAccessibility(false)) { notifySubtreeAccessibilityStateChangedIfNeeded(); } else { notifyViewAccessibilityStateChangedIfNeeded( AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } } else if ((changed & ENABLED_MASK) != 0) { notifyViewAccessibilityStateChangedIfNeeded( AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } } } public void bringToFront() { if (mParent != null) { mParent.bringChildToFront(this); } } private HapticScrollFeedbackProvider getScrollFeedbackProvider() { if (mScrollFeedbackProvider == null) { mScrollFeedbackProvider = new HapticScrollFeedbackProvider(this, } return mScrollFeedbackProvider; } private void doRotaryProgressForScrollHaptics(MotionEvent rotaryEvent) { final float axisScrollValue = rotaryEvent.getAxisValue(MotionEvent.AXIS_SCROLL); final float verticalScrollFactor = ViewConfiguration.get(mContext).getScaledVerticalScrollFactor(); getScrollFeedbackProvider().onScrollProgress( rotaryEvent.getDeviceId(), InputDevice.SOURCE_ROTARY_ENCODER, MotionEvent.AXIS_SCROLL, scrollAmount); } private void doRotaryLimitForScrollHaptics(MotionEvent rotaryEvent) { final boolean isStart = rotaryEvent.getAxisValue(MotionEvent.AXIS_SCROLL) > 0; getScrollFeedbackProvider().onScrollLimit( rotaryEvent.getDeviceId(), InputDevice.SOURCE_ROTARY_ENCODER, MotionEvent.AXIS_SCROLL, isStart); } private void processScrollEventForRotaryEncoderHaptics() { if ((mPrivateFlags4 |= PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT) != 0) { mPrivateFlags4 |= PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT; mPrivateFlags4 &= ~PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT; } } protected void onScrollChanged(int l, int t, int oldl, int oldt) { notifySubtreeAccessibilityStateChangedIfNeeded(); postSendViewScrolledAccessibilityEventCallback(l - oldl, t - oldt); processScrollEventForRotaryEncoderHaptics(); mBackgroundSizeChanged = true; mDefaultFocusHighlightSizeChanged = true; if (mForegroundInfo != null) { mForegroundInfo.mBoundsChanged = true; } final AttachInfo ai = mAttachInfo; if (ai != null) { ai.mViewScrollChanged = true; } if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); } } public interface OnScrollChangeListener { void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); } public interface OnLayoutChangeListener { void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom); } protected void onSizeChanged(int w, int h, int oldw, int oldh) { } protected void dispatchDraw(@NonNull Canvas canvas) { } public final ViewParent getParent() { return mParent; } public void setScrollX(int value) { scrollTo(value, mScrollY); } public void setScrollY(int value) { scrollTo(mScrollX, value); } @InspectableProperty public final int getScrollX() { return mScrollX; } @InspectableProperty public final int getScrollY() { return mScrollY; } @ViewDebug.ExportedProperty(category = "layout") public final int getWidth() { return mRight - mLeft; } @ViewDebug.ExportedProperty(category = "layout") public final int getHeight() { return mBottom - mTop; } public void getDrawingRect(Rect outRect) { outRect.left = mScrollX; outRect.top = mScrollY; outRect.right = mScrollX + (mRight - mLeft); outRect.bottom = mScrollY + (mBottom - mTop); } public final int getMeasuredWidth() { return mMeasuredWidth & MEASURED_SIZE_MASK; } @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, name = "MEASURED_STATE_TOO_SMALL"), }) public final int getMeasuredWidthAndState() { return mMeasuredWidth; } public final int getMeasuredHeight() { return mMeasuredHeight & MEASURED_SIZE_MASK; } @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, name = "MEASURED_STATE_TOO_SMALL"), }) public final int getMeasuredHeightAndState() { return mMeasuredHeight; } public final int getMeasuredState() { return (mMeasuredWidth&MEASURED_STATE_MASK) | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); } public Matrix getMatrix() { ensureTransformationInfo(); final Matrix matrix = mTransformationInfo.mMatrix; mRenderNode.getMatrix(matrix); return matrix; } @UnsupportedAppUsage public final boolean hasIdentityMatrix() { return mRenderNode.hasIdentityMatrix(); } @UnsupportedAppUsage void ensureTransformationInfo() { if (mTransformationInfo == null) { mTransformationInfo = new TransformationInfo(); } } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public final Matrix getInverseMatrix() { ensureTransformationInfo(); if (mTransformationInfo.mInverseMatrix == null) { mTransformationInfo.mInverseMatrix = new Matrix(); } final Matrix matrix = mTransformationInfo.mInverseMatrix; mRenderNode.getInverseMatrix(matrix); return matrix; } public float getCameraDistance() { final float dpi = mResources.getDisplayMetrics().densityDpi; } public void setCameraDistance(float distance) { final float dpi = mResources.getDisplayMetrics().densityDpi; invalidateViewProperty(true, false); mRenderNode.setCameraDistance(Math.abs(distance) / dpi); invalidateViewProperty(false, false); invalidateParentIfNeededAndWasQuickRejected(); } @ViewDebug.ExportedProperty(category = "drawing") @InspectableProperty public float getRotation() { return mRenderNode.getRotationZ(); } @RemotableViewMethod public void setRotation(float rotation) { if (rotation != getRotation()) { invalidateViewProperty(true, false); mRenderNode.setRotationZ(rotation); invalidateViewProperty(false, true); invalidateParentIfNeededAndWasQuickRejected(); notifySubtreeAccessibilityStateChangedIfNeeded(); } } @ViewDebug.ExportedProperty(category = "drawing") @InspectableProperty public float getRotationY() { return mRenderNode.getRotationY(); } @RemotableViewMethod public void setRotationY(float rotationY) { if (rotationY != getRotationY()) { invalidateViewProperty(true, false); mRenderNode.setRotationY(rotationY); invalidateViewProperty(false, true); invalidateParentIfNeededAndWasQuickRejected(); notifySubtreeAccessibilityStateChangedIfNeeded(); } } @ViewDebug.ExportedProperty(category = "drawing") @InspectableProperty public float getRotationX() { return mRenderNode.getRotationX(); } @RemotableViewMethod public void setRotationX(float rotationX) { if (rotationX != getRotationX()) { invalidateViewProperty(true, false); mRenderNode.setRotationX(rotationX); invalidateViewProperty(false, true); invalidateParentIfNeededAndWasQuickRejected(); notifySubtreeAccessibilityStateChangedIfNeeded(); } } @ViewDebug.ExportedProperty(category = "drawing") @InspectableProperty public float getScaleX() { return mRenderNode.getScaleX(); } @RemotableViewMethod public void setScaleX(float scaleX) { if (scaleX != getScaleX()) { scaleX = sanitizeFloatPropertyValue(scaleX, "scaleX"); invalidateViewProperty(true, false); mRenderNode.setScaleX(scaleX); invalidateViewProperty(false, true); invalidateParentIfNeededAndWasQuickRejected(); notifySubtreeAccessibilityStateChangedIfNeeded(); } } @ViewDebug.ExportedProperty(category = "drawing") @InspectableProperty public float getScaleY() { return mRenderNode.getScaleY(); } @RemotableViewMethod public void setScaleY(float scaleY) { if (scaleY != getScaleY()) { scaleY = sanitizeFloatPropertyValue(scaleY, "scaleY"); invalidateViewProperty(true, false); mRenderNode.setScaleY(scaleY); invalidateViewProperty(false, true); invalidateParentIfNeededAndWasQuickRejected(); notifySubtreeAccessibilityStateChangedIfNeeded(); } } @ViewDebug.ExportedProperty(category = "drawing") @InspectableProperty(name = "transformPivotX") public float getPivotX() { return mRenderNode.getPivotX(); } @RemotableViewMethod public void setPivotX(float pivotX) { if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { invalidateViewProperty(true, false); mRenderNode.setPivotX(pivotX); invalidateViewProperty(false, true); invalidateParentIfNeededAndWasQuickRejected(); } } @ViewDebug.ExportedProperty(category = "drawing") @InspectableProperty(name = "transformPivotY") public float getPivotY() { return mRenderNode.getPivotY(); } @RemotableViewMethod public void setPivotY(float pivotY) { if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { invalidateViewProperty(true, false); mRenderNode.setPivotY(pivotY); invalidateViewProperty(false, true); invalidateParentIfNeededAndWasQuickRejected(); } } public boolean isPivotSet() { return mRenderNode.isPivotExplicitlySet(); } public void resetPivot() { if (mRenderNode.resetPivot()) { invalidateViewProperty(false, false); } } @ViewDebug.ExportedProperty(category = "drawing") @InspectableProperty public float getAlpha() { return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; } public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; if (hasOverlappingRendering) { mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; } else { mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; } } public final boolean getHasOverlappingRendering() { return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : hasOverlappingRendering(); } @ViewDebug.ExportedProperty(category = "drawing") public boolean hasOverlappingRendering() { return true; } @RemotableViewMethod public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { ensureTransformationInfo(); if (mTransformationInfo.mAlpha != alpha) { setAlphaInternal(alpha); mPrivateFlags |= PFLAG_ALPHA_SET; invalidateParentCaches(); invalidate(true); } else { mPrivateFlags &= ~PFLAG_ALPHA_SET; invalidateViewProperty(true, false); mRenderNode.setAlpha(getFinalAlpha()); } } } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768435) boolean setAlphaNoInvalidation(float alpha) { ensureTransformationInfo(); if (mTransformationInfo.mAlpha != alpha) { setAlphaInternal(alpha); if (subclassHandlesAlpha) { mPrivateFlags |= PFLAG_ALPHA_SET; return true; } else { mPrivateFlags &= ~PFLAG_ALPHA_SET; mRenderNode.setAlpha(getFinalAlpha()); } } return false; } void setAlphaInternal(float alpha) { float oldAlpha = mTransformationInfo.mAlpha; mTransformationInfo.mAlpha = alpha; if ((alpha == 0) ^ (oldAlpha == 0)) { notifySubtreeAccessibilityStateChangedIfNeeded(); } } public void setTransitionAlpha(float alpha) { ensureTransformationInfo(); if (mTransformationInfo.mTransitionAlpha != alpha) { mTransformationInfo.mTransitionAlpha = alpha; mPrivateFlags &= ~PFLAG_ALPHA_SET; invalidateViewProperty(true, false); mRenderNode.setAlpha(getFinalAlpha()); } } private float getFinalAlpha() { if (mTransformationInfo != null) { } return 1; } @ViewDebug.ExportedProperty(category = "drawing") public float getTransitionAlpha() { return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; } public void setForceDarkAllowed(boolean allow) { if (mRenderNode.setForceDarkAllowed(allow)) { invalidate(); } } @ViewDebug.ExportedProperty(category = "drawing") @InspectableProperty public boolean isForceDarkAllowed() { return mRenderNode.isForceDarkAllowed(); } @ViewDebug.CapturedViewProperty public final int getTop() { return mTop; } public final void setTop(int top) { if (top != mTop) { final boolean matrixIsIdentity = hasIdentityMatrix(); if (matrixIsIdentity) { if (mAttachInfo != null) { int minTop; int yLoc; if (top < mTop) { minTop = top; yLoc = top - mTop; } else { minTop = mTop; yLoc = 0; } invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); } } else { invalidate(true); } int width = mRight - mLeft; int oldHeight = mBottom - mTop; mTop = top; mRenderNode.setTop(mTop); sizeChange(width, mBottom - mTop, width, oldHeight); if (!matrixIsIdentity) { mPrivateFlags |= PFLAG_DRAWN; invalidate(true); } mBackgroundSizeChanged = true; mDefaultFocusHighlightSizeChanged = true; if (mForegroundInfo != null) { mForegroundInfo.mBoundsChanged = true; } invalidateParentIfNeeded(); } } @ViewDebug.CapturedViewProperty public final int getBottom() { return mBottom; } public boolean isDirty() { return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; } public final void setBottom(int bottom) { if (bottom != mBottom) { final boolean matrixIsIdentity = hasIdentityMatrix(); if (matrixIsIdentity) { if (mAttachInfo != null) { int maxBottom; if (bottom < mBottom) { maxBottom = mBottom; } else { maxBottom = bottom; } invalidate(0, 0, mRight - mLeft, maxBottom - mTop); } } else { invalidate(true); } int width = mRight - mLeft; int oldHeight = mBottom - mTop; mBottom = bottom; mRenderNode.setBottom(mBottom); sizeChange(width, mBottom - mTop, width, oldHeight); if (!matrixIsIdentity) { mPrivateFlags |= PFLAG_DRAWN; invalidate(true); } mBackgroundSizeChanged = true; mDefaultFocusHighlightSizeChanged = true; if (mForegroundInfo != null) { mForegroundInfo.mBoundsChanged = true; } invalidateParentIfNeeded(); } } @ViewDebug.CapturedViewProperty public final int getLeft() { return mLeft; } public final void setLeft(int left) { if (left != mLeft) { mPrivateFlags4 |= PFLAG4_HAS_MOVED; final boolean matrixIsIdentity = hasIdentityMatrix(); if (matrixIsIdentity) { if (mAttachInfo != null) { int minLeft; int xLoc; if (left < mLeft) { minLeft = left; xLoc = left - mLeft; } else { minLeft = mLeft; xLoc = 0; } invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); } } else { invalidate(true); } int oldWidth = mRight - mLeft; int height = mBottom - mTop; mLeft = left; mRenderNode.setLeft(left); sizeChange(mRight - mLeft, height, oldWidth, height); if (!matrixIsIdentity) { mPrivateFlags |= PFLAG_DRAWN; invalidate(true); } mBackgroundSizeChanged = true; mDefaultFocusHighlightSizeChanged = true; if (mForegroundInfo != null) { mForegroundInfo.mBoundsChanged = true; } invalidateParentIfNeeded(); } } @ViewDebug.CapturedViewProperty public final int getRight() { return mRight; } public final void setRight(int right) { if (right != mRight) { final boolean matrixIsIdentity = hasIdentityMatrix(); if (matrixIsIdentity) { if (mAttachInfo != null) { int maxRight; if (right < mRight) { maxRight = mRight; } else { maxRight = right; } invalidate(0, 0, maxRight - mLeft, mBottom - mTop); } } else { invalidate(true); } int oldWidth = mRight - mLeft; int height = mBottom - mTop; mRight = right; mRenderNode.setRight(mRight); sizeChange(mRight - mLeft, height, oldWidth, height); if (!matrixIsIdentity) { mPrivateFlags |= PFLAG_DRAWN; invalidate(true); } mBackgroundSizeChanged = true; mDefaultFocusHighlightSizeChanged = true; if (mForegroundInfo != null) { mForegroundInfo.mBoundsChanged = true; } invalidateParentIfNeeded(); } } private static float sanitizeFloatPropertyValue(float value, String propertyName) { return sanitizeFloatPropertyValue(value, propertyName, -Float.MAX_VALUE, Float.MAX_VALUE); } private static float sanitizeFloatPropertyValue(float value, String propertyName, float min, float max) { if (value >= min && value <= max) return value; if (value < min || value == Float.NEGATIVE_INFINITY) { if (sThrowOnInvalidFloatProperties) { throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " + value + ", the value must be >= " + min); } return min; } if (value > max || value == Float.POSITIVE_INFINITY) { if (sThrowOnInvalidFloatProperties) { throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " + value + ", the value must be <= " + max); } return max; } if (Float.isNaN(value)) { if (sThrowOnInvalidFloatProperties) { throw new IllegalArgumentException( "Cannot set '" + propertyName + "' to Float.NaN"); } return 0; } throw new IllegalStateException("How do you get here?? " + value); } @ViewDebug.ExportedProperty(category = "drawing") public float getX() { return mLeft + getTranslationX(); } public void setX(float x) { setTranslationX(x - mLeft); } @ViewDebug.ExportedProperty(category = "drawing") public float getY() { return mTop + getTranslationY(); } public void setY(float y) { setTranslationY(y - mTop); } @ViewDebug.ExportedProperty(category = "drawing") public float getZ() { return getElevation() + getTranslationZ(); } public void setZ(float z) { setTranslationZ(z - getElevation()); } @ViewDebug.ExportedProperty(category = "drawing") @InspectableProperty public float getElevation() { return mRenderNode.getElevation(); } @RemotableViewMethod public void setElevation(float elevation) { if (elevation != getElevation()) { elevation = sanitizeFloatPropertyValue(elevation, "elevation"); invalidateViewProperty(true, false); mRenderNode.setElevation(elevation); invalidateViewProperty(false, true); invalidateParentIfNeededAndWasQuickRejected(); } } @ViewDebug.ExportedProperty(category = "drawing") @InspectableProperty public float getTranslationX() { return mRenderNode.getTranslationX(); } @RemotableViewMethod public void setTranslationX(float translationX) { if (translationX != getTranslationX()) { mPrivateFlags4 |= PFLAG4_HAS_MOVED; invalidateViewProperty(true, false); mRenderNode.setTranslationX(translationX); invalidateViewProperty(false, true); invalidateParentIfNeededAndWasQuickRejected(); notifySubtreeAccessibilityStateChangedIfNeeded(); } } @ViewDebug.ExportedProperty(category = "drawing") @InspectableProperty public float getTranslationY() { return mRenderNode.getTranslationY(); } @RemotableViewMethod public void setTranslationY(float translationY) { if (translationY != getTranslationY()) { mPrivateFlags4 |= PFLAG4_HAS_MOVED; invalidateViewProperty(true, false); mRenderNode.setTranslationY(translationY); invalidateViewProperty(false, true); invalidateParentIfNeededAndWasQuickRejected(); notifySubtreeAccessibilityStateChangedIfNeeded(); } } @ViewDebug.ExportedProperty(category = "drawing") @InspectableProperty public float getTranslationZ() { return mRenderNode.getTranslationZ(); } @RemotableViewMethod public void setTranslationZ(float translationZ) { if (translationZ != getTranslationZ()) { translationZ = sanitizeFloatPropertyValue(translationZ, "translationZ"); invalidateViewProperty(true, false); mRenderNode.setTranslationZ(translationZ); invalidateViewProperty(false, true); invalidateParentIfNeededAndWasQuickRejected(); } } public void setAnimationMatrix(@Nullable Matrix matrix) { invalidateViewProperty(true, false); mRenderNode.setAnimationMatrix(matrix); invalidateViewProperty(false, true); invalidateParentIfNeededAndWasQuickRejected(); } @Nullable public Matrix getAnimationMatrix() { return mRenderNode.getAnimationMatrix(); } @InspectableProperty public StateListAnimator getStateListAnimator() { return mStateListAnimator; } public void setStateListAnimator(StateListAnimator stateListAnimator) { if (mStateListAnimator == stateListAnimator) { return; } if (mStateListAnimator != null) { mStateListAnimator.setTarget(null); } mStateListAnimator = stateListAnimator; if (stateListAnimator != null) { stateListAnimator.setTarget(this); if (isAttachedToWindow()) { stateListAnimator.setState(getDrawableState()); } } } public final boolean getClipToOutline() { return mRenderNode.getClipToOutline(); } @RemotableViewMethod public void setClipToOutline(boolean clipToOutline) { damageInParent(); if (getClipToOutline() != clipToOutline) { mRenderNode.setClipToOutline(clipToOutline); } } private static final int PROVIDER_BACKGROUND = 0; private static final int PROVIDER_NONE = 1; private static final int PROVIDER_BOUNDS = 2; private static final int PROVIDER_PADDED_BOUNDS = 3; private void setOutlineProviderFromAttribute(int providerInt) { switch (providerInt) { case PROVIDER_BACKGROUND: setOutlineProvider(ViewOutlineProvider.BACKGROUND); break; case PROVIDER_NONE: setOutlineProvider(null); break; case PROVIDER_BOUNDS: setOutlineProvider(ViewOutlineProvider.BOUNDS); break; case PROVIDER_PADDED_BOUNDS: setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); break; } } public void setOutlineProvider(ViewOutlineProvider provider) { if (mOutlineProvider != provider) { mOutlineProvider = provider; invalidateOutline(); } } @InspectableProperty public ViewOutlineProvider getOutlineProvider() { return mOutlineProvider; } public void invalidateOutline() { rebuildOutline(); notifySubtreeAccessibilityStateChangedIfNeeded(); invalidateViewProperty(false, false); } private void rebuildOutline() { if (mAttachInfo == null) return; if (mOutlineProvider == null) { mRenderNode.setOutline(null); } else { final Outline outline = mAttachInfo.mTmpOutline; outline.setEmpty(); outline.setAlpha(1.0f); mOutlineProvider.getOutline(this, outline); mRenderNode.setOutline(outline); } } @ViewDebug.ExportedProperty(category = "drawing") public boolean hasShadow() { return mRenderNode.hasShadow(); } public void setOutlineSpotShadowColor(@ColorInt int color) { if (mRenderNode.setSpotShadowColor(color)) { invalidateViewProperty(true, true); } } @InspectableProperty public @ColorInt int getOutlineSpotShadowColor() { return mRenderNode.getSpotShadowColor(); } public void setOutlineAmbientShadowColor(@ColorInt int color) { if (mRenderNode.setAmbientShadowColor(color)) { invalidateViewProperty(true, true); } } @InspectableProperty public @ColorInt int getOutlineAmbientShadowColor() { return mRenderNode.getAmbientShadowColor(); } public void setRevealClip(boolean shouldClip, float x, float y, float radius) { mRenderNode.setRevealClip(shouldClip, x, y, radius); invalidateViewProperty(false, false); } public void getHitRect(Rect outRect) { if (hasIdentityMatrix() || mAttachInfo == null) { outRect.set(mLeft, mTop, mRight, mBottom); } else { final RectF tmpRect = mAttachInfo.mTmpTransformRect; tmpRect.set(0, 0, getWidth(), getHeight()); getMatrix().mapRect(tmpRect); outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); } } return pointInView(localX, localY, 0); } @UnsupportedAppUsage public boolean pointInView(float localX, float localY, float slop) { return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && localY < ((mBottom - mTop) + slop); } public void getFocusedRect(Rect r) { getDrawingRect(r); } public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { int width = mRight - mLeft; int height = mBottom - mTop; if (width > 0 && height > 0) { r.set(0, 0, width, height); if (globalOffset != null) { globalOffset.set(-mScrollX, -mScrollY); } return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); } return false; } public final boolean getGlobalVisibleRect(Rect r) { return getGlobalVisibleRect(r, null); } public final boolean getLocalVisibleRect(Rect r) { final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); if (getGlobalVisibleRect(r, offset)) { r.offset(-offset.x, -offset.y); return true; } return false; } public void offsetTopAndBottom(int offset) { if (offset != 0) { final boolean matrixIsIdentity = hasIdentityMatrix(); if (matrixIsIdentity) { if (isHardwareAccelerated()) { invalidateViewProperty(false, false); } else { final ViewParent p = mParent; if (p != null && mAttachInfo != null) { final Rect r = mAttachInfo.mTmpInvalRect; int minTop; int maxBottom; int yLoc; if (offset < 0) { minTop = mTop + offset; maxBottom = mBottom; yLoc = offset; } else { minTop = mTop; maxBottom = mBottom + offset; yLoc = 0; } r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); p.invalidateChild(this, r); } } } else { invalidateViewProperty(false, false); } mTop += offset; mBottom += offset; mRenderNode.offsetTopAndBottom(offset); if (isHardwareAccelerated()) { invalidateViewProperty(false, false); invalidateParentIfNeededAndWasQuickRejected(); } else { if (!matrixIsIdentity) { invalidateViewProperty(false, true); } invalidateParentIfNeeded(); } notifySubtreeAccessibilityStateChangedIfNeeded(); } } public void offsetLeftAndRight(int offset) { if (offset != 0) { final boolean matrixIsIdentity = hasIdentityMatrix(); if (matrixIsIdentity) { if (isHardwareAccelerated()) { invalidateViewProperty(false, false); } else { final ViewParent p = mParent; if (p != null && mAttachInfo != null) { final Rect r = mAttachInfo.mTmpInvalRect; int minLeft; int maxRight; if (offset < 0) { minLeft = mLeft + offset; maxRight = mRight; } else { minLeft = mLeft; maxRight = mRight + offset; } r.set(0, 0, maxRight - minLeft, mBottom - mTop); p.invalidateChild(this, r); } } } else { invalidateViewProperty(false, false); } mLeft += offset; mRight += offset; mRenderNode.offsetLeftAndRight(offset); if (isHardwareAccelerated()) { invalidateViewProperty(false, false); invalidateParentIfNeededAndWasQuickRejected(); } else { if (!matrixIsIdentity) { invalidateViewProperty(false, true); } invalidateParentIfNeeded(); } notifySubtreeAccessibilityStateChangedIfNeeded(); } } @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") public ViewGroup.LayoutParams getLayoutParams() { return mLayoutParams; } public void setLayoutParams(ViewGroup.LayoutParams params) { if (params == null) { throw new NullPointerException("Layout parameters cannot be null"); } mLayoutParams = params; resolveLayoutParams(); if (mParent instanceof ViewGroup) { ((ViewGroup) mParent).onSetLayoutParams(this, params); } requestLayout(); } public void resolveLayoutParams() { if (mLayoutParams != null) { mLayoutParams.resolveLayoutDirection(getLayoutDirection()); } } public void scrollTo(int x, int y) { if (mScrollX != x || mScrollY != y) { int oldX = mScrollX; int oldY = mScrollY; mScrollX = x; mScrollY = y; invalidateParentCaches(); onScrollChanged(mScrollX, mScrollY, oldX, oldY); if (!awakenScrollBars()) { postInvalidateOnAnimation(); } } } public void scrollBy(int x, int y) { scrollTo(mScrollX + x, mScrollY + y); } protected boolean awakenScrollBars() { return mScrollCache != null && awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); } private boolean initialAwakenScrollBars() { return mScrollCache != null && } protected boolean awakenScrollBars(int startDelay) { return awakenScrollBars(startDelay, true); } protected boolean awakenScrollBars(int startDelay, boolean invalidate) { final ScrollabilityCache scrollCache = mScrollCache; if (scrollCache == null || !scrollCache.fadeScrollBars) { return false; } if (scrollCache.scrollBar == null) { scrollCache.scrollBar = new ScrollBarDrawable(); scrollCache.scrollBar.setState(getDrawableState()); scrollCache.scrollBar.setCallback(this); } if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { if (invalidate) { postInvalidateOnAnimation(); } if (scrollCache.state == ScrollabilityCache.OFF) { final int KEY_REPEAT_FIRST_DELAY = 750; startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); } long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; scrollCache.fadeStartTime = fadeStartTime; scrollCache.state = ScrollabilityCache.ON; if (mAttachInfo != null) { mAttachInfo.mHandler.removeCallbacks(scrollCache); mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); } return true; } return false; } private boolean skipInvalidate() { return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && (!(mParent instanceof ViewGroup) || !((ViewGroup) mParent).isViewTransitioning(this)); } @Deprecated public void invalidate(Rect dirty) { final int scrollX = mScrollX; final int scrollY = mScrollY; invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, dirty.right - scrollX, dirty.bottom - scrollY, true, false); } @Deprecated public void invalidate(int l, int t, int r, int b) { final int scrollX = mScrollX; final int scrollY = mScrollY; invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); } public void invalidate() { invalidate(true); } @UnsupportedAppUsage public void invalidate(boolean invalidateCache) { invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); } void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate) { if (mGhostView != null) { mGhostView.invalidate(true); return; } if (skipInvalidate()) { return; } mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK; mContentCaptureSessionCached = false; if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED || (fullInvalidate && isOpaque() != mLastIsOpaque)) { if (fullInvalidate) { mLastIsOpaque = isOpaque(); mPrivateFlags &= ~PFLAG_DRAWN; } mPrivateFlags |= PFLAG_DIRTY; if (invalidateCache) { mPrivateFlags |= PFLAG_INVALIDATED; mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; } final AttachInfo ai = mAttachInfo; final ViewParent p = mParent; if (p != null && ai != null && l < r && t < b) { final Rect damage = ai.mTmpInvalRect; damage.set(l, t, r, b); p.invalidateChild(this, damage); } if (mBackground != null && mBackground.isProjected()) { final View receiver = getProjectionReceiver(); if (receiver != null) { receiver.damageInParent(); } } } } private View getProjectionReceiver() { ViewParent p = getParent(); while (p != null && p instanceof View) { final View v = (View) p; if (v.isProjectionReceiver()) { return v; } p = p.getParent(); } return null; } private boolean isProjectionReceiver() { return mBackground != null; } @UnsupportedAppUsage void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { if (!isHardwareAccelerated() || !mRenderNode.hasDisplayList() || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { if (invalidateParent) { invalidateParentCaches(); } if (forceRedraw) { mPrivateFlags |= PFLAG_DRAWN; } invalidate(false); } else { damageInParent(); } mPrivateFlags4 |= PFLAG4_HAS_VIEW_PROPERTY_INVALIDATION; } protected void damageInParent() { if (mParent != null && mAttachInfo != null) { mParent.onDescendantInvalidated(this, this); } } @UnsupportedAppUsage protected void invalidateParentCaches() { if (mParent instanceof View) { ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; } } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) protected void invalidateParentIfNeeded() { if (isHardwareAccelerated() && mParent instanceof View) { ((View) mParent).invalidate(true); } } protected void invalidateParentIfNeededAndWasQuickRejected() { if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { invalidateParentIfNeeded(); } } @ViewDebug.ExportedProperty(category = "drawing") public boolean isOpaque() { return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && getFinalAlpha() >= 1.0f; } @UnsupportedAppUsage protected void computeOpaqueFlags() { if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; } else { mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; } final int flags = mViewFlags; if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; } else { mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; } } protected boolean hasOpaqueScrollbars() { return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; } public Handler getHandler() { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { return attachInfo.mHandler; } return null; } private HandlerActionQueue getRunQueue() { if (mRunQueue == null) { mRunQueue = new HandlerActionQueue(); } return mRunQueue; } @UnsupportedAppUsage public ViewRootImpl getViewRootImpl() { if (mAttachInfo != null) { return mAttachInfo.mViewRootImpl; } return null; } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public ThreadedRenderer getThreadedRenderer() { return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; } public boolean post(Runnable action) { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { return attachInfo.mHandler.post(action); } getRunQueue().post(action); return true; } public boolean postDelayed(Runnable action, long delayMillis) { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { return attachInfo.mHandler.postDelayed(action, delayMillis); } getRunQueue().postDelayed(action, delayMillis); return true; } public void postOnAnimation(Runnable action) { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { attachInfo.mViewRootImpl.mChoreographer.postCallback( Choreographer.CALLBACK_ANIMATION, action, null); } else { getRunQueue().post(action); } } public void postOnAnimationDelayed(Runnable action, long delayMillis) { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); } else { getRunQueue().postDelayed(action, delayMillis); } } public boolean removeCallbacks(Runnable action) { if (action != null) { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { attachInfo.mHandler.removeCallbacks(action); attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( Choreographer.CALLBACK_ANIMATION, action, null); } getRunQueue().removeCallbacks(action); } return true; } public void postInvalidate() { postInvalidateDelayed(0); } public void postInvalidate(int left, int top, int right, int bottom) { postInvalidateDelayed(0, left, top, right, bottom); } public void postInvalidateDelayed(long delayMilliseconds) { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); } } public void postInvalidateDelayed(long delayMilliseconds, int left, int top, int right, int bottom) { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); info.target = this; info.left = left; info.top = top; info.right = right; info.bottom = bottom; attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); } } public void postInvalidateOnAnimation() { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); } } public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); info.target = this; info.left = left; info.top = top; info.right = right; info.bottom = bottom; attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); } } private void postSendViewScrolledAccessibilityEventCallback(int dx, int dy) { if (AccessibilityManager.getInstance(mContext).isEnabled()) { AccessibilityEvent event = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED); event.setScrollDeltaX(dx); event.setScrollDeltaY(dy); sendAccessibilityEventUnchecked(event); } } public void computeScroll() { } public boolean isHorizontalFadingEdgeEnabled() { return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; } public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { if (horizontalFadingEdgeEnabled) { initScrollCache(); } mViewFlags ^= FADING_EDGE_HORIZONTAL; } } public boolean isVerticalFadingEdgeEnabled() { return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; } public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { if (verticalFadingEdgeEnabled) { initScrollCache(); } mViewFlags ^= FADING_EDGE_VERTICAL; } } @InspectableProperty(name = "requiresFadingEdge", flagMapping = { @FlagEntry(target = FADING_EDGE_NONE, mask = FADING_EDGE_MASK, name = "none"), @FlagEntry(target = FADING_EDGE_VERTICAL, name = "vertical"), @FlagEntry(target = FADING_EDGE_HORIZONTAL, name = "horizontal") }) public int getFadingEdge() { return mViewFlags & FADING_EDGE_MASK; } @InspectableProperty public int getFadingEdgeLength() { if (mScrollCache != null && (mViewFlags & FADING_EDGE_MASK) != FADING_EDGE_NONE) { return mScrollCache.fadingEdgeLength; } return 0; } protected float getTopFadingEdgeStrength() { return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; } protected float getBottomFadingEdgeStrength() { return computeVerticalScrollOffset() + computeVerticalScrollExtent() < computeVerticalScrollRange() ? 1.0f : 0.0f; } protected float getLeftFadingEdgeStrength() { return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; } protected float getRightFadingEdgeStrength() { return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < computeHorizontalScrollRange() ? 1.0f : 0.0f; } public boolean isHorizontalScrollBarEnabled() { return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; } public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { mViewFlags ^= SCROLLBARS_HORIZONTAL; computeOpaqueFlags(); resolvePadding(); } } public boolean isVerticalScrollBarEnabled() { return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; } public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { mViewFlags ^= SCROLLBARS_VERTICAL; computeOpaqueFlags(); resolvePadding(); } } @UnsupportedAppUsage protected void recomputePadding() { internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); } public void setScrollbarFadingEnabled(boolean fadeScrollbars) { initScrollCache(); final ScrollabilityCache scrollabilityCache = mScrollCache; scrollabilityCache.fadeScrollBars = fadeScrollbars; if (fadeScrollbars) { scrollabilityCache.state = ScrollabilityCache.OFF; } else { scrollabilityCache.state = ScrollabilityCache.ON; } } public boolean isScrollbarFadingEnabled() { return mScrollCache != null && mScrollCache.fadeScrollBars; } @InspectableProperty(name = "scrollbarDefaultDelayBeforeFade") public int getScrollBarDefaultDelayBeforeFade() { return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : mScrollCache.scrollBarDefaultDelayBeforeFade; } public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; } @InspectableProperty(name = "scrollbarFadeDuration") public int getScrollBarFadeDuration() { return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : mScrollCache.scrollBarFadeDuration; } public void setScrollBarFadeDuration(int scrollBarFadeDuration) { getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; } @InspectableProperty(name = "scrollbarSize") public int getScrollBarSize() { return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : mScrollCache.scrollBarSize; } public void setScrollBarSize(int scrollBarSize) { getScrollCache().scrollBarSize = scrollBarSize; } public void setScrollBarStyle(@ScrollBarStyle int style) { if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); computeOpaqueFlags(); resolvePadding(); } } @ViewDebug.ExportedProperty(mapping = { @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") }) @InspectableProperty(name = "scrollbarStyle", enumMapping = { @EnumEntry(value = SCROLLBARS_INSIDE_OVERLAY, name = "insideOverlay"), @EnumEntry(value = SCROLLBARS_INSIDE_INSET, name = "insideInset"), @EnumEntry(value = SCROLLBARS_OUTSIDE_OVERLAY, name = "outsideOverlay"), @EnumEntry(value = SCROLLBARS_OUTSIDE_INSET, name = "outsideInset") }) @ScrollBarStyle public int getScrollBarStyle() { return mViewFlags & SCROLLBARS_STYLE_MASK; } protected int computeHorizontalScrollRange() { return getWidth(); } protected int computeHorizontalScrollOffset() { return mScrollX; } protected int computeHorizontalScrollExtent() { return getWidth(); } protected int computeVerticalScrollRange() { return getHeight(); } protected int computeVerticalScrollOffset() { return mScrollY; } protected int computeVerticalScrollExtent() { return getHeight(); } public boolean canScrollHorizontally(int direction) { final int offset = computeHorizontalScrollOffset(); final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); if (range == 0) return false; if (direction < 0) { return offset > 0; } else { return offset < range - 1; } } public boolean canScrollVertically(int direction) { final int offset = computeVerticalScrollOffset(); final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); if (range == 0) return false; if (direction < 0) { return offset > 0; } else { return offset < range - 1; } } void getScrollIndicatorBounds(@NonNull Rect out) { out.left = mScrollX; out.right = mScrollX + mRight - mLeft; out.top = mScrollY; out.bottom = mScrollY + mBottom - mTop; } private void onDrawScrollIndicators(@NonNull Canvas c) { if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { return; } final Drawable dr = mScrollIndicatorDrawable; if (dr == null) { return; } if (mAttachInfo == null) { return; } final int h = dr.getIntrinsicHeight(); final int w = dr.getIntrinsicWidth(); final Rect rect = mAttachInfo.mTmpInvalRect; getScrollIndicatorBounds(rect); if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { final boolean canScrollUp = canScrollVertically(-1); if (canScrollUp) { dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); dr.draw(c); } } if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { final boolean canScrollDown = canScrollVertically(1); if (canScrollDown) { dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); dr.draw(c); } } final int leftRtl; final int rightRtl; if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { leftRtl = PFLAG3_SCROLL_INDICATOR_END; rightRtl = PFLAG3_SCROLL_INDICATOR_START; } else { leftRtl = PFLAG3_SCROLL_INDICATOR_START; rightRtl = PFLAG3_SCROLL_INDICATOR_END; } final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; if ((mPrivateFlags3 & leftMask) != 0) { final boolean canScrollLeft = canScrollHorizontally(-1); if (canScrollLeft) { dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); dr.draw(c); } } final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; if ((mPrivateFlags3 & rightMask) != 0) { final boolean canScrollRight = canScrollHorizontally(1); if (canScrollRight) { dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); dr.draw(c); } } } private void getHorizontalScrollBarBounds(@Nullable Rect drawBounds, @Nullable Rect touchBounds) { final Rect bounds = drawBounds != null ? drawBounds : touchBounds; if (bounds == null) { return; } final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden(); final int size = getHorizontalScrollbarHeight(); final int verticalScrollBarGap = drawVerticalScrollBar ? getVerticalScrollbarWidth() : 0; final int width = mRight - mLeft; final int height = mBottom - mTop; bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); bounds.left = mScrollX + (mPaddingLeft & inside); bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; bounds.bottom = bounds.top + size; if (touchBounds == null) { return; } if (touchBounds != bounds) { touchBounds.set(bounds); } final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; if (touchBounds.height() < minTouchTarget) { final int adjust = (minTouchTarget - touchBounds.height()) / 2; touchBounds.bottom = Math.min(touchBounds.bottom + adjust, mScrollY + height); touchBounds.top = touchBounds.bottom - minTouchTarget; } if (touchBounds.width() < minTouchTarget) { final int adjust = (minTouchTarget - touchBounds.width()) / 2; touchBounds.left -= adjust; touchBounds.right = touchBounds.left + minTouchTarget; } } private void getVerticalScrollBarBounds(@Nullable Rect bounds, @Nullable Rect touchBounds) { if (mRoundScrollbarRenderer == null) { getStraightVerticalScrollBarBounds(bounds, touchBounds); } else { mRoundScrollbarRenderer.getRoundVerticalScrollBarBounds( bounds != null ? bounds : touchBounds); } } private void getStraightVerticalScrollBarBounds(@Nullable Rect drawBounds, @Nullable Rect touchBounds) { final Rect bounds = drawBounds != null ? drawBounds : touchBounds; if (bounds == null) { return; } final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; final int size = getVerticalScrollbarWidth(); int verticalScrollbarPosition = mVerticalScrollbarPosition; if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { verticalScrollbarPosition = isLayoutRtl() ? SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; } final int width = mRight - mLeft; final int height = mBottom - mTop; switch (verticalScrollbarPosition) { default: case SCROLLBAR_POSITION_RIGHT: bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); break; case SCROLLBAR_POSITION_LEFT: bounds.left = mScrollX + (mUserPaddingLeft & inside); break; } bounds.top = mScrollY + (mPaddingTop & inside); bounds.right = bounds.left + size; bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); if (touchBounds == null) { return; } if (touchBounds != bounds) { touchBounds.set(bounds); } final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; if (touchBounds.width() < minTouchTarget) { final int adjust = (minTouchTarget - touchBounds.width()) / 2; if (verticalScrollbarPosition == SCROLLBAR_POSITION_RIGHT) { touchBounds.right = Math.min(touchBounds.right + adjust, mScrollX + width); touchBounds.left = touchBounds.right - minTouchTarget; } else { touchBounds.left = Math.max(touchBounds.left + adjust, mScrollX); touchBounds.right = touchBounds.left + minTouchTarget; } } if (touchBounds.height() < minTouchTarget) { final int adjust = (minTouchTarget - touchBounds.height()) / 2; touchBounds.top -= adjust; touchBounds.bottom = touchBounds.top + minTouchTarget; } } protected final void onDrawScrollBars(@NonNull Canvas canvas) { final ScrollabilityCache cache = mScrollCache; if (cache != null) { int state = cache.state; if (state == ScrollabilityCache.OFF) { return; } boolean invalidate = false; if (state == ScrollabilityCache.FADING) { if (cache.interpolatorValues == null) { cache.interpolatorValues = new float[1]; } float[] values = cache.interpolatorValues; if (cache.scrollBarInterpolator.timeToValues(values) == Interpolator.Result.FREEZE_END) { cache.state = ScrollabilityCache.OFF; } else { cache.scrollBar.mutate().setAlpha(Math.round(values[0])); } invalidate = true; } else { cache.scrollBar.mutate().setAlpha(255); } final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden(); if (mRoundScrollbarRenderer != null) { if (drawVerticalScrollBar) { final Rect bounds = cache.mScrollBarBounds; getVerticalScrollBarBounds(bounds, null); boolean shouldDrawScrollbarAtLeft = (mVerticalScrollbarPosition == SCROLLBAR_POSITION_LEFT) || (mVerticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT && isLayoutRtl()); mRoundScrollbarRenderer.drawRoundScrollbars( canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds, shouldDrawScrollbarAtLeft); if (invalidate) { invalidate(); } } } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { final ScrollBarDrawable scrollBar = cache.scrollBar; if (drawHorizontalScrollBar) { scrollBar.setParameters(computeHorizontalScrollRange(), computeHorizontalScrollOffset(), computeHorizontalScrollExtent(), false); final Rect bounds = cache.mScrollBarBounds; getHorizontalScrollBarBounds(bounds, null); onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, bounds.right, bounds.bottom); if (invalidate) { invalidate(bounds); } } if (drawVerticalScrollBar) { scrollBar.setParameters(computeVerticalScrollRange(), computeVerticalScrollOffset(), computeVerticalScrollExtent(), true); final Rect bounds = cache.mScrollBarBounds; getVerticalScrollBarBounds(bounds, null); onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, bounds.right, bounds.bottom); if (invalidate) { invalidate(bounds); } } } } } protected boolean isVerticalScrollBarHidden() { return false; } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) protected void onDrawHorizontalScrollBar(@NonNull Canvas canvas, Drawable scrollBar, int l, int t, int r, int b) { scrollBar.setBounds(l, t, r, b); scrollBar.draw(canvas); } @UnsupportedAppUsage protected void onDrawVerticalScrollBar(@NonNull Canvas canvas, Drawable scrollBar, int l, int t, int r, int b) { scrollBar.setBounds(l, t, r, b); scrollBar.draw(canvas); } protected void onDraw(@NonNull Canvas canvas) { } @UnsupportedAppUsage void assignParent(ViewParent parent) { if (mParent == null) { mParent = parent; } else if (parent == null) { mParent = null; } else { throw new RuntimeException("view " + this + " being added, but" + " it already has a parent"); } } @CallSuper protected void onAttachedToWindow() { if (mParent != null && (mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { mParent.requestTransparentRegion(this); } mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; jumpDrawablesToCurrentState(); AccessibilityNodeIdManager.getInstance().registerViewWithId(this, getAccessibilityViewId()); resetSubtreeAccessibilityStateChanged(); rebuildOutline(); if (isFocused()) { } if (sTraceLayoutSteps) { setTraversalTracingEnabled(true); } if (sTraceRequestLayoutClass != null && sTraceRequestLayoutClass.equals(getClass().getSimpleName())) { setRelayoutTracingEnabled(true); } } public boolean resolveRtlPropertiesIfNeeded() { if (!needRtlPropertiesResolution()) return false; if (!isLayoutDirectionResolved()) { resolveLayoutDirection(); resolveLayoutParams(); } if (!isTextDirectionResolved()) { resolveTextDirection(); } if (!isTextAlignmentResolved()) { resolveTextAlignment(); } if (!areDrawablesResolved()) { resolveDrawables(); } if (!isPaddingResolved()) { resolvePadding(); } onRtlPropertiesChanged(getLayoutDirection()); return true; } @TestApi public void resetRtlProperties() { resetResolvedLayoutDirection(); resetResolvedTextDirection(); resetResolvedTextAlignment(); resetResolvedPadding(); resetResolvedDrawables(); } void dispatchScreenStateChanged(int screenState) { onScreenStateChanged(screenState); } public void onScreenStateChanged(int screenState) { } void dispatchMovedToDisplay(Display display, Configuration config) { mAttachInfo.mDisplay = display; mAttachInfo.mDisplayState = display.getState(); onMovedToDisplay(display.getDisplayId(), config); } public void onMovedToDisplay(int displayId, Configuration config) { } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private boolean hasRtlSupport() { return mContext.getApplicationInfo().hasRtlSupport(); } private boolean isRtlCompatibilityMode() { return !hasRtlSupport(); } private boolean needRtlPropertiesResolution() { return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; } public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { } public boolean resolveLayoutDirection() { mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; if (hasRtlSupport()) { switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { case LAYOUT_DIRECTION_INHERIT: if (!canResolveLayoutDirection()) return false; try { if (!mParent.isLayoutDirectionResolved()) return false; if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; } } catch (AbstractMethodError e) { Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + " does not fully implement ViewParent", e); } break; case LAYOUT_DIRECTION_RTL: mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; break; case LAYOUT_DIRECTION_LOCALE: if((LAYOUT_DIRECTION_RTL == TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; } break; default: } } mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; return true; } public boolean canResolveLayoutDirection() { switch (getRawLayoutDirection()) { case LAYOUT_DIRECTION_INHERIT: if (mParent != null) { try { return mParent.canResolveLayoutDirection(); } catch (AbstractMethodError e) { Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + " does not fully implement ViewParent", e); } } return false; default: return true; } } @TestApi public void resetResolvedLayoutDirection() { mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; } public boolean isLayoutDirectionInherited() { return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); } public boolean isLayoutDirectionResolved() { return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; } @UnsupportedAppUsage boolean isPaddingResolved() { return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void resolvePadding() { final int resolvedLayoutDirection = getLayoutDirection(); if (!isRtlCompatibilityMode()) { if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { Rect padding = sThreadLocal.get(); if (padding == null) { padding = new Rect(); sThreadLocal.set(padding); } mBackground.getPadding(padding); if (!mLeftPaddingDefined) { mUserPaddingLeftInitial = padding.left; } if (!mRightPaddingDefined) { mUserPaddingRightInitial = padding.right; } } switch (resolvedLayoutDirection) { case LAYOUT_DIRECTION_RTL: if (mUserPaddingStart != UNDEFINED_PADDING) { mUserPaddingRight = mUserPaddingStart; } else { mUserPaddingRight = mUserPaddingRightInitial; } if (mUserPaddingEnd != UNDEFINED_PADDING) { mUserPaddingLeft = mUserPaddingEnd; } else { mUserPaddingLeft = mUserPaddingLeftInitial; } break; case LAYOUT_DIRECTION_LTR: default: if (mUserPaddingStart != UNDEFINED_PADDING) { mUserPaddingLeft = mUserPaddingStart; } else { mUserPaddingLeft = mUserPaddingLeftInitial; } if (mUserPaddingEnd != UNDEFINED_PADDING) { mUserPaddingRight = mUserPaddingEnd; } else { mUserPaddingRight = mUserPaddingRightInitial; } } mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; } internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); onRtlPropertiesChanged(resolvedLayoutDirection); mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; } @TestApi public void resetResolvedPadding() { resetResolvedPaddingInternal(); } void resetResolvedPaddingInternal() { mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; } @CallSuper protected void onDetachedFromWindow() { } @CallSuper @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) protected void onDetachedFromWindowInternal() { mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; removeUnsetPressCallback(); removeLongPressCallback(); removePerformClickCallback(); clearAccessibilityThrottles(); stopNestedScroll(); jumpDrawablesToCurrentState(); destroyDrawingCache(); cleanupDraw(); mCurrentAnimation = null; if ((mViewFlags & TOOLTIP) == TOOLTIP) { removeCallbacks(mTooltipInfo.mShowTooltipRunnable); removeCallbacks(mTooltipInfo.mHideTooltipRunnable); hideTooltip(); } AccessibilityNodeIdManager.getInstance().unregisterViewWithId(getAccessibilityViewId()); if (mBackgroundRenderNode != null) { mBackgroundRenderNode.forceEndAnimators(); } mRenderNode.forceEndAnimators(); } private void cleanupDraw() { resetDisplayList(); if (mAttachInfo != null) { mAttachInfo.mViewRootImpl.cancelInvalidate(this); } } void invalidateInheritedLayoutMode(int layoutModeOfRoot) { } protected int getWindowAttachCount() { return mWindowAttachCount; } public IBinder getWindowToken() { return mAttachInfo != null ? mAttachInfo.mWindowToken : null; } public WindowId getWindowId() { AttachInfo ai = mAttachInfo; if (ai == null) { return null; } if (ai.mWindowId == null) { try { ai.mIWindowId = ai.mSession.getWindowId(ai.mWindowToken); if (ai.mIWindowId != null) { ai.mWindowId = new WindowId(ai.mIWindowId); } } catch (RemoteException e) { } } return ai.mWindowId; } public IBinder getApplicationWindowToken() { AttachInfo ai = mAttachInfo; if (ai != null) { IBinder appWindowToken = ai.mPanelParentWindowToken; if (appWindowToken == null) { appWindowToken = ai.mWindowToken; } return appWindowToken; } return null; } public Display getDisplay() { return mAttachInfo != null ? mAttachInfo.mDisplay : null; } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) return mAttachInfo != null ? mAttachInfo.mSession : null; } protected IWindow getWindow() { return mAttachInfo != null ? mAttachInfo.mWindow : null; } int combineVisibility(int vis1, int vis2) { return Math.max(vis1, vis2); } private boolean mShouldFakeFocus = false; public void fakeFocusAfterAttachingToWindow() { mShouldFakeFocus = true; } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) void dispatchAttachedToWindow(AttachInfo info, int visibility) { mAttachInfo = info; if (mOverlay != null) { mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); } mWindowAttachCount++; mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; if (mFloatingTreeObserver != null) { info.mTreeObserver.merge(mFloatingTreeObserver); mFloatingTreeObserver = null; } registerPendingFrameMetricsObservers(); if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { mAttachInfo.mScrollContainers.add(this); mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; } if (mRunQueue != null) { mRunQueue.executeActions(info.mHandler); mRunQueue = null; } performCollectViewAttributes(mAttachInfo, visibility); onAttachedToWindow(); ListenerInfo li = mListenerInfo; final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = li != null ? li.mOnAttachStateChangeListeners : null; if (listeners != null && listeners.size() > 0) { for (OnAttachStateChangeListener listener : listeners) { listener.onViewAttachedToWindow(this); } } int vis = info.mWindowVisibility; if (vis != GONE) { onWindowVisibilityChanged(vis); if (isShown()) { onVisibilityAggregated(vis == VISIBLE); } } onVisibilityChanged(this, visibility); if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { refreshDrawableState(); } needGlobalAttributesUpdate(false); notifyEnterOrExitForAutoFillIfNeeded(true); notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); if (mShouldFakeFocus) { getViewRootImpl().dispatchCompatFakeFocus(); mShouldFakeFocus = false; } } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) void dispatchDetachedFromWindow() { AttachInfo info = mAttachInfo; if (info != null) { int vis = info.mWindowVisibility; if (vis != GONE) { onWindowVisibilityChanged(GONE); if (isShown()) { onVisibilityAggregated(false); } else { notifyAutofillManagerViewVisibilityChanged(false); } } } onDetachedFromWindow(); onDetachedFromWindowInternal(); if (info != null) { info.mViewRootImpl.getImeFocusController().onViewDetachedFromWindow(this); } ListenerInfo li = mListenerInfo; final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = li != null ? li.mOnAttachStateChangeListeners : null; if (listeners != null && listeners.size() > 0) { for (OnAttachStateChangeListener listener : listeners) { listener.onViewDetachedFromWindow(this); } } if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { mAttachInfo.mScrollContainers.remove(this); mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; } notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); updateSensitiveViewsCountIfNeeded(false); mAttachInfo = null; if (mOverlay != null) { mOverlay.getOverlayView().dispatchDetachedFromWindow(); } notifyEnterOrExitForAutoFillIfNeeded(false); if (info != null && !collectPreferKeepClearRects().isEmpty()) { info.mViewRootImpl.updateKeepClearRectsForView(this); } } public final void cancelPendingInputEvents() { dispatchCancelPendingInputEvents(); } void dispatchCancelPendingInputEvents() { mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; onCancelPendingInputEvents(); if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { throw new SuperNotCalledException("View " + getClass().getSimpleName() + " did not call through to super.onCancelPendingInputEvents()"); } } public void onCancelPendingInputEvents() { removePerformClickCallback(); cancelLongPress(); mPrivateFlags3 |= PFLAG3_CALLED_SUPER; } public void saveHierarchyState(SparseArray<Parcelable> container) { dispatchSaveInstanceState(container); } protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; Parcelable state = onSaveInstanceState(); if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { throw new IllegalStateException( "Derived class did not call super.onSaveInstanceState()"); } if (state != null) { container.put(mID, state); } } } @CallSuper @Nullable protected Parcelable onSaveInstanceState() { mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; if (mStartActivityRequestWho != null || isAutofilled() || mAutofillViewId > LAST_APP_AUTOFILL_ID) { BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); if (mStartActivityRequestWho != null) { state.mSavedData |= BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED; } if (isAutofilled()) { state.mSavedData |= BaseSavedState.IS_AUTOFILLED; } if (mAutofillViewId > LAST_APP_AUTOFILL_ID) { state.mSavedData |= BaseSavedState.AUTOFILL_ID; } state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; state.mIsAutofilled = isAutofilled(); state.mHideHighlight = hideAutofillHighlight(); state.mAutofillViewId = mAutofillViewId; return state; } return BaseSavedState.EMPTY_STATE; } public void restoreHierarchyState(SparseArray<Parcelable> container) { dispatchRestoreInstanceState(container); } protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { if (mID != NO_ID) { Parcelable state = container.get(mID); if (state != null) { mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; onRestoreInstanceState(state); if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { throw new IllegalStateException( "Derived class did not call super.onRestoreInstanceState()"); } } } } @CallSuper protected void onRestoreInstanceState(Parcelable state) { mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; if (state != null && !(state instanceof AbsSavedState)) { throw new IllegalArgumentException("Wrong state class, expecting View State but " + "received " + state.getClass().toString() + " instead. This usually happens " + "when two views of different type have the same id in the same hierarchy. " + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " + "other views do not use the same id."); } if (state != null && state instanceof BaseSavedState) { BaseSavedState baseState = (BaseSavedState) state; if ((baseState.mSavedData & BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED) != 0) { mStartActivityRequestWho = baseState.mStartActivityRequestWhoSaved; } if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) { setAutofilled(baseState.mIsAutofilled, baseState.mHideHighlight); } if ((baseState.mSavedData & BaseSavedState.AUTOFILL_ID) != 0) { ((BaseSavedState) state).mSavedData &= ~BaseSavedState.AUTOFILL_ID; if ((mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) != 0) { if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.DEBUG)) { Log.d(AUTOFILL_LOG_TAG, "onRestoreInstanceState(): not setting autofillId " + "to " + baseState.mAutofillViewId + " because view explicitly set" + " it to " + mAutofillId); } } else { mAutofillViewId = baseState.mAutofillViewId; mAutofillId = null; } } } } public long getDrawingTime() { return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; } public void setDuplicateParentStateEnabled(boolean enabled) { setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); } @InspectableProperty(name = "duplicateParentState") public boolean isDuplicateParentStateEnabled() { return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; } public void setLayerType(@LayerType int layerType, @Nullable Paint paint) { if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); } boolean typeChanged = mRenderNode.setLayerType(layerType); if (!typeChanged) { setLayerPaint(paint); return; } if (layerType != LAYER_TYPE_SOFTWARE) { destroyDrawingCache(); } mLayerType = layerType; mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; mRenderNode.setLayerPaint(mLayerPaint); invalidateParentCaches(); invalidate(true); } public void setRenderEffect(@Nullable RenderEffect renderEffect) { if (mRenderNode.setRenderEffect(renderEffect)) { invalidateViewProperty(true, true); } } public void setBackdropRenderEffect(@Nullable RenderEffect renderEffect) { if (mRenderNode.setBackdropRenderEffect(renderEffect)) { invalidateViewProperty(true, true); } } public void setLayerPaint(@Nullable Paint paint) { int layerType = getLayerType(); if (layerType != LAYER_TYPE_NONE) { mLayerPaint = paint; if (layerType == LAYER_TYPE_HARDWARE) { if (mRenderNode.setLayerPaint(paint)) { invalidateViewProperty(false, false); } } else { invalidate(); } } } @InspectableProperty(enumMapping = { @EnumEntry(value = LAYER_TYPE_NONE, name = "none"), @EnumEntry(value = LAYER_TYPE_SOFTWARE, name = "software"), @EnumEntry(value = LAYER_TYPE_HARDWARE, name = "hardware") }) @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") }) @LayerType public int getLayerType() { return mLayerType; } public void buildLayer() { if (mLayerType == LAYER_TYPE_NONE) return; final AttachInfo attachInfo = mAttachInfo; if (attachInfo == null) { throw new IllegalStateException("This view must be attached to a window first"); } if (getWidth() == 0 || getHeight() == 0) { return; } switch (mLayerType) { case LAYER_TYPE_HARDWARE: updateDisplayListIfDirty(); if (attachInfo.mThreadedRenderer != null && mRenderNode.hasDisplayList()) { attachInfo.mThreadedRenderer.buildLayer(mRenderNode); } break; case LAYER_TYPE_SOFTWARE: buildDrawingCache(true); break; } } public boolean probablyHasInput() { ViewRootImpl viewRootImpl = getViewRootImpl(); if (viewRootImpl == null) { return false; } return viewRootImpl.probablyHasInput(); } @CallSuper @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) protected void destroyHardwareResources() { if (mOverlay != null) { mOverlay.getOverlayView().destroyHardwareResources(); } if (mGhostView != null) { mGhostView.destroyHardwareResources(); } } @Deprecated public void setDrawingCacheEnabled(boolean enabled) { mCachingFailed = false; setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); } @Deprecated @ViewDebug.ExportedProperty(category = "drawing") public boolean isDrawingCacheEnabled() { return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; } @SuppressWarnings({"UnusedDeclaration"}) public void outputDirtyFlags(String indent, boolean clear, int clearMask) { Log.d(VIEW_LOG_TAG, indent + this + " DIRTY(" + (mPrivateFlags & View.PFLAG_DIRTY_MASK) + ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" + (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) + ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); if (clear) { mPrivateFlags &= clearMask; } if (this instanceof ViewGroup) { ViewGroup parent = (ViewGroup) this; final int count = parent.getChildCount(); for (int i = 0; i < count; i++) { final View child = parent.getChildAt(i); child.outputDirtyFlags(indent + " ", clear, clearMask); } } } protected void dispatchGetDisplayList() {} public boolean canHaveDisplayList() { return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); } @NonNull @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public RenderNode updateDisplayListIfDirty() { final RenderNode renderNode = mRenderNode; if (!canHaveDisplayList()) { return renderNode; } if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || !renderNode.hasDisplayList() || (mRecreateDisplayList)) { if (renderNode.hasDisplayList() && !mRecreateDisplayList) { mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; mPrivateFlags &= ~PFLAG_DIRTY_MASK; dispatchGetDisplayList(); return renderNode; } mRecreateDisplayList = true; int width = mRight - mLeft; int height = mBottom - mTop; int layerType = getLayerType(); renderNode.clearStretch(); final RecordingCanvas canvas = renderNode.beginRecording(width, height); try { if (layerType == LAYER_TYPE_SOFTWARE) { buildDrawingCache(true); Bitmap cache = getDrawingCache(true); if (cache != null) { canvas.drawBitmap(cache, 0, 0, mLayerPaint); } } else { computeScroll(); canvas.translate(-mScrollX, -mScrollY); mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; mPrivateFlags &= ~PFLAG_DIRTY_MASK; mPrivateFlags4 |= PFLAG4_HAS_DRAWN; if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { dispatchDraw(canvas); drawAutofilledHighlight(canvas); if (mOverlay != null && !mOverlay.isEmpty()) { mOverlay.getOverlayView().draw(canvas); } if (isShowingLayoutBounds()) { debugDrawFocus(canvas); } } else { draw(canvas); } } if (sToolkitSetFrameRateReadOnlyFlagValue && sToolkitFrameRateViewEnablingReadOnlyFlagValue) { votePreferredFrameRate(); } } finally { renderNode.endRecording(); setDisplayListProperties(renderNode); } } else { if ((mPrivateFlags4 & PFLAG4_HAS_VIEW_PROPERTY_INVALIDATION) == PFLAG4_HAS_VIEW_PROPERTY_INVALIDATION) { if (sToolkitSetFrameRateReadOnlyFlagValue && sToolkitFrameRateViewEnablingReadOnlyFlagValue) { votePreferredFrameRate(); } mPrivateFlags4 &= ~PFLAG4_HAS_VIEW_PROPERTY_INVALIDATION; } mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; mPrivateFlags &= ~PFLAG_DIRTY_MASK; } mPrivateFlags4 &= ~PFLAG4_HAS_MOVED; mFrameContentVelocity = -1; return renderNode; } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private void resetDisplayList() { mRenderNode.discardDisplayList(); if (mBackgroundRenderNode != null) { mBackgroundRenderNode.discardDisplayList(); } } @Deprecated public Bitmap getDrawingCache() { return getDrawingCache(false); } @Deprecated public Bitmap getDrawingCache(boolean autoScale) { if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { return null; } if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { buildDrawingCache(autoScale); } return autoScale ? mDrawingCache : mUnscaledDrawingCache; } @Deprecated public void destroyDrawingCache() { if (mDrawingCache != null) { mDrawingCache.recycle(); mDrawingCache = null; } if (mUnscaledDrawingCache != null) { mUnscaledDrawingCache.recycle(); mUnscaledDrawingCache = null; } } @Deprecated public void setDrawingCacheBackgroundColor(@ColorInt int color) { if (color != mDrawingCacheBackgroundColor) { mDrawingCacheBackgroundColor = color; mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; } } @Deprecated @ColorInt public int getDrawingCacheBackgroundColor() { return mDrawingCacheBackgroundColor; } @Deprecated public void buildDrawingCache() { buildDrawingCache(false); } @Deprecated public void buildDrawingCache(boolean autoScale) { if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? mDrawingCache == null : mUnscaledDrawingCache == null)) { if (Trace.isTagEnabled(TRACE_TAG_VIEW)) { Trace.traceBegin(TRACE_TAG_VIEW, "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); } try { buildDrawingCacheImpl(autoScale); } finally { Trace.traceEnd(TRACE_TAG_VIEW); } } } private void buildDrawingCacheImpl(boolean autoScale) { mCachingFailed = false; int width = mRight - mLeft; int height = mBottom - mTop; final AttachInfo attachInfo = mAttachInfo; final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; if (autoScale && scalingRequired) { } final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; final long drawingCacheSize = ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { if (width > 0 && height > 0) { Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" + " too large to fit into a software layer (or drawing cache), needs " + projectedBitmapSize + " bytes, only " + drawingCacheSize + " available"); } destroyDrawingCache(); mCachingFailed = true; return; } boolean clear = true; Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { Bitmap.Config quality; if (!opaque) { switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { case DRAWING_CACHE_QUALITY_AUTO: case DRAWING_CACHE_QUALITY_LOW: case DRAWING_CACHE_QUALITY_HIGH: default: quality = Bitmap.Config.ARGB_8888; break; } } else { quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; } if (bitmap != null) bitmap.recycle(); try { bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), width, height, quality); bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); if (autoScale) { mDrawingCache = bitmap; } else { mUnscaledDrawingCache = bitmap; } if (opaque && use32BitCache) bitmap.setHasAlpha(false); } catch (OutOfMemoryError e) { if (autoScale) { mDrawingCache = null; } else { mUnscaledDrawingCache = null; } mCachingFailed = true; return; } clear = drawingCacheBackgroundColor != 0; } Canvas canvas; if (attachInfo != null) { canvas = attachInfo.mCanvas; if (canvas == null) { canvas = new Canvas(); } canvas.setBitmap(bitmap); attachInfo.mCanvas = null; } else { canvas = new Canvas(bitmap); } if (clear) { bitmap.eraseColor(drawingCacheBackgroundColor); } computeScroll(); final int restoreCount = canvas.save(); if (autoScale && scalingRequired) { final float scale = attachInfo.mApplicationScale; canvas.scale(scale, scale); } canvas.translate(-mScrollX, -mScrollY); mPrivateFlags |= PFLAG_DRAWN; if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || mLayerType != LAYER_TYPE_NONE) { mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; } if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { mPrivateFlags &= ~PFLAG_DIRTY_MASK; dispatchDraw(canvas); drawAutofilledHighlight(canvas); if (mOverlay != null && !mOverlay.isEmpty()) { mOverlay.getOverlayView().draw(canvas); } } else { draw(canvas); } canvas.restoreToCount(restoreCount); canvas.setBitmap(null); if (attachInfo != null) { attachInfo.mCanvas = canvas; } } @UnsupportedAppUsage public Bitmap createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren) { int width = mRight - mLeft; int height = mBottom - mTop; final AttachInfo attachInfo = mAttachInfo; final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; Canvas oldCanvas = null; try { Canvas canvas = canvasProvider.getCanvas(this, width > 0 ? width : 1, height > 0 ? height : 1); if (attachInfo != null) { oldCanvas = attachInfo.mCanvas; attachInfo.mCanvas = null; } computeScroll(); final int restoreCount = canvas.save(); canvas.scale(scale, scale); canvas.translate(-mScrollX, -mScrollY); int flags = mPrivateFlags; mPrivateFlags &= ~PFLAG_DIRTY_MASK; if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { dispatchDraw(canvas); drawAutofilledHighlight(canvas); if (mOverlay != null && !mOverlay.isEmpty()) { mOverlay.getOverlayView().draw(canvas); } } else { draw(canvas); } mPrivateFlags = flags; canvas.restoreToCount(restoreCount); return canvasProvider.createBitmap(); } finally { if (oldCanvas != null) { attachInfo.mCanvas = oldCanvas; } } } public boolean isInEditMode() { return false; } protected boolean isPaddingOffsetRequired() { return false; } protected int getLeftPaddingOffset() { return 0; } protected int getRightPaddingOffset() { return 0; } protected int getTopPaddingOffset() { return 0; } protected int getBottomPaddingOffset() { return 0; } protected int getFadeTop(boolean offsetRequired) { int top = mPaddingTop; if (offsetRequired) top += getTopPaddingOffset(); return top; } protected int getFadeHeight(boolean offsetRequired) { int padding = mPaddingTop; if (offsetRequired) padding += getTopPaddingOffset(); return mBottom - mTop - mPaddingBottom - padding; } @ViewDebug.ExportedProperty(category = "drawing") public boolean isHardwareAccelerated() { return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; } public void setClipBounds(Rect clipBounds) { if (clipBounds == mClipBounds || (clipBounds != null && clipBounds.equals(mClipBounds))) { return; } if (clipBounds != null) { if (mClipBounds == null) { mClipBounds = new Rect(clipBounds); } else { mClipBounds.set(clipBounds); } } else { mClipBounds = null; } mRenderNode.setClipRect(mClipBounds); invalidateViewProperty(false, false); } public Rect getClipBounds() { return (mClipBounds != null) ? new Rect(mClipBounds) : null; } public boolean getClipBounds(Rect outRect) { if (mClipBounds != null) { outRect.set(mClipBounds); return true; } return false; } private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, Animation a, boolean scalingRequired) { Transformation invalidationTransform; final int flags = parent.mGroupFlags; final boolean initialized = a.isInitialized(); if (!initialized) { a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); onAnimationStart(); } final Transformation t = parent.getChildTransformation(); boolean more = a.getTransformation(drawingTime, t, 1f); if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { if (parent.mInvalidationTransformation == null) { parent.mInvalidationTransformation = new Transformation(); } invalidationTransform = parent.mInvalidationTransformation; a.getTransformation(drawingTime, invalidationTransform, 1f); } else { invalidationTransform = t; } if (more) { if (!a.willChangeBounds()) { if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; parent.invalidate(mLeft, mTop, mRight, mBottom); } } else { if (parent.mInvalidateRegion == null) { parent.mInvalidateRegion = new RectF(); } final RectF region = parent.mInvalidateRegion; a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, invalidationTransform); parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; final int left = mLeft + (int) region.left; final int top = mTop + (int) region.top; parent.invalidate(left, top, left + (int) (region.width() + .5f), top + (int) (region.height() + .5f)); } } return more; } void setDisplayListProperties(RenderNode renderNode) { if (renderNode != null) { renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); renderNode.setClipToBounds(mParent instanceof ViewGroup && ((ViewGroup) mParent).getClipChildren()); float alpha = 1; if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { ViewGroup parentVG = (ViewGroup) mParent; final Transformation t = parentVG.getChildTransformation(); if (parentVG.getChildStaticTransformation(this, t)) { final int transformType = t.getTransformationType(); if (transformType != Transformation.TYPE_IDENTITY) { if ((transformType & Transformation.TYPE_ALPHA) != 0) { alpha = t.getAlpha(); } if ((transformType & Transformation.TYPE_MATRIX) != 0) { renderNode.setStaticMatrix(t.getMatrix()); } } } } if (mTransformationInfo != null) { if (alpha < 1) { if (onSetAlpha(multipliedAlpha)) { alpha = 1; } } renderNode.setAlpha(alpha); } else if (alpha < 1) { renderNode.setAlpha(alpha); } } } protected final boolean drawsWithRenderNode(@NonNull Canvas canvas) { return mAttachInfo != null && mAttachInfo.mHardwareAccelerated && canvas.isHardwareAccelerated(); } boolean draw(@NonNull Canvas canvas, ViewGroup parent, long drawingTime) { final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); boolean drawingWithRenderNode = drawsWithRenderNode(canvas); boolean more = false; final boolean childHasIdentityMatrix = hasIdentityMatrix(); final int parentFlags = parent.mGroupFlags; if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { parent.getChildTransformation().clear(); parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; } Transformation transformToApply = null; boolean concatMatrix = false; final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; final Animation a = getAnimation(); if (a != null) { more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); concatMatrix = a.willChangeTransformationMatrix(); if (concatMatrix) { mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; } transformToApply = parent.getChildTransformation(); } else { if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { mRenderNode.setAnimationMatrix(null); mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; } if (!drawingWithRenderNode && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { final Transformation t = parent.getChildTransformation(); final boolean hasTransform = parent.getChildStaticTransformation(this, t); if (hasTransform) { final int transformType = t.getTransformationType(); transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; } } } concatMatrix |= !childHasIdentityMatrix; mPrivateFlags |= PFLAG_DRAWN; if (!concatMatrix && (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && canvas.quickReject(mLeft, mTop, mRight, mBottom) && (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; return more; } mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; if (hardwareAcceleratedCanvas) { mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; mPrivateFlags &= ~PFLAG_INVALIDATED; } RenderNode renderNode = null; Bitmap cache = null; int layerType = getLayerType(); if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { if (layerType != LAYER_TYPE_NONE) { layerType = LAYER_TYPE_SOFTWARE; buildDrawingCache(true); } cache = getDrawingCache(true); } if (drawingWithRenderNode) { renderNode = updateDisplayListIfDirty(); if (!renderNode.hasDisplayList()) { renderNode = null; drawingWithRenderNode = false; } } int sx = 0; int sy = 0; if (!drawingWithRenderNode) { computeScroll(); sx = mScrollX; sy = mScrollY; } final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; final boolean offsetForScroll = cache == null && !drawingWithRenderNode; int restoreTo = -1; if (!drawingWithRenderNode || transformToApply != null) { restoreTo = canvas.save(); } if (offsetForScroll) { canvas.translate(mLeft - sx, mTop - sy); } else { if (!drawingWithRenderNode) { canvas.translate(mLeft, mTop); } if (scalingRequired) { if (drawingWithRenderNode) { restoreTo = canvas.save(); } final float scale = 1.0f / mAttachInfo.mApplicationScale; canvas.scale(scale, scale); } } if (transformToApply != null || alpha < 1 || !hasIdentityMatrix() || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { if (transformToApply != null || !childHasIdentityMatrix) { int transX = 0; int transY = 0; if (offsetForScroll) { transX = -sx; transY = -sy; } if (transformToApply != null) { if (concatMatrix) { if (drawingWithRenderNode) { renderNode.setAnimationMatrix(transformToApply.getMatrix()); } else { canvas.translate(-transX, -transY); canvas.concat(transformToApply.getMatrix()); canvas.translate(transX, transY); } parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; } float transformAlpha = transformToApply.getAlpha(); if (transformAlpha < 1) { parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; } } if (!childHasIdentityMatrix && !drawingWithRenderNode) { canvas.translate(-transX, -transY); canvas.concat(getMatrix()); canvas.translate(transX, transY); } } if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { if (alpha < 1) { mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; } else { mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; } parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; if (!drawingWithDrawingCache) { if (!onSetAlpha(multipliedAlpha)) { if (drawingWithRenderNode) { } else if (layerType == LAYER_TYPE_NONE) { canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), multipliedAlpha); } } else { mPrivateFlags |= PFLAG_ALPHA_SET; } } } } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { onSetAlpha(255); mPrivateFlags &= ~PFLAG_ALPHA_SET; } if (!drawingWithRenderNode) { if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { if (offsetForScroll) { canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); } else { if (!scalingRequired || cache == null) { canvas.clipRect(0, 0, getWidth(), getHeight()); } else { canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); } } } if (mClipBounds != null) { canvas.clipRect(mClipBounds); } } if (!drawingWithDrawingCache) { if (drawingWithRenderNode) { mPrivateFlags &= ~PFLAG_DIRTY_MASK; ((RecordingCanvas) canvas).drawRenderNode(renderNode); } else { if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { mPrivateFlags &= ~PFLAG_DIRTY_MASK; dispatchDraw(canvas); } else { draw(canvas); } } } else if (cache != null) { mPrivateFlags &= ~PFLAG_DIRTY_MASK; if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { Paint cachePaint = parent.mCachePaint; if (cachePaint == null) { cachePaint = new Paint(); cachePaint.setDither(false); parent.mCachePaint = cachePaint; } canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); } else { int layerPaintAlpha = mLayerPaint.getAlpha(); if (alpha < 1) { } canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); if (alpha < 1) { mLayerPaint.setAlpha(layerPaintAlpha); } } } if (restoreTo >= 0) { canvas.restoreToCount(restoreTo); } if (a != null && !more) { if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { onSetAlpha(255); } parent.finishAnimatingView(this, a); } if (more && hardwareAcceleratedCanvas) { if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { invalidate(true); } } mRecreateDisplayList = false; return more; } static Paint getDebugPaint() { if (sDebugPaint == null) { sDebugPaint = new Paint(); sDebugPaint.setAntiAlias(false); } return sDebugPaint; } final int dipsToPixels(int dips) { float scale = getContext().getResources().getDisplayMetrics().density; } private void debugDrawFocus(@NonNull Canvas canvas) { if (isFocused()) { final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); final int l = mScrollX; final int r = l + mRight - mLeft; final int t = mScrollY; final int b = t + mBottom - mTop; final Paint paint = getDebugPaint(); paint.setColor(DEBUG_CORNERS_COLOR); paint.setStyle(Paint.Style.FILL); canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); paint.setStyle(Paint.Style.STROKE); canvas.drawLine(l, t, r, b, paint); canvas.drawLine(l, b, r, t, paint); } } @CallSuper public void draw(@NonNull Canvas canvas) { final int privateFlags = mPrivateFlags; mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; int saveCount; drawBackground(canvas); final int viewFlags = mViewFlags; boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; if (!verticalEdges && !horizontalEdges) { onDraw(canvas); dispatchDraw(canvas); drawAutofilledHighlight(canvas); if (mOverlay != null && !mOverlay.isEmpty()) { mOverlay.getOverlayView().dispatchDraw(canvas); } onDrawForeground(canvas); drawDefaultFocusHighlight(canvas); if (isShowingLayoutBounds()) { debugDrawFocus(canvas); } return; } boolean drawTop = false; boolean drawBottom = false; boolean drawLeft = false; boolean drawRight = false; float topFadeStrength = 0.0f; float bottomFadeStrength = 0.0f; float leftFadeStrength = 0.0f; float rightFadeStrength = 0.0f; int paddingLeft = mPaddingLeft; final boolean offsetRequired = isPaddingOffsetRequired(); if (offsetRequired) { paddingLeft += getLeftPaddingOffset(); } int left = mScrollX + paddingLeft; int right = left + mRight - mLeft - mPaddingRight - paddingLeft; int top = mScrollY + getFadeTop(offsetRequired); int bottom = top + getFadeHeight(offsetRequired); if (offsetRequired) { right += getRightPaddingOffset(); bottom += getBottomPaddingOffset(); } final ScrollabilityCache scrollabilityCache = mScrollCache; final float fadeHeight = scrollabilityCache.fadingEdgeLength; int length = (int) fadeHeight; if (verticalEdges && (top + length > bottom - length)) { length = (bottom - top) / 2; } if (horizontalEdges && (left + length > right - length)) { length = (right - left) / 2; } if (verticalEdges) { topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); } if (horizontalEdges) { leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); } saveCount = canvas.getSaveCount(); int topSaveCount = -1; int bottomSaveCount = -1; int leftSaveCount = -1; int rightSaveCount = -1; int solidColor = getSolidColor(); if (solidColor == 0) { if (drawTop) { topSaveCount = canvas.saveUnclippedLayer(left, top, right, top + length); } if (drawBottom) { bottomSaveCount = canvas.saveUnclippedLayer(left, bottom - length, right, bottom); } if (drawLeft) { leftSaveCount = canvas.saveUnclippedLayer(left, top, left + length, bottom); } if (drawRight) { rightSaveCount = canvas.saveUnclippedLayer(right - length, top, right, bottom); } } else { scrollabilityCache.setFadeColor(solidColor); } onDraw(canvas); dispatchDraw(canvas); final Paint p = scrollabilityCache.paint; final Matrix matrix = scrollabilityCache.matrix; final Shader fade = scrollabilityCache.shader; if (drawRight) { matrix.postRotate(90); matrix.postTranslate(right, top); fade.setLocalMatrix(matrix); p.setShader(fade); if (solidColor == 0) { canvas.restoreUnclippedLayer(rightSaveCount, p); } else { canvas.drawRect(right - length, top, right, bottom, p); } } if (drawLeft) { matrix.postRotate(-90); matrix.postTranslate(left, top); fade.setLocalMatrix(matrix); p.setShader(fade); if (solidColor == 0) { canvas.restoreUnclippedLayer(leftSaveCount, p); } else { canvas.drawRect(left, top, left + length, bottom, p); } } if (drawBottom) { matrix.postRotate(180); matrix.postTranslate(left, bottom); fade.setLocalMatrix(matrix); p.setShader(fade); if (solidColor == 0) { canvas.restoreUnclippedLayer(bottomSaveCount, p); } else { canvas.drawRect(left, bottom - length, right, bottom, p); } } if (drawTop) { matrix.postTranslate(left, top); fade.setLocalMatrix(matrix); p.setShader(fade); if (solidColor == 0) { canvas.restoreUnclippedLayer(topSaveCount, p); } else { canvas.drawRect(left, top, right, top + length, p); } } canvas.restoreToCount(saveCount); drawAutofilledHighlight(canvas); if (mOverlay != null && !mOverlay.isEmpty()) { mOverlay.getOverlayView().dispatchDraw(canvas); } onDrawForeground(canvas); drawDefaultFocusHighlight(canvas); if (isShowingLayoutBounds()) { debugDrawFocus(canvas); } } @UnsupportedAppUsage private void drawBackground(@NonNull Canvas canvas) { final Drawable background = mBackground; if (background == null) { return; } setBackgroundBounds(); if (canvas.isHardwareAccelerated() && mAttachInfo != null && mAttachInfo.mThreadedRenderer != null) { mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); final RenderNode renderNode = mBackgroundRenderNode; if (renderNode != null && renderNode.hasDisplayList()) { setBackgroundRenderNodeProperties(renderNode); ((RecordingCanvas) canvas).drawRenderNode(renderNode); return; } } final int scrollX = mScrollX; final int scrollY = mScrollY; if ((scrollX | scrollY) == 0) { background.draw(canvas); } else { canvas.translate(scrollX, scrollY); background.draw(canvas); canvas.translate(-scrollX, -scrollY); } } void setBackgroundBounds() { if (mBackgroundSizeChanged && mBackground != null) { mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); mBackgroundSizeChanged = false; rebuildOutline(); } } private void setBackgroundRenderNodeProperties(RenderNode renderNode) { renderNode.setTranslationX(mScrollX); renderNode.setTranslationY(mScrollY); } private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { if (renderNode == null) { renderNode = RenderNode.create(drawable.getClass().getName(), new ViewAnimationHostBridge(this)); renderNode.setUsageHint(RenderNode.USAGE_BACKGROUND); } final Rect bounds = drawable.getBounds(); final int width = bounds.width(); final int height = bounds.height(); renderNode.clearStretch(); final RecordingCanvas canvas = renderNode.beginRecording(width, height); canvas.translate(-bounds.left, -bounds.top); try { drawable.draw(canvas); } finally { renderNode.endRecording(); } renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); renderNode.setProjectBackwards(drawable.isProjected()); renderNode.setProjectionReceiver(true); renderNode.setClipToBounds(false); return renderNode; } public ViewOverlay getOverlay() { if (mOverlay == null) { mOverlay = new ViewOverlay(mContext, this); } return mOverlay; } @ViewDebug.ExportedProperty(category = "drawing") @InspectableProperty @ColorInt public int getSolidColor() { return 0; } private static String printFlags(int flags) { String output = ""; int numFlags = 0; if ((flags & FOCUSABLE) == FOCUSABLE) { output += "TAKES_FOCUS"; numFlags++; } switch (flags & VISIBILITY_MASK) { case INVISIBLE: if (numFlags > 0) { output += " "; } output += "INVISIBLE"; break; case GONE: if (numFlags > 0) { output += " "; } output += "GONE"; break; default: break; } return output; } private static String printPrivateFlags(int privateFlags) { String output = ""; int numFlags = 0; if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { output += "WANTS_FOCUS"; numFlags++; } if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { if (numFlags > 0) { output += " "; } output += "FOCUSED"; numFlags++; } if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { if (numFlags > 0) { output += " "; } output += "SELECTED"; numFlags++; } if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { if (numFlags > 0) { output += " "; } output += "IS_ROOT_NAMESPACE"; numFlags++; } if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { if (numFlags > 0) { output += " "; } output += "HAS_BOUNDS"; numFlags++; } if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { if (numFlags > 0) { output += " "; } output += "DRAWN"; } return output; } public boolean isLayoutRequested() { return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; } public static boolean isLayoutModeOptical(Object o) { return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); } public static void setTraceLayoutSteps(boolean traceLayoutSteps) { sTraceLayoutSteps = traceLayoutSteps; } public static void setTracedRequestLayoutClassClass(String s) { sTraceRequestLayoutClass = s; } private boolean setOpticalFrame(int left, int top, int right, int bottom) { Insets parentInsets = mParent instanceof View ? ((View) mParent).getOpticalInsets() : Insets.NONE; Insets childInsets = getOpticalInsets(); return setFrame( left + parentInsets.left - childInsets.left, top + parentInsets.top - childInsets.top, right + parentInsets.left + childInsets.right, bottom + parentInsets.top + childInsets.bottom); } @SuppressWarnings({"unchecked"}) public void layout(int l, int t, int r, int b) { if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { if (isTraversalTracingEnabled()) { Trace.beginSection(mTracingStrings.onMeasureBeforeLayout); } onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); if (isTraversalTracingEnabled()) { Trace.endSection(); } mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; } int oldL = mLeft; int oldT = mTop; int oldB = mBottom; int oldR = mRight; boolean changed = isLayoutModeOptical(mParent) ? setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { if (isTraversalTracingEnabled()) { Trace.beginSection(mTracingStrings.onLayout); } onLayout(changed, l, t, r, b); if (isTraversalTracingEnabled()) { Trace.endSection(); } if (shouldDrawRoundScrollbar()) { if(mRoundScrollbarRenderer == null) { mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); } } else { mRoundScrollbarRenderer = null; } mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; ListenerInfo li = mListenerInfo; if (li != null && li.mOnLayoutChangeListeners != null) { ArrayList<OnLayoutChangeListener> listenersCopy = (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); int numListeners = listenersCopy.size(); for (int i = 0; i < numListeners; ++i) { listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); } } } final boolean wasLayoutValid = isLayoutValid(); mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; if (!wasLayoutValid && isFocused()) { mPrivateFlags &= ~PFLAG_WANTS_FOCUS; if (canTakeFocus()) { clearParentsWantFocus(); } else if (getViewRootImpl() == null || !getViewRootImpl().isInLayout()) { clearParentsWantFocus(); } else if (!hasParentWantsFocus()) { } } else if ((mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { mPrivateFlags &= ~PFLAG_WANTS_FOCUS; View focused = findFocus(); if (focused != null) { if (!restoreDefaultFocus() && !hasParentWantsFocus()) { } } } if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) { mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; notifyEnterOrExitForAutoFillIfNeeded(true); } notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); } private boolean hasParentWantsFocus() { ViewParent parent = mParent; while (parent instanceof ViewGroup) { ViewGroup pv = (ViewGroup) parent; if ((pv.mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { return true; } parent = pv.mParent; } return false; } protected void onLayout(boolean changed, int left, int top, int right, int bottom) { } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) protected boolean setFrame(int left, int top, int right, int bottom) { boolean changed = false; if (DBG) { Log.d(VIEW_LOG_TAG, this + " View.setFrame(" + left + "," + top + "," + right + "," + bottom + ")"); } if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { changed = true; int drawn = mPrivateFlags & PFLAG_DRAWN; int oldWidth = mRight - mLeft; int oldHeight = mBottom - mTop; int newWidth = right - left; int newHeight = bottom - top; boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); invalidate(sizeChanged); mLeft = left; mTop = top; mRight = right; mBottom = bottom; mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); mPrivateFlags |= PFLAG_HAS_BOUNDS; if (sizeChanged) { sizeChange(newWidth, newHeight, oldWidth, oldHeight); } if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { mPrivateFlags |= PFLAG_DRAWN; invalidate(sizeChanged); invalidateParentCaches(); } mPrivateFlags |= drawn; mBackgroundSizeChanged = true; mDefaultFocusHighlightSizeChanged = true; if (mForegroundInfo != null) { mForegroundInfo.mBoundsChanged = true; } notifySubtreeAccessibilityStateChangedIfNeeded(); } return changed; } public final void setLeftTopRightBottom(int left, int top, int right, int bottom) { setFrame(left, top, right, bottom); } private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { if (mAttachInfo != null && sToolkitFrameRateViewEnablingReadOnlyFlagValue) { boolean isSmall; if (sToolkitFrameRateSmallUsesPercentReadOnlyFlagValue) { float percent = size / mAttachInfo.mDisplayPixelCount; isSmall = percent <= FRAME_RATE_SIZE_PERCENTAGE_THRESHOLD; } else { float density = mAttachInfo.mDensity; isSmall = newWidth <= narrowSize || newHeight <= narrowSize || (newWidth <= smallSize && newHeight <= smallSize); } if (isSmall) { int category = sToolkitFrameRateBySizeReadOnlyFlagValue ? FRAME_RATE_CATEGORY_LOW : FRAME_RATE_CATEGORY_NORMAL; mSizeBasedFrameRateCategoryAndReason = category | FRAME_RATE_CATEGORY_REASON_SMALL; } else { int category = sToolkitFrameRateDefaultNormalReadOnlyFlagValue ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH; mSizeBasedFrameRateCategoryAndReason = category | FRAME_RATE_CATEGORY_REASON_LARGE; } } onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); if (mOverlay != null) { mOverlay.getOverlayView().setRight(newWidth); mOverlay.getOverlayView().setBottom(newHeight); } if (!sCanFocusZeroSized && isLayoutValid() && !(mParent instanceof ViewGroup && ((ViewGroup) mParent).isLayoutSuppressed())) { if (newWidth <= 0 || newHeight <= 0) { if (hasFocus()) { clearFocus(); if (mParent instanceof ViewGroup) { ((ViewGroup) mParent).clearFocusedInCluster(); } } clearAccessibilityFocus(); } else if (oldWidth <= 0 || oldHeight <= 0) { if (mParent != null && canTakeFocus()) { mParent.focusableViewAvailable(this); } } } rebuildOutline(); if (onCheckIsTextEditor() || mHandwritingDelegatorCallback != null) { setHandwritingArea(new Rect(0, 0, newWidth, newHeight)); } } @CallSuper protected void onFinishInflate() { } public Resources getResources() { return mResources; } @Override public void invalidateDrawable(@NonNull Drawable drawable) { if (verifyDrawable(drawable)) { final Rect dirty = drawable.getDirtyBounds(); final int scrollX = mScrollX; final int scrollY = mScrollY; invalidate(dirty.left + scrollX, dirty.top + scrollY, dirty.right + scrollX, dirty.bottom + scrollY); rebuildOutline(); } } @Override public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { if (verifyDrawable(who) && what != null) { final long delay = when - SystemClock.uptimeMillis(); if (mAttachInfo != null) { mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( Choreographer.CALLBACK_ANIMATION, what, who, Choreographer.subtractFrameDelay(delay)); } else { getRunQueue().postDelayed(what, delay); } } } @Override public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { if (verifyDrawable(who) && what != null) { if (mAttachInfo != null) { mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( Choreographer.CALLBACK_ANIMATION, what, who); } getRunQueue().removeCallbacks(what); } } public void unscheduleDrawable(Drawable who) { if (mAttachInfo != null && who != null) { mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( Choreographer.CALLBACK_ANIMATION, null, who); } } protected void resolveDrawables() { if (!isLayoutDirectionResolved() && getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { return; } final int layoutDirection = isLayoutDirectionResolved() ? getLayoutDirection() : getRawLayoutDirection(); if (mBackground != null) { mBackground.setLayoutDirection(layoutDirection); } if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); } if (mDefaultFocusHighlight != null) { mDefaultFocusHighlight.setLayoutDirection(layoutDirection); } mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; onResolveDrawables(layoutDirection); } boolean areDrawablesResolved() { return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; } public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { } @TestApi protected void resetResolvedDrawables() { resetResolvedDrawablesInternal(); } void resetResolvedDrawablesInternal() { mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; } @CallSuper protected boolean verifyDrawable(@NonNull Drawable who) { return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who) || (mDefaultFocusHighlight == who); } @CallSuper protected void drawableStateChanged() { final int[] state = getDrawableState(); boolean changed = false; final Drawable bg = mBackground; if (bg != null && bg.isStateful()) { changed |= bg.setState(state); } final Drawable hl = mDefaultFocusHighlight; if (hl != null && hl.isStateful()) { changed |= hl.setState(state); } final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; if (fg != null && fg.isStateful()) { changed |= fg.setState(state); } if (mScrollCache != null) { final Drawable scrollBar = mScrollCache.scrollBar; if (scrollBar != null && scrollBar.isStateful()) { changed |= scrollBar.setState(state) && mScrollCache.state != ScrollabilityCache.OFF; } } if (mStateListAnimator != null) { mStateListAnimator.setState(state); } if (!isAggregatedVisible()) { jumpDrawablesToCurrentState(); } if (changed) { invalidate(); } } @CallSuper public void drawableHotspotChanged(float x, float y) { if (mBackground != null) { mBackground.setHotspot(x, y); } if (mDefaultFocusHighlight != null) { mDefaultFocusHighlight.setHotspot(x, y); } if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { mForegroundInfo.mDrawable.setHotspot(x, y); } dispatchDrawableHotspotChanged(x, y); } public void dispatchDrawableHotspotChanged(float x, float y) { } public void refreshDrawableState() { mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; drawableStateChanged(); ViewParent parent = mParent; if (parent != null) { parent.childDrawableStateChanged(this); } } private Drawable getDefaultFocusHighlightDrawable() { if (mDefaultFocusHighlightCache == null) { if (mContext != null) { final int[] attrs = new int[] { android.R.attr.selectableItemBackground }; final TypedArray ta = mContext.obtainStyledAttributes(attrs); mDefaultFocusHighlightCache = ta.getDrawable(0); ta.recycle(); } } return mDefaultFocusHighlightCache; } private void setDefaultFocusHighlight(Drawable highlight) { mDefaultFocusHighlight = highlight; mDefaultFocusHighlightSizeChanged = true; if (highlight != null) { if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { mPrivateFlags &= ~PFLAG_SKIP_DRAW; } highlight.setLayoutDirection(getLayoutDirection()); if (highlight.isStateful()) { highlight.setState(getDrawableState()); } if (isAttachedToWindow()) { highlight.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); } highlight.setCallback(this); } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { mPrivateFlags |= PFLAG_SKIP_DRAW; } invalidate(); } @TestApi public boolean isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground) { final boolean lackFocusState = (background == null || !background.isStateful() || !background.hasFocusStateSpecified()) && (foreground == null || !foreground.isStateful() || !foreground.hasFocusStateSpecified()); return !isInTouchMode() && getDefaultFocusHighlightEnabled() && lackFocusState && isAttachedToWindow() && sUseDefaultFocusHighlight; } private void switchDefaultFocusHighlight() { if (isFocused()) { final boolean needed = isDefaultFocusHighlightNeeded(mBackground, mForegroundInfo == null ? null : mForegroundInfo.mDrawable); final boolean active = mDefaultFocusHighlight != null; if (needed && !active) { setDefaultFocusHighlight(getDefaultFocusHighlightDrawable()); } else if (!needed && active) { setDefaultFocusHighlight(null); } } } private void drawDefaultFocusHighlight(@NonNull Canvas canvas) { if (mDefaultFocusHighlight != null && isFocused()) { if (mDefaultFocusHighlightSizeChanged) { mDefaultFocusHighlightSizeChanged = false; final int l = mScrollX; final int r = l + mRight - mLeft; final int t = mScrollY; final int b = t + mBottom - mTop; mDefaultFocusHighlight.setBounds(l, t, r, b); } mDefaultFocusHighlight.draw(canvas); } } public final int[] getDrawableState() { if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { return mDrawableState; } else { mDrawableState = onCreateDrawableState(0); mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; return mDrawableState; } } protected int[] onCreateDrawableState(int extraSpace) { if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && mParent instanceof View) { return ((View) mParent).onCreateDrawableState(extraSpace); } int[] drawableState; int privateFlags = mPrivateFlags; int viewStateIndex = 0; if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested) { viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; } if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; final int privateFlags2 = mPrivateFlags2; if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; } if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; } drawableState = StateSet.get(viewStateIndex); if (false) { Log.i("View", "drawableStateIndex=" + viewStateIndex); Log.i("View", toString() + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) + " fo=" + hasFocus() + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) + " wf=" + hasWindowFocus() + ": " + Arrays.toString(drawableState)); } if (extraSpace == 0) { return drawableState; } final int[] fullState; if (drawableState != null) { fullState = new int[drawableState.length + extraSpace]; System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); } else { fullState = new int[extraSpace]; } return fullState; } protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { final int N = baseState.length; int i = N - 1; while (i >= 0 && baseState[i] == 0) { i--; } System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); return baseState; } @CallSuper public void jumpDrawablesToCurrentState() { if (mBackground != null) { mBackground.jumpToCurrentState(); } if (mStateListAnimator != null) { mStateListAnimator.jumpToCurrentState(); } if (mDefaultFocusHighlight != null) { mDefaultFocusHighlight.jumpToCurrentState(); } if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { mForegroundInfo.mDrawable.jumpToCurrentState(); } } @RemotableViewMethod public void setBackgroundColor(@ColorInt int color) { if (mBackground instanceof ColorDrawable) { ((ColorDrawable) mBackground.mutate()).setColor(color); computeOpaqueFlags(); mBackgroundResource = 0; } else { setBackground(new ColorDrawable(color)); } } @RemotableViewMethod public void setBackgroundResource(@DrawableRes int resid) { if (resid != 0 && resid == mBackgroundResource) { return; } Drawable d = null; if (resid != 0) { d = mContext.getDrawable(resid); } setBackground(d); mBackgroundResource = resid; } public void setBackground(Drawable background) { setBackgroundDrawable(background); } @Deprecated public void setBackgroundDrawable(Drawable background) { computeOpaqueFlags(); if (background == mBackground) { return; } boolean requestLayout = false; mBackgroundResource = 0; if (mBackground != null) { if (isAttachedToWindow()) { mBackground.setVisible(false, false); } mBackground.setCallback(null); unscheduleDrawable(mBackground); } if (background != null) { Rect padding = sThreadLocal.get(); if (padding == null) { padding = new Rect(); sThreadLocal.set(padding); } resetResolvedDrawablesInternal(); background.setLayoutDirection(getLayoutDirection()); if (background.getPadding(padding)) { resetResolvedPaddingInternal(); switch (background.getLayoutDirection()) { case LAYOUT_DIRECTION_RTL: mUserPaddingLeftInitial = padding.right; mUserPaddingRightInitial = padding.left; internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); break; case LAYOUT_DIRECTION_LTR: default: mUserPaddingLeftInitial = padding.left; mUserPaddingRightInitial = padding.right; internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); } mLeftPaddingDefined = false; mRightPaddingDefined = false; } if (mBackground == null || mBackground.getMinimumHeight() != background.getMinimumHeight() || mBackground.getMinimumWidth() != background.getMinimumWidth()) { requestLayout = true; } mBackground = background; if (background.isStateful()) { background.setState(getDrawableState()); } if (isAttachedToWindow()) { background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); } applyBackgroundTint(); background.setCallback(this); if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { mPrivateFlags &= ~PFLAG_SKIP_DRAW; requestLayout = true; } } else { mBackground = null; if ((mViewFlags & WILL_NOT_DRAW) != 0 && (mDefaultFocusHighlight == null) && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { mPrivateFlags |= PFLAG_SKIP_DRAW; } requestLayout = true; } computeOpaqueFlags(); if (requestLayout) { requestLayout(); } mBackgroundSizeChanged = true; invalidate(true); invalidateOutline(); } @InspectableProperty public Drawable getBackground() { return mBackground; } @RemotableViewMethod public void setBackgroundTintList(@Nullable ColorStateList tint) { if (mBackgroundTint == null) { mBackgroundTint = new TintInfo(); } mBackgroundTint.mTintList = tint; mBackgroundTint.mHasTintList = true; applyBackgroundTint(); } @InspectableProperty(name = "backgroundTint") @Nullable public ColorStateList getBackgroundTintList() { return mBackgroundTint != null ? mBackgroundTint.mTintList : null; } public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { BlendMode mode = null; if (tintMode != null) { mode = BlendMode.fromValue(tintMode.nativeInt); } setBackgroundTintBlendMode(mode); } @RemotableViewMethod public void setBackgroundTintBlendMode(@Nullable BlendMode blendMode) { if (mBackgroundTint == null) { mBackgroundTint = new TintInfo(); } mBackgroundTint.mBlendMode = blendMode; mBackgroundTint.mHasTintMode = true; applyBackgroundTint(); } @Nullable @InspectableProperty public PorterDuff.Mode getBackgroundTintMode() { PorterDuff.Mode porterDuffMode; if (mBackgroundTint != null && mBackgroundTint.mBlendMode != null) { porterDuffMode = BlendMode.blendModeToPorterDuffMode(mBackgroundTint.mBlendMode); } else { porterDuffMode = null; } return porterDuffMode; } public @Nullable BlendMode getBackgroundTintBlendMode() { return mBackgroundTint != null ? mBackgroundTint.mBlendMode : null; } private void applyBackgroundTint() { if (mBackground != null && mBackgroundTint != null) { final TintInfo tintInfo = mBackgroundTint; if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { mBackground = mBackground.mutate(); if (tintInfo.mHasTintList) { mBackground.setTintList(tintInfo.mTintList); } if (tintInfo.mHasTintMode) { mBackground.setTintBlendMode(tintInfo.mBlendMode); } if (mBackground.isStateful()) { mBackground.setState(getDrawableState()); } } } } @InspectableProperty public Drawable getForeground() { return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; } public void setForeground(Drawable foreground) { if (mForegroundInfo == null) { if (foreground == null) { return; } mForegroundInfo = new ForegroundInfo(); } if (foreground == mForegroundInfo.mDrawable) { return; } if (mForegroundInfo.mDrawable != null) { if (isAttachedToWindow()) { mForegroundInfo.mDrawable.setVisible(false, false); } mForegroundInfo.mDrawable.setCallback(null); unscheduleDrawable(mForegroundInfo.mDrawable); } mForegroundInfo.mDrawable = foreground; mForegroundInfo.mBoundsChanged = true; if (foreground != null) { if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { mPrivateFlags &= ~PFLAG_SKIP_DRAW; } foreground.setLayoutDirection(getLayoutDirection()); if (foreground.isStateful()) { foreground.setState(getDrawableState()); } applyForegroundTint(); if (isAttachedToWindow()) { foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); } foreground.setCallback(this); } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null && (mDefaultFocusHighlight == null)) { mPrivateFlags |= PFLAG_SKIP_DRAW; } requestLayout(); invalidate(); } public boolean isForegroundInsidePadding() { return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; } @InspectableProperty(valueType = InspectableProperty.ValueType.GRAVITY) public int getForegroundGravity() { return mForegroundInfo != null ? mForegroundInfo.mGravity : Gravity.START | Gravity.TOP; } public void setForegroundGravity(int gravity) { if (mForegroundInfo == null) { mForegroundInfo = new ForegroundInfo(); } if (mForegroundInfo.mGravity != gravity) { if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { gravity |= Gravity.START; } if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { gravity |= Gravity.TOP; } mForegroundInfo.mGravity = gravity; requestLayout(); } } @RemotableViewMethod public void setForegroundTintList(@Nullable ColorStateList tint) { if (mForegroundInfo == null) { mForegroundInfo = new ForegroundInfo(); } if (mForegroundInfo.mTintInfo == null) { mForegroundInfo.mTintInfo = new TintInfo(); } mForegroundInfo.mTintInfo.mTintList = tint; mForegroundInfo.mTintInfo.mHasTintList = true; applyForegroundTint(); } @InspectableProperty(name = "foregroundTint") @Nullable public ColorStateList getForegroundTintList() { return mForegroundInfo != null && mForegroundInfo.mTintInfo != null ? mForegroundInfo.mTintInfo.mTintList : null; } public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { BlendMode mode = null; if (tintMode != null) { mode = BlendMode.fromValue(tintMode.nativeInt); } setForegroundTintBlendMode(mode); } @RemotableViewMethod public void setForegroundTintBlendMode(@Nullable BlendMode blendMode) { if (mForegroundInfo == null) { mForegroundInfo = new ForegroundInfo(); } if (mForegroundInfo.mTintInfo == null) { mForegroundInfo.mTintInfo = new TintInfo(); } mForegroundInfo.mTintInfo.mBlendMode = blendMode; mForegroundInfo.mTintInfo.mHasTintMode = true; applyForegroundTint(); } @InspectableProperty @Nullable public PorterDuff.Mode getForegroundTintMode() { BlendMode blendMode = mForegroundInfo != null && mForegroundInfo.mTintInfo != null ? mForegroundInfo.mTintInfo.mBlendMode : null; if (blendMode != null) { return BlendMode.blendModeToPorterDuffMode(blendMode); } else { return null; } } public @Nullable BlendMode getForegroundTintBlendMode() { return mForegroundInfo != null && mForegroundInfo.mTintInfo != null ? mForegroundInfo.mTintInfo.mBlendMode : null; } private void applyForegroundTint() { if (mForegroundInfo != null && mForegroundInfo.mDrawable != null && mForegroundInfo.mTintInfo != null) { final TintInfo tintInfo = mForegroundInfo.mTintInfo; if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); if (tintInfo.mHasTintList) { mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); } if (tintInfo.mHasTintMode) { mForegroundInfo.mDrawable.setTintBlendMode(tintInfo.mBlendMode); } if (mForegroundInfo.mDrawable.isStateful()) { mForegroundInfo.mDrawable.setState(getDrawableState()); } } } } @Nullable private Drawable getAutofilledDrawable() { if (mAttachInfo == null) { return null; } if (mAttachInfo.mAutofilledDrawable == null) { Context rootContext = getRootView().getContext(); TypedArray a = rootContext.getTheme().obtainStyledAttributes(AUTOFILL_HIGHLIGHT_ATTR); int attributeResourceId = a.getResourceId(0, 0); mAttachInfo.mAutofilledDrawable = rootContext.getDrawable(attributeResourceId); a.recycle(); } return mAttachInfo.mAutofilledDrawable; } private void drawAutofilledHighlight(@NonNull Canvas canvas) { if (isAutofilled() && !hideAutofillHighlight()) { Drawable autofilledHighlight = getAutofilledDrawable(); if (autofilledHighlight != null) { autofilledHighlight.setBounds(0, 0, getWidth(), getHeight()); autofilledHighlight.draw(canvas); } } } public void onDrawForeground(@NonNull Canvas canvas) { onDrawScrollIndicators(canvas); onDrawScrollBars(canvas); final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; if (foreground != null) { if (mForegroundInfo.mBoundsChanged) { mForegroundInfo.mBoundsChanged = false; final Rect selfBounds = mForegroundInfo.mSelfBounds; final Rect overlayBounds = mForegroundInfo.mOverlayBounds; if (mForegroundInfo.mInsidePadding) { selfBounds.set(0, 0, getWidth(), getHeight()); } else { selfBounds.set(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); } final int ld = getLayoutDirection(); Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); foreground.setBounds(overlayBounds); } foreground.draw(canvas); } } public void setPadding(int left, int top, int right, int bottom) { resetResolvedPaddingInternal(); mUserPaddingStart = UNDEFINED_PADDING; mUserPaddingEnd = UNDEFINED_PADDING; mUserPaddingLeftInitial = left; mUserPaddingRightInitial = right; mLeftPaddingDefined = true; mRightPaddingDefined = true; internalSetPadding(left, top, right, bottom); } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768420) protected void internalSetPadding(int left, int top, int right, int bottom) { mUserPaddingLeft = left; mUserPaddingRight = right; mUserPaddingBottom = bottom; final int viewFlags = mViewFlags; boolean changed = false; if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 ? 0 : getVerticalScrollbarWidth(); switch (mVerticalScrollbarPosition) { case SCROLLBAR_POSITION_DEFAULT: if (isLayoutRtl()) { left += offset; } else { right += offset; } break; case SCROLLBAR_POSITION_RIGHT: right += offset; break; case SCROLLBAR_POSITION_LEFT: left += offset; break; } } if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 ? 0 : getHorizontalScrollbarHeight(); } } if (mPaddingLeft != left) { changed = true; mPaddingLeft = left; } if (mPaddingTop != top) { changed = true; mPaddingTop = top; } if (mPaddingRight != right) { changed = true; mPaddingRight = right; } if (mPaddingBottom != bottom) { changed = true; mPaddingBottom = bottom; } if (changed) { requestLayout(); invalidateOutline(); } } public void setPaddingRelative(int start, int top, int end, int bottom) { resetResolvedPaddingInternal(); mUserPaddingStart = start; mUserPaddingEnd = end; mLeftPaddingDefined = true; mRightPaddingDefined = true; switch(getLayoutDirection()) { case LAYOUT_DIRECTION_RTL: mUserPaddingLeftInitial = end; mUserPaddingRightInitial = start; internalSetPadding(end, top, start, bottom); break; case LAYOUT_DIRECTION_LTR: default: mUserPaddingLeftInitial = start; mUserPaddingRightInitial = end; internalSetPadding(start, top, end, bottom); } } @LayoutRes public int getSourceLayoutResId() { return mSourceLayoutId; } @InspectableProperty public int getPaddingTop() { return mPaddingTop; } @InspectableProperty public int getPaddingBottom() { return mPaddingBottom; } @InspectableProperty public int getPaddingLeft() { if (!isPaddingResolved()) { resolvePadding(); } return mPaddingLeft; } public int getPaddingStart() { if (!isPaddingResolved()) { resolvePadding(); } return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? mPaddingRight : mPaddingLeft; } @InspectableProperty public int getPaddingRight() { if (!isPaddingResolved()) { resolvePadding(); } return mPaddingRight; } public int getPaddingEnd() { if (!isPaddingResolved()) { resolvePadding(); } return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? mPaddingLeft : mPaddingRight; } public boolean isPaddingRelative() { return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); } Insets computeOpticalInsets() { return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); } @UnsupportedAppUsage public void resetPaddingToInitialValues() { if (isRtlCompatibilityMode()) { mPaddingLeft = mUserPaddingLeftInitial; mPaddingRight = mUserPaddingRightInitial; return; } if (isLayoutRtl()) { mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; } else { mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; } } public Insets getOpticalInsets() { if (mLayoutInsets == null) { mLayoutInsets = computeOpticalInsets(); } return mLayoutInsets; } public void setOpticalInsets(Insets insets) { mLayoutInsets = insets; } public void setSelected(boolean selected) { if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); if (!selected) resetPressedState(); invalidate(true); refreshDrawableState(); dispatchSetSelected(selected); if (selected) { sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); } else { notifyViewAccessibilityStateChangedIfNeeded( AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } } } protected void dispatchSetSelected(boolean selected) { } @ViewDebug.ExportedProperty @InspectableProperty(hasAttributeId = false) public boolean isSelected() { return (mPrivateFlags & PFLAG_SELECTED) != 0; } public void setActivated(boolean activated) { if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); invalidate(true); refreshDrawableState(); dispatchSetActivated(activated); } } protected void dispatchSetActivated(boolean activated) { } @ViewDebug.ExportedProperty @InspectableProperty(hasAttributeId = false) public boolean isActivated() { return (mPrivateFlags & PFLAG_ACTIVATED) != 0; } public ViewTreeObserver getViewTreeObserver() { if (mAttachInfo != null) { return mAttachInfo.mTreeObserver; } if (mFloatingTreeObserver == null) { mFloatingTreeObserver = new ViewTreeObserver(mContext); } return mFloatingTreeObserver; } public View getRootView() { if (mAttachInfo != null) { final View v = mAttachInfo.mRootView; if (v != null) { return v; } } View parent = this; while (parent.mParent instanceof View) { parent = (View) parent.mParent; } return parent; } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean toGlobalMotionEvent(MotionEvent ev) { final AttachInfo info = mAttachInfo; if (info == null) { return false; } final Matrix m = info.mTmpMatrix; m.set(Matrix.IDENTITY_MATRIX); transformMatrixToGlobal(m); ev.transform(m); return true; } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean toLocalMotionEvent(MotionEvent ev) { final AttachInfo info = mAttachInfo; if (info == null) { return false; } final Matrix m = info.mTmpMatrix; m.set(Matrix.IDENTITY_MATRIX); transformMatrixToLocal(m); ev.transform(m); return true; } public void transformMatrixToGlobal(@NonNull Matrix matrix) { final ViewParent parent = mParent; if (parent instanceof View) { final View vp = (View) parent; vp.transformMatrixToGlobal(matrix); matrix.preTranslate(-vp.mScrollX, -vp.mScrollY); } else if (parent instanceof ViewRootImpl) { final ViewRootImpl vr = (ViewRootImpl) parent; vr.transformMatrixToGlobal(matrix); matrix.preTranslate(0, -vr.mCurScrollY); } matrix.preTranslate(mLeft, mTop); if (!hasIdentityMatrix()) { matrix.preConcat(getMatrix()); } } public void transformMatrixToLocal(@NonNull Matrix matrix) { final ViewParent parent = mParent; if (parent instanceof View) { final View vp = (View) parent; vp.transformMatrixToLocal(matrix); matrix.postTranslate(vp.mScrollX, vp.mScrollY); } else if (parent instanceof ViewRootImpl) { final ViewRootImpl vr = (ViewRootImpl) parent; vr.transformMatrixToLocal(matrix); matrix.postTranslate(0, vr.mCurScrollY); } matrix.postTranslate(-mLeft, -mTop); if (!hasIdentityMatrix()) { matrix.postConcat(getInverseMatrix()); } } @ViewDebug.ExportedProperty(category = "layout", indexMapping = { @ViewDebug.IntToString(from = 0, to = "x"), @ViewDebug.IntToString(from = 1, to = "y") }) @UnsupportedAppUsage public int[] getLocationOnScreen() { int[] location = new int[2]; getLocationOnScreen(location); return location; } public void getLocationOnScreen(@Size(2) int[] outLocation) { getLocationInWindow(outLocation); final AttachInfo info = mAttachInfo; if (info != null) { outLocation[0] += info.mWindowLeft; outLocation[1] += info.mWindowTop; info.mViewRootImpl.applyViewLocationSandboxingIfNeeded(outLocation); } } public void getLocationInWindow(@Size(2) int[] outLocation) { if (outLocation == null || outLocation.length < 2) { throw new IllegalArgumentException("outLocation must be an array of two integers"); } outLocation[0] = 0; outLocation[1] = 0; transformFromViewToWindowSpace(outLocation); } public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { if (inOutLocation == null || inOutLocation.length < 2) { throw new IllegalArgumentException("inOutLocation must be an array of two integers"); } if (mAttachInfo == null) { inOutLocation[0] = inOutLocation[1] = 0; return; } float position[] = mAttachInfo.mTmpTransformLocation; position[0] = inOutLocation[0]; position[1] = inOutLocation[1]; if (!hasIdentityMatrix()) { getMatrix().mapPoints(position); } position[0] += mLeft; position[1] += mTop; ViewParent viewParent = mParent; while (viewParent instanceof View) { final View view = (View) viewParent; position[0] -= view.mScrollX; position[1] -= view.mScrollY; if (!view.hasIdentityMatrix()) { view.getMatrix().mapPoints(position); } position[0] += view.mLeft; position[1] += view.mTop; viewParent = view.mParent; } if (viewParent instanceof ViewRootImpl) { final ViewRootImpl vr = (ViewRootImpl) viewParent; position[1] -= vr.mCurScrollY; } inOutLocation[0] = Math.round(position[0]); inOutLocation[1] = Math.round(position[1]); } protected <T extends View> T findViewTraversal(@IdRes int id) { if (id == mID) { return (T) this; } return null; } protected <T extends View> T findViewWithTagTraversal(Object tag) { if (tag != null && tag.equals(mTag)) { return (T) this; } return null; } protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) { if (predicate.test(this)) { return (T) this; } return null; } public final <T extends View> T findViewById(@IdRes int id) { if (id == NO_ID) { return null; } return findViewTraversal(id); } @NonNull public final <T extends View> T requireViewById(@IdRes int id) { T view = findViewById(id); if (view == null) { throw new IllegalArgumentException("ID does not reference a View inside this View"); } return view; } public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) { if (getAccessibilityViewId() == accessibilityId) { return (T) this; } return null; } public <T extends View> T findViewByAutofillIdTraversal(int autofillId) { if (getAutofillViewId() == autofillId) { return (T) this; } return null; } public final <T extends View> T findViewWithTag(Object tag) { if (tag == null) { return null; } return findViewWithTagTraversal(tag); } public final <T extends View> T findViewByPredicate(Predicate<View> predicate) { return findViewByPredicateTraversal(predicate, null); } public final <T extends View> T findViewByPredicateInsideOut( View start, Predicate<View> predicate) { View childToSkip = null; for (;;) { T view = start.findViewByPredicateTraversal(predicate, childToSkip); if (view != null || start == this) { return view; } ViewParent parent = start.getParent(); if (parent == null || !(parent instanceof View)) { return null; } childToSkip = start; start = (View) parent; } } public void setId(@IdRes int id) { mID = id; if (mID == View.NO_ID && mLabelForId != View.NO_ID) { mID = generateViewId(); } } @UnsupportedAppUsage @TestApi public void setIsRootNamespace(boolean isRoot) { if (isRoot) { mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; } else { mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; } } @UnsupportedAppUsage public boolean isRootNamespace() { return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; } @IdRes @ViewDebug.CapturedViewProperty @InspectableProperty public int getId() { return mID; } public long getUniqueDrawingId() { return mRenderNode.getUniqueId(); } @ViewDebug.ExportedProperty @InspectableProperty public Object getTag() { return mTag; } public void setTag(final Object tag) { mTag = tag; } public Object getTag(int key) { if (mKeyedTags != null) return mKeyedTags.get(key); return null; } public void setTag(int key, final Object tag) { if ((key >>> 24) < 2) { throw new IllegalArgumentException("The key must be an application-specific " + "resource id."); } setKeyedTag(key, tag); } @UnsupportedAppUsage public void setTagInternal(int key, Object tag) { if ((key >>> 24) != 0x1) { throw new IllegalArgumentException("The key must be a framework-specific " + "resource id."); } setKeyedTag(key, tag); } private void setKeyedTag(int key, Object tag) { if (mKeyedTags == null) { mKeyedTags = new SparseArray<Object>(2); } mKeyedTags.put(key, tag); } @UnsupportedAppUsage public void debug() { debug(0); } @UnsupportedAppUsage protected void debug(int depth) { String output = debugIndent(depth - 1); output += "+ " + this; int id = getId(); if (id != -1) { output += " (id=" + id + ")"; } Object tag = getTag(); if (tag != null) { output += " (tag=" + tag + ")"; } Log.d(VIEW_LOG_TAG, output); if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { output = debugIndent(depth) + " FOCUSED"; Log.d(VIEW_LOG_TAG, output); } output = debugIndent(depth); output += "frame={" + mLeft + ", " + mTop + ", " + mRight + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY + "} "; Log.d(VIEW_LOG_TAG, output); if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 || mPaddingBottom != 0) { output = debugIndent(depth); output += "padding={" + mPaddingLeft + ", " + mPaddingTop + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; Log.d(VIEW_LOG_TAG, output); } output = debugIndent(depth); output += "mMeasureWidth=" + mMeasuredWidth + " mMeasureHeight=" + mMeasuredHeight; Log.d(VIEW_LOG_TAG, output); output = debugIndent(depth); if (mLayoutParams == null) { output += "BAD! no layout params"; } else { output = mLayoutParams.debug(output); } Log.d(VIEW_LOG_TAG, output); output = debugIndent(depth); output += "flags={"; output += View.printFlags(mViewFlags); output += "}"; Log.d(VIEW_LOG_TAG, output); output = debugIndent(depth); output += "privateFlags={"; output += View.printPrivateFlags(mPrivateFlags); output += "}"; Log.d(VIEW_LOG_TAG, output); } protected static String debugIndent(int depth) { spaces.append(' ').append(' '); } return spaces.toString(); } @ViewDebug.ExportedProperty(category = "layout") @InspectableProperty public int getBaseline() { return -1; } public boolean isInLayout() { ViewRootImpl viewRoot = getViewRootImpl(); return (viewRoot != null && viewRoot.isInLayout()); } private void printStackStrace(String name) { Log.d(VIEW_LOG_TAG, "---- ST:" + name); StringBuilder sb = new StringBuilder(); StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); int startIndex = 1; int endIndex = Math.min(stackTraceElements.length, startIndex + 20); for (int i = startIndex; i < endIndex; i++) { StackTraceElement s = stackTraceElements[i]; sb.append(s.getMethodName()) .append("(") .append(s.getFileName()) .append(":") .append(s.getLineNumber()) .append(") <- "); } Log.d(VIEW_LOG_TAG, name + ": " + sb); } @CallSuper public void requestLayout() { if (isRelayoutTracingEnabled()) { Trace.instantForTrack(TRACE_TAG_APP, "requestLayoutTracing", mTracingStrings.classSimpleName); printStackStrace(mTracingStrings.requestLayoutStacktracePrefix); } if (mMeasureCache != null) mMeasureCache.clear(); if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { ViewRootImpl viewRoot = getViewRootImpl(); if (viewRoot != null && viewRoot.isInLayout()) { if (!viewRoot.requestLayoutDuringLayout(this)) { return; } } mAttachInfo.mViewRequestingLayout = this; } mPrivateFlags |= PFLAG_FORCE_LAYOUT; mPrivateFlags |= PFLAG_INVALIDATED; if (mParent != null && !mParent.isLayoutRequested()) { mParent.requestLayout(); } if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { mAttachInfo.mViewRequestingLayout = null; } } public void forceLayout() { if (mMeasureCache != null) mMeasureCache.clear(); mPrivateFlags |= PFLAG_FORCE_LAYOUT; mPrivateFlags |= PFLAG_INVALIDATED; } public final void measure(int widthMeasureSpec, int heightMeasureSpec) { boolean optical = isLayoutModeOptical(this); if (optical != isLayoutModeOptical(mParent)) { Insets insets = getOpticalInsets(); int oWidth = insets.left + insets.right; int oHeight = insets.top + insets.bottom; widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); } long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec || heightMeasureSpec != mOldHeightMeasureSpec; final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); final boolean needsLayout = specChanged && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); if (forceLayout || needsLayout) { mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; resolveRtlPropertiesIfNeeded(); int cacheIndex; if (sUseMeasureCacheDuringForceLayoutFlagValue) { cacheIndex = mMeasureCache.indexOfKey(key); } else { cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); } if (cacheIndex < 0) { if (isTraversalTracingEnabled()) { Trace.beginSection(mTracingStrings.onMeasure); } if (android.os.Flags.adpfMeasureDuringInputEventBoost()) { final boolean notifyRenderer = hasExpensiveMeasuresDuringInputEvent(); if (notifyRenderer) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "CPU_LOAD_UP: " + "hasExpensiveMeasuresDuringInputEvent"); getViewRootImpl().notifyRendererOfExpensiveFrame(); Trace.traceEnd(Trace.TRACE_TAG_VIEW); } } onMeasure(widthMeasureSpec, heightMeasureSpec); if (isTraversalTracingEnabled()) { Trace.endSection(); } mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; } else { long value = mMeasureCache.valueAt(cacheIndex); setMeasuredDimensionRaw((int) (value >> 32), (int) value); mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; } if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { throw new IllegalStateException("View with id " + getId() + ": " + getClass().getName() + "#onMeasure() did not set the" + " measured dimension by calling" + " setMeasuredDimension()"); } mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; } mOldWidthMeasureSpec = widthMeasureSpec; mOldHeightMeasureSpec = heightMeasureSpec; mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | (long) mMeasuredHeight & 0xffffffffL); } protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); } protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { boolean optical = isLayoutModeOptical(this); if (optical != isLayoutModeOptical(mParent)) { Insets insets = getOpticalInsets(); int opticalWidth = insets.left + insets.right; int opticalHeight = insets.top + insets.bottom; measuredWidth += optical ? opticalWidth : -opticalWidth; measuredHeight += optical ? opticalHeight : -opticalHeight; } setMeasuredDimensionRaw(measuredWidth, measuredHeight); } private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { mMeasuredWidth = measuredWidth; mMeasuredHeight = measuredHeight; mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; } public static int combineMeasuredStates(int curState, int newState) { return curState | newState; } public static int resolveSize(int size, int measureSpec) { return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; } public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { final int specMode = MeasureSpec.getMode(measureSpec); final int specSize = MeasureSpec.getSize(measureSpec); final int result; switch (specMode) { case MeasureSpec.AT_MOST: if (specSize < size) { result = specSize | MEASURED_STATE_TOO_SMALL; } else { result = size; } break; case MeasureSpec.EXACTLY: result = specSize; break; case MeasureSpec.UNSPECIFIED: default: result = size; } return result | (childMeasuredState & MEASURED_STATE_MASK); } public static int getDefaultSize(int size, int measureSpec) { int result = size; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); switch (specMode) { case MeasureSpec.UNSPECIFIED: result = size; break; case MeasureSpec.AT_MOST: case MeasureSpec.EXACTLY: result = specSize; break; } return result; } protected int getSuggestedMinimumHeight() { return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); } protected int getSuggestedMinimumWidth() { return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); } @InspectableProperty(name = "minHeight") public int getMinimumHeight() { return mMinHeight; } @RemotableViewMethod public void setMinimumHeight(int minHeight) { mMinHeight = minHeight; requestLayout(); } @InspectableProperty(name = "minWidth") public int getMinimumWidth() { return mMinWidth; } @RemotableViewMethod public void setMinimumWidth(int minWidth) { mMinWidth = minWidth; requestLayout(); } public Animation getAnimation() { return mCurrentAnimation; } public void startAnimation(Animation animation) { animation.setStartTime(Animation.START_ON_FIRST_FRAME); setAnimation(animation); invalidateParentCaches(); invalidate(true); } public void clearAnimation() { if (mCurrentAnimation != null) { mCurrentAnimation.detach(); } mCurrentAnimation = null; invalidateParentIfNeeded(); } public void setAnimation(Animation animation) { mCurrentAnimation = animation; if (animation != null) { if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); } animation.reset(); } } @CallSuper protected void onAnimationStart() { mPrivateFlags |= PFLAG_ANIMATION_STARTED; } @CallSuper protected void onAnimationEnd() { mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; } protected boolean onSetAlpha(int alpha) { return false; } public boolean gatherTransparentRegion(@Nullable Region region) { final AttachInfo attachInfo = mAttachInfo; if (region != null && attachInfo != null) { final int pflags = mPrivateFlags; if ((pflags & PFLAG_SKIP_DRAW) == 0) { final int[] location = attachInfo.mTransparentLocation; getLocationInWindow(location); int shadowOffset = getZ() > 0 ? (int) getZ() : 0; region.op(location[0] - shadowOffset, location[1] - shadowOffset, location[0] + mRight - mLeft + shadowOffset, } else { if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { applyDrawableToTransparentRegion(mBackground, region); } if (mForegroundInfo != null && mForegroundInfo.mDrawable != null && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); } if (mDefaultFocusHighlight != null && mDefaultFocusHighlight.getOpacity() != PixelFormat.TRANSPARENT) { applyDrawableToTransparentRegion(mDefaultFocusHighlight, region); } } } return true; } public void playSoundEffect(@SoundEffectConstants.SoundEffect int soundConstant) { if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { return; } mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); } public boolean performHapticFeedback(int feedbackConstant) { return performHapticFeedback(feedbackConstant, 0); } public boolean performHapticFeedback(int feedbackConstant, int flags) { if (feedbackConstant == HapticFeedbackConstants.NO_HAPTICS || mAttachInfo == null) { return false; } if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 && !isHapticFeedbackEnabled()) { return false; } final boolean always = (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0; boolean fromIme = false; if (mAttachInfo.mViewRootImpl != null) { fromIme = mAttachInfo.mViewRootImpl.mWindowAttributes.type == TYPE_INPUT_METHOD; } if (Flags.useVibratorHapticFeedback()) { if (!mAttachInfo.canPerformHapticFeedback()) { return false; } getSystemVibrator().performHapticFeedback( feedbackConstant, always, "View#performHapticFeedback", fromIme); return true; } return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, always, fromIme); } private Vibrator getSystemVibrator() { if (mVibrator != null) { return mVibrator; } return mVibrator = mContext.getSystemService(Vibrator.class); } @Deprecated public void setSystemUiVisibility(int visibility) { if (visibility != mSystemUiVisibility) { mSystemUiVisibility = visibility; if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { mParent.recomputeViewAttributes(this); } } } @Deprecated public int getSystemUiVisibility() { return mSystemUiVisibility; } @Deprecated public int getWindowSystemUiVisibility() { return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; } @Deprecated public void onWindowSystemUiVisibilityChanged(int visible) { } @Deprecated public void dispatchWindowSystemUiVisiblityChanged(int visible) { onWindowSystemUiVisibilityChanged(visible); } @Deprecated public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { getListenerInfo().mOnSystemUiVisibilityChangeListener = l; if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { mParent.recomputeViewAttributes(this); } } @Deprecated public void dispatchSystemUiVisibilityChanged(int visibility) { ListenerInfo li = mListenerInfo; if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); } } boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); if (val != mSystemUiVisibility) { setSystemUiVisibility(val); return true; } return false; } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void setDisabledSystemUiVisibility(int flags) { if (mAttachInfo != null) { if (mAttachInfo.mDisabledSystemUiVisibility != flags) { mAttachInfo.mDisabledSystemUiVisibility = flags; if (mParent != null) { mParent.recomputeViewAttributes(this); } } } } public void onSystemBarAppearanceChanged(@WindowInsetsController.Appearance int appearance) { } public static class DragShadowBuilder { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private final WeakReference<View> mView; public DragShadowBuilder(View view) { mView = new WeakReference<View>(view); } public DragShadowBuilder() { mView = new WeakReference<View>(null); } @SuppressWarnings({"JavadocReference"}) final public View getView() { return mView.get(); } public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { final View view = mView.get(); if (view != null) { outShadowSize.set(view.getWidth(), view.getHeight()); outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); } else { Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); } } public void onDrawShadow(@NonNull Canvas canvas) { final View view = mView.get(); if (view != null) { view.draw(canvas); } else { Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); } } } @Deprecated public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags) { return startDragAndDrop(data, shadowBuilder, myLocalState, flags); } public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags) { if (ViewDebug.DEBUG_DRAG) { Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); } if (mAttachInfo == null) { Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); return false; } if (!mAttachInfo.mViewRootImpl.mSurface.isValid()) { Log.w(VIEW_LOG_TAG, "startDragAndDrop called with an invalid surface."); return false; } if ((flags & DRAG_FLAG_GLOBAL) != 0 && ((flags & DRAG_FLAG_GLOBAL_SAME_APPLICATION) != 0)) { Log.w(VIEW_LOG_TAG, "startDragAndDrop called with both DRAG_FLAG_GLOBAL " + "and DRAG_FLAG_GLOBAL_SAME_APPLICATION, the drag will default to " + "DRAG_FLAG_GLOBAL_SAME_APPLICATION"); flags &= ~DRAG_FLAG_GLOBAL; } if (data != null) { if (com.android.window.flags.Flags.delegateUnhandledDrags()) { data.prepareToLeaveProcess( (flags & (DRAG_FLAG_GLOBAL_SAME_APPLICATION | DRAG_FLAG_GLOBAL)) != 0); if ((flags & DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG) != 0) { if (!hasActivityPendingIntents(data)) { flags &= ~DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG; Log.w(VIEW_LOG_TAG, "startDragAndDrop called with " + "DRAG_FLAG_START_INTENT_ON_UNHANDLED_DRAG but the clip data " + "contains non-activity PendingIntents"); } } } else { data.prepareToLeaveProcess((flags & DRAG_FLAG_GLOBAL) != 0); } } Rect bounds = new Rect(); getBoundsOnScreen(bounds, true); Point lastTouchPoint = new Point(); mAttachInfo.mViewRootImpl.getLastTouchPoint(lastTouchPoint); final ViewRootImpl root = mAttachInfo.mViewRootImpl; final boolean a11yEnabled = AccessibilityManager.getInstance(mContext).isEnabled(); if (a11yEnabled && (flags & View.DRAG_FLAG_ACCESSIBILITY_ACTION) != 0) { try { IBinder token = mAttachInfo.mSession.performDrag( mAttachInfo.mWindow, flags, null, mAttachInfo.mViewRootImpl.getLastTouchSource(), mAttachInfo.mViewRootImpl.getLastTouchDeviceId(), mAttachInfo.mViewRootImpl.getLastTouchPointerId(), 0f, 0f, 0f, 0f, data); if (ViewDebug.DEBUG_DRAG) { Log.d(VIEW_LOG_TAG, "startDragAndDrop via a11y action returned " + token); } if (token != null) { root.setLocalDragState(myLocalState); mAttachInfo.mDragToken = token; mAttachInfo.mDragData = data; mAttachInfo.mViewRootImpl.setDragStartedViewForAccessibility(this); setAccessibilityDragStarted(true); } return token != null; } catch (Exception e) { Log.e(VIEW_LOG_TAG, "Unable to initiate a11y drag", e); return false; } } Point shadowSize = new Point(); Point shadowTouchPoint = new Point(); shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); if ((shadowSize.x < 0) || (shadowSize.y < 0) || (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { throw new IllegalStateException("Drag shadow dimensions must not be negative"); } final float overrideInvScale = CompatibilityInfo.getOverrideInvertedScale(); if (overrideInvScale != 1f) { shadowTouchPoint.x = (int) (shadowTouchPoint.x / overrideInvScale); shadowTouchPoint.y = (int) (shadowTouchPoint.y / overrideInvScale); } if (shadowSize.x == 0 || shadowSize.y == 0) { if (!sAcceptZeroSizeDragShadow) { throw new IllegalStateException("Drag shadow dimensions must be positive"); } shadowSize.x = 1; shadowSize.y = 1; } if (ViewDebug.DEBUG_DRAG) { Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); } final SurfaceSession session = new SurfaceSession(); final SurfaceControl surfaceControl = new SurfaceControl.Builder(session) .setName("drag surface") .setParent(root.getSurfaceControl()) .setBufferSize(shadowSize.x, shadowSize.y) .setFormat(PixelFormat.TRANSLUCENT) .setCallsite("View.startDragAndDrop") .build(); if (overrideInvScale != 1f) { final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction(); transaction.setMatrix(surfaceControl, 1 / overrideInvScale, 0, 0, 1 / overrideInvScale) .apply(); } final Surface surface = new Surface(); surface.copyFrom(surfaceControl); IBinder token = null; try { Trace.traceBegin(TRACE_TAG_VIEW, "startDragAndDrop#drawDragShadow"); final Canvas canvas = isHardwareAccelerated() ? surface.lockHardwareCanvas() : surface.lockCanvas(null); try { canvas.drawColor(0, PorterDuff.Mode.CLEAR); shadowBuilder.onDrawShadow(canvas); } finally { surface.unlockCanvasAndPost(canvas); Trace.traceEnd(TRACE_TAG_VIEW); } Trace.traceBegin(TRACE_TAG_VIEW, "startDragAndDrop#performDrag"); try { token = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, flags, surfaceControl, root.getLastTouchSource(), root.getLastTouchDeviceId(), root.getLastTouchPointerId(), lastTouchPoint.x, lastTouchPoint.y, shadowTouchPoint.x, shadowTouchPoint.y, data); if (ViewDebug.DEBUG_DRAG) { Log.d(VIEW_LOG_TAG, "performDrag returned " + token); } if (token != null) { if (mAttachInfo.mDragSurface != null) { mAttachInfo.mDragSurface.release(); } if (mAttachInfo.mDragData != null) { View.cleanUpPendingIntents(mAttachInfo.mDragData); } mAttachInfo.mDragSurface = surface; mAttachInfo.mDragToken = token; mAttachInfo.mDragData = data; root.setLocalDragState(myLocalState); if (a11yEnabled) { mAttachInfo.mViewRootImpl.setDragStartedViewForAccessibility(this); } } return token != null; } finally { Trace.traceEnd(TRACE_TAG_VIEW); } } catch (Exception e) { Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); return false; } finally { if (token == null) { surface.destroy(); } session.kill(); surfaceControl.release(); } } static boolean hasActivityPendingIntents(ClipData data) { final int size = data.getItemCount(); for (int i = 0; i < size; i++) { final ClipData.Item item = data.getItemAt(i); if (item.getIntentSender() != null) { final PendingIntent pi = new PendingIntent(item.getIntentSender().getTarget()); if (pi.isActivity()) { return true; } } } return false; } static void cleanUpPendingIntents(ClipData data) { final int size = data.getItemCount(); for (int i = 0; i < size; i++) { final ClipData.Item item = data.getItemAt(i); if (item.getIntentSender() != null) { final PendingIntent pi = new PendingIntent(item.getIntentSender().getTarget()); pi.cancel(); } } } void setAccessibilityDragStarted(boolean started) { int pflags4 = mPrivateFlags4; if (started) { pflags4 |= PFLAG4_DRAG_A11Y_STARTED; } else { pflags4 &= ~PFLAG4_DRAG_A11Y_STARTED; } if (pflags4 != mPrivateFlags4) { mPrivateFlags4 = pflags4; sendWindowContentChangedAccessibilityEvent(CONTENT_CHANGE_TYPE_UNDEFINED); } } private boolean startedSystemDragForAccessibility() { return (mPrivateFlags4 & PFLAG4_DRAG_A11Y_STARTED) != 0; } public final void cancelDragAndDrop() { if (ViewDebug.DEBUG_DRAG) { Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); } if (mAttachInfo == null) { Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); return; } if (mAttachInfo.mDragToken != null) { try { mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken, false); } catch (Exception e) { Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); } mAttachInfo.mDragToken = null; } else { Log.e(VIEW_LOG_TAG, "No active drag to cancel"); } } public final void updateDragShadow(DragShadowBuilder shadowBuilder) { if (ViewDebug.DEBUG_DRAG) { Log.d(VIEW_LOG_TAG, "updateDragShadow"); } if (mAttachInfo == null) { Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); return; } if (mAttachInfo.mDragToken != null) { try { Canvas canvas = isHardwareAccelerated() ? mAttachInfo.mDragSurface.lockHardwareCanvas() : mAttachInfo.mDragSurface.lockCanvas(null); try { canvas.drawColor(0, PorterDuff.Mode.CLEAR); shadowBuilder.onDrawShadow(canvas); } finally { mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); } } catch (Exception e) { Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); } } else { Log.e(VIEW_LOG_TAG, "No active drag"); } } public final boolean startMovingTask(float startX, float startY) { if (ViewDebug.DEBUG_POSITIONING) { Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); } try { return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); } catch (RemoteException e) { Log.e(VIEW_LOG_TAG, "Unable to start moving", e); } return false; } public void finishMovingTask() { if (ViewDebug.DEBUG_POSITIONING) { Log.d(VIEW_LOG_TAG, "finishMovingTask"); } try { mAttachInfo.mSession.finishMovingTask(mAttachInfo.mWindow); } catch (RemoteException e) { Log.e(VIEW_LOG_TAG, "Unable to finish moving", e); } } public boolean onDragEvent(DragEvent event) { if (mListenerInfo == null || mListenerInfo.mOnReceiveContentListener == null) { return false; } if (event.getAction() == DragEvent.ACTION_DRAG_STARTED) { return true; } if (event.getAction() == DragEvent.ACTION_DROP) { final DragAndDropPermissions permissions = DragAndDropPermissions.obtain(event); if (permissions != null) { permissions.takeTransient(); } final ContentInfo payload = new ContentInfo.Builder(event.getClipData(), SOURCE_DRAG_AND_DROP) .setDragAndDropPermissions(permissions) .build(); ContentInfo remainingPayload = performReceiveContent(payload); return remainingPayload != payload; } return false; } boolean dispatchDragEnterExitInPreN(DragEvent event) { return callDragEventHandler(event); } public boolean dispatchDragEvent(DragEvent event) { event.mEventHandlerWasCalled = true; if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || event.mAction == DragEvent.ACTION_DROP) { getViewRootImpl().setDragFocus(this, event); } return callDragEventHandler(event); } final boolean callDragEventHandler(DragEvent event) { final boolean result; ListenerInfo li = mListenerInfo; if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnDragListener.onDrag(this, event)) { result = true; } else { result = onDragEvent(event); } switch (event.mAction) { case DragEvent.ACTION_DRAG_STARTED: { if (result && li != null && li.mOnDragListener != null) { sendWindowContentChangedAccessibilityEvent( AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } } break; case DragEvent.ACTION_DRAG_ENTERED: { mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; refreshDrawableState(); } break; case DragEvent.ACTION_DRAG_EXITED: { mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; refreshDrawableState(); } break; case DragEvent.ACTION_DROP: { if (result && li != null && (li.mOnDragListener != null || li.mOnReceiveContentListener != null)) { sendWindowContentChangedAccessibilityEvent( AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_DROPPED); } } break; case DragEvent.ACTION_DRAG_ENDED: { sendWindowContentChangedAccessibilityEvent( AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); mPrivateFlags2 &= ~View.DRAG_MASK; refreshDrawableState(); } break; } return result; } boolean canAcceptDrag() { return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; } void sendWindowContentChangedAccessibilityEvent(int changeType) { if (AccessibilityManager.getInstance(mContext).isEnabled()) { AccessibilityEvent event = AccessibilityEvent.obtain(); event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); event.setContentChangeTypes(changeType); sendAccessibilityEventUnchecked(event); } } @UnsupportedAppUsage public void onCloseSystemDialogs(String reason) { } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void applyDrawableToTransparentRegion(Drawable dr, Region region) { if (DBG) { Log.i("View", "Getting transparent region for: " + this); } final Region r = dr.getTransparentRegion(); final Rect db = dr.getBounds(); final AttachInfo attachInfo = mAttachInfo; if (r != null && attachInfo != null) { final int w = getRight()-getLeft(); final int h = getBottom()-getTop(); if (db.left > 0) { r.op(0, 0, db.left, h, Region.Op.UNION); } if (db.right < w) { r.op(db.right, 0, w, h, Region.Op.UNION); } if (db.top > 0) { r.op(0, 0, w, db.top, Region.Op.UNION); } if (db.bottom < h) { r.op(0, db.bottom, w, h, Region.Op.UNION); } final int[] location = attachInfo.mTransparentLocation; getLocationInWindow(location); r.translate(location[0], location[1]); region.op(r, Region.Op.INTERSECT); } else { region.op(db, Region.Op.DIFFERENCE); } } private void checkForLongClick(long delay, float x, float y, int classification) { if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { mHasPerformedLongPress = false; if (mPendingCheckForLongPress == null) { mPendingCheckForLongPress = new CheckForLongPress(); } mPendingCheckForLongPress.setAnchor(x, y); mPendingCheckForLongPress.rememberWindowAttachCount(); mPendingCheckForLongPress.rememberPressedState(); mPendingCheckForLongPress.setClassification(classification); postDelayed(mPendingCheckForLongPress, delay); } } public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { LayoutInflater factory = LayoutInflater.from(context); return factory.inflate(resource, root); } @SuppressWarnings({"UnusedParameters"}) protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) { final int overScrollMode = mOverScrollMode; final boolean canScrollHorizontal = computeHorizontalScrollRange() > computeHorizontalScrollExtent(); final boolean canScrollVertical = computeVerticalScrollRange() > computeVerticalScrollExtent(); final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); int newScrollX = scrollX + deltaX; if (!overScrollHorizontal) { maxOverScrollX = 0; } int newScrollY = scrollY + deltaY; if (!overScrollVertical) { maxOverScrollY = 0; } final int left = -maxOverScrollX; final int right = maxOverScrollX + scrollRangeX; final int top = -maxOverScrollY; final int bottom = maxOverScrollY + scrollRangeY; boolean clampedX = false; if (newScrollX > right) { newScrollX = right; clampedX = true; } else if (newScrollX < left) { newScrollX = left; clampedX = true; } boolean clampedY = false; if (newScrollY > bottom) { newScrollY = bottom; clampedY = true; } else if (newScrollY < top) { newScrollY = top; clampedY = true; } onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); return clampedX || clampedY; } protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) { } @InspectableProperty(enumMapping = { @EnumEntry(value = OVER_SCROLL_ALWAYS, name = "always"), @EnumEntry(value = OVER_SCROLL_IF_CONTENT_SCROLLS, name = "ifContentScrolls"), @EnumEntry(value = OVER_SCROLL_NEVER, name = "never") }) public int getOverScrollMode() { return mOverScrollMode; } public void setOverScrollMode(int overScrollMode) { if (overScrollMode != OVER_SCROLL_ALWAYS && overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && overScrollMode != OVER_SCROLL_NEVER) { throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); } mOverScrollMode = overScrollMode; } public void setNestedScrollingEnabled(boolean enabled) { if (enabled) { mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; } else { stopNestedScroll(); mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; } } @InspectableProperty public boolean isNestedScrollingEnabled() { return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == PFLAG3_NESTED_SCROLLING_ENABLED; } public boolean startNestedScroll(int axes) { if (hasNestedScrollingParent()) { return true; } if (isNestedScrollingEnabled()) { ViewParent p = getParent(); View child = this; while (p != null) { try { if (p.onStartNestedScroll(child, this, axes)) { mNestedScrollingParent = p; p.onNestedScrollAccepted(child, this, axes); return true; } } catch (AbstractMethodError e) { Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + "method onStartNestedScroll", e); } if (p instanceof View) { child = (View) p; } p = p.getParent(); } } return false; } public void stopNestedScroll() { if (mNestedScrollingParent != null) { mNestedScrollingParent.onStopNestedScroll(this); mNestedScrollingParent = null; } } public boolean hasNestedScrollingParent() { return mNestedScrollingParent != null; } public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { int startX = 0; int startY = 0; if (offsetInWindow != null) { getLocationInWindow(offsetInWindow); startX = offsetInWindow[0]; startY = offsetInWindow[1]; } mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed); if (offsetInWindow != null) { getLocationInWindow(offsetInWindow); offsetInWindow[0] -= startX; offsetInWindow[1] -= startY; } return true; } else if (offsetInWindow != null) { offsetInWindow[0] = 0; offsetInWindow[1] = 0; } } return false; } public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { if (dx != 0 || dy != 0) { int startX = 0; int startY = 0; if (offsetInWindow != null) { getLocationInWindow(offsetInWindow); startX = offsetInWindow[0]; startY = offsetInWindow[1]; } if (consumed == null) { if (mTempNestedScrollConsumed == null) { mTempNestedScrollConsumed = new int[2]; } consumed = mTempNestedScrollConsumed; } consumed[0] = 0; consumed[1] = 0; mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); if (offsetInWindow != null) { getLocationInWindow(offsetInWindow); offsetInWindow[0] -= startX; offsetInWindow[1] -= startY; } return consumed[0] != 0 || consumed[1] != 0; } else if (offsetInWindow != null) { offsetInWindow[0] = 0; offsetInWindow[1] = 0; } } return false; } public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); } return false; } public boolean dispatchNestedPreFling(float velocityX, float velocityY) { if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); } return false; } @UnsupportedAppUsage protected float getVerticalScrollFactor() { if (mVerticalScrollFactor == 0) { TypedValue outValue = new TypedValue(); if (!mContext.getTheme().resolveAttribute( com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { throw new IllegalStateException( "Expected theme to define listPreferredItemHeight."); } mVerticalScrollFactor = outValue.getDimension( mContext.getResources().getDisplayMetrics()); } return mVerticalScrollFactor; } @UnsupportedAppUsage protected float getHorizontalScrollFactor() { return getVerticalScrollFactor(); } @ViewDebug.ExportedProperty(category = "text", mapping = { @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") }) @InspectableProperty(hasAttributeId = false, enumMapping = { @EnumEntry(value = TEXT_DIRECTION_INHERIT, name = "inherit"), @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), }) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public int getRawTextDirection() { return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; } public void setTextDirection(int textDirection) { if (getRawTextDirection() != textDirection) { mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; resetResolvedTextDirection(); mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); resolveTextDirection(); onRtlPropertiesChanged(getLayoutDirection()); requestLayout(); invalidate(true); } } @ViewDebug.ExportedProperty(category = "text", mapping = { @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") }) @InspectableProperty(hasAttributeId = false, enumMapping = { @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), }) public int getTextDirection() { return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; } public boolean resolveTextDirection() { mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); if (hasRtlSupport()) { final int textDirection = getRawTextDirection(); switch(textDirection) { case TEXT_DIRECTION_INHERIT: if (!canResolveTextDirection()) { mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; return false; } try { if (!mParent.isTextDirectionResolved()) { mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; return false; } } catch (AbstractMethodError e) { Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + " does not fully implement ViewParent", e); mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; return true; } int parentResolvedDirection; try { parentResolvedDirection = mParent.getTextDirection(); } catch (AbstractMethodError e) { Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + " does not fully implement ViewParent", e); parentResolvedDirection = TEXT_DIRECTION_LTR; } switch (parentResolvedDirection) { case TEXT_DIRECTION_FIRST_STRONG: case TEXT_DIRECTION_ANY_RTL: case TEXT_DIRECTION_LTR: case TEXT_DIRECTION_RTL: case TEXT_DIRECTION_LOCALE: case TEXT_DIRECTION_FIRST_STRONG_LTR: case TEXT_DIRECTION_FIRST_STRONG_RTL: mPrivateFlags2 |= (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); break; default: mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; } break; case TEXT_DIRECTION_FIRST_STRONG: case TEXT_DIRECTION_ANY_RTL: case TEXT_DIRECTION_LTR: case TEXT_DIRECTION_RTL: case TEXT_DIRECTION_LOCALE: case TEXT_DIRECTION_FIRST_STRONG_LTR: case TEXT_DIRECTION_FIRST_STRONG_RTL: mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); break; default: mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; } } else { mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; } mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; return true; } public boolean canResolveTextDirection() { switch (getRawTextDirection()) { case TEXT_DIRECTION_INHERIT: if (mParent != null) { try { return mParent.canResolveTextDirection(); } catch (AbstractMethodError e) { Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + " does not fully implement ViewParent", e); } } return false; default: return true; } } @TestApi public void resetResolvedTextDirection() { mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; } public boolean isTextDirectionInherited() { return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); } public boolean isTextDirectionResolved() { return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; } @ViewDebug.ExportedProperty(category = "text", mapping = { @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") }) @InspectableProperty(hasAttributeId = false, enumMapping = { @EnumEntry(value = TEXT_ALIGNMENT_INHERIT, name = "inherit"), @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") }) @TextAlignment @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public int getRawTextAlignment() { return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; } public void setTextAlignment(@TextAlignment int textAlignment) { if (textAlignment != getRawTextAlignment()) { mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; resetResolvedTextAlignment(); mPrivateFlags2 |= ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); resolveTextAlignment(); onRtlPropertiesChanged(getLayoutDirection()); requestLayout(); invalidate(true); } } @ViewDebug.ExportedProperty(category = "text", mapping = { @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") }) @InspectableProperty(enumMapping = { @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") }) @TextAlignment public int getTextAlignment() { return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; } public boolean resolveTextAlignment() { mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); if (hasRtlSupport()) { final int textAlignment = getRawTextAlignment(); switch (textAlignment) { case TEXT_ALIGNMENT_INHERIT: if (!canResolveTextAlignment()) { mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; return false; } try { if (!mParent.isTextAlignmentResolved()) { mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; return false; } } catch (AbstractMethodError e) { Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + " does not fully implement ViewParent", e); mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; return true; } int parentResolvedTextAlignment; try { parentResolvedTextAlignment = mParent.getTextAlignment(); } catch (AbstractMethodError e) { Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + " does not fully implement ViewParent", e); parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; } switch (parentResolvedTextAlignment) { case TEXT_ALIGNMENT_GRAVITY: case TEXT_ALIGNMENT_TEXT_START: case TEXT_ALIGNMENT_TEXT_END: case TEXT_ALIGNMENT_CENTER: case TEXT_ALIGNMENT_VIEW_START: case TEXT_ALIGNMENT_VIEW_END: mPrivateFlags2 |= (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); break; default: mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; } break; case TEXT_ALIGNMENT_GRAVITY: case TEXT_ALIGNMENT_TEXT_START: case TEXT_ALIGNMENT_TEXT_END: case TEXT_ALIGNMENT_CENTER: case TEXT_ALIGNMENT_VIEW_START: case TEXT_ALIGNMENT_VIEW_END: mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); break; default: mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; } } else { mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; } mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; return true; } public boolean canResolveTextAlignment() { switch (getRawTextAlignment()) { case TEXT_DIRECTION_INHERIT: if (mParent != null) { try { return mParent.canResolveTextAlignment(); } catch (AbstractMethodError e) { Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + " does not fully implement ViewParent", e); } } return false; default: return true; } } @TestApi public void resetResolvedTextAlignment() { mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; } public boolean isTextAlignmentInherited() { return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); } public boolean isTextAlignmentResolved() { return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; } public static int generateViewId() { for (;;) { final int result = sNextGeneratedId.get(); int newValue = result + 1; if (newValue > 0x00FFFFFF) newValue = 1; if (sNextGeneratedId.compareAndSet(result, newValue)) { return result; } } } private static boolean isViewIdGenerated(int id) { return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0; } public void captureTransitioningViews(List<View> transitioningViews) { if (getVisibility() == View.VISIBLE) { transitioningViews.add(this); } } public void findNamedViews(Map<String, View> namedElements) { if (getVisibility() == VISIBLE || mGhostView != null) { String transitionName = getTransitionName(); if (transitionName != null) { namedElements.put(transitionName, this); } } } public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { final float x = event.getX(pointerIndex); final float y = event.getY(pointerIndex); if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { return null; } if (event.isFromSource(InputDevice.SOURCE_MOUSE)) { return mMousePointerIcon; } return null; } public void setPointerIcon(PointerIcon pointerIcon) { mMousePointerIcon = pointerIcon; final ViewRootImpl viewRootImpl = getViewRootImpl(); if (viewRootImpl == null) { return; } viewRootImpl.refreshPointerIcon(); } @InspectableProperty public PointerIcon getPointerIcon() { return mMousePointerIcon; } public boolean hasPointerCapture() { final ViewRootImpl viewRootImpl = getViewRootImpl(); if (viewRootImpl == null) { return false; } return viewRootImpl.hasPointerCapture(); } public void requestPointerCapture() { final ViewRootImpl viewRootImpl = getViewRootImpl(); if (viewRootImpl != null) { viewRootImpl.requestPointerCapture(true); } } public void releasePointerCapture() { final ViewRootImpl viewRootImpl = getViewRootImpl(); if (viewRootImpl != null) { viewRootImpl.requestPointerCapture(false); } } @CallSuper public void onPointerCaptureChange(boolean hasCapture) { } public void dispatchPointerCaptureChanged(boolean hasCapture) { onPointerCaptureChange(hasCapture); } public boolean onCapturedPointerEvent(MotionEvent event) { return false; } public interface OnCapturedPointerListener { boolean onCapturedPointer(View view, MotionEvent event); } public void setOnCapturedPointerListener(OnCapturedPointerListener l) { getListenerInfo().mOnCapturedPointerListener = l; } public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { @Override public void setValue(View object, float value) { object.setAlpha(value); } @Override public Float get(View object) { return object.getAlpha(); } }; public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { @Override public void setValue(View object, float value) { object.setTranslationX(value); } @Override public Float get(View object) { return object.getTranslationX(); } }; public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { @Override public void setValue(View object, float value) { object.setTranslationY(value); } @Override public Float get(View object) { return object.getTranslationY(); } }; public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { @Override public void setValue(View object, float value) { object.setTranslationZ(value); } @Override public Float get(View object) { return object.getTranslationZ(); } }; public static final Property<View, Float> X = new FloatProperty<View>("x") { @Override public void setValue(View object, float value) { object.setX(value); } @Override public Float get(View object) { return object.getX(); } }; public static final Property<View, Float> Y = new FloatProperty<View>("y") { @Override public void setValue(View object, float value) { object.setY(value); } @Override public Float get(View object) { return object.getY(); } }; public static final Property<View, Float> Z = new FloatProperty<View>("z") { @Override public void setValue(View object, float value) { object.setZ(value); } @Override public Float get(View object) { return object.getZ(); } }; public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { @Override public void setValue(View object, float value) { object.setRotation(value); } @Override public Float get(View object) { return object.getRotation(); } }; public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { @Override public void setValue(View object, float value) { object.setRotationX(value); } @Override public Float get(View object) { return object.getRotationX(); } }; public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { @Override public void setValue(View object, float value) { object.setRotationY(value); } @Override public Float get(View object) { return object.getRotationY(); } }; public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { @Override public void setValue(View object, float value) { object.setScaleX(value); } @Override public Float get(View object) { return object.getScaleX(); } }; public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { @Override public void setValue(View object, float value) { object.setScaleY(value); } @Override public Float get(View object) { return object.getScaleY(); } }; public static class MeasureSpec { private static final int MODE_SHIFT = 30; private static final int MODE_MASK = 0x3 << MODE_SHIFT; @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) @Retention(RetentionPolicy.SOURCE) public @interface MeasureSpecMode {} public static final int UNSPECIFIED = 0 << MODE_SHIFT; public static final int EXACTLY = 1 << MODE_SHIFT; public static final int AT_MOST = 2 << MODE_SHIFT; public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, @MeasureSpecMode int mode) { return (size & ~MODE_MASK) | (mode & MODE_MASK); } @UnsupportedAppUsage public static int makeSafeMeasureSpec(int size, int mode) { return makeMeasureSpec(size, mode); } @MeasureSpecMode public static int getMode(int measureSpec) { return (measureSpec & MODE_MASK); } public static int getSize(int measureSpec) { return (measureSpec & ~MODE_MASK); } static int adjust(int measureSpec, int delta) { final int mode = getMode(measureSpec); int size = getSize(measureSpec); if (mode == UNSPECIFIED) { return makeMeasureSpec(size, UNSPECIFIED); } size += delta; if (size < 0) { Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + ") spec: " + toString(measureSpec) + " delta: " + delta); size = 0; } return makeMeasureSpec(size, mode); } public static String toString(int measureSpec) { int mode = getMode(measureSpec); int size = getSize(measureSpec); StringBuilder sb = new StringBuilder("MeasureSpec: "); if (mode == UNSPECIFIED) sb.append("UNSPECIFIED "); else if (mode == EXACTLY) sb.append("EXACTLY "); else if (mode == AT_MOST) sb.append("AT_MOST "); else sb.append(mode).append(" "); sb.append(size); return sb.toString(); } } private final class CheckForLongPress implements Runnable { private int mOriginalWindowAttachCount; private float mX; private float mY; private boolean mOriginalPressedState; private int mClassification; @UnsupportedAppUsage private CheckForLongPress() { } @Override public void run() { if ((mOriginalPressedState == isPressed()) && (mParent != null) && mOriginalWindowAttachCount == mWindowAttachCount) { recordGestureClassification(mClassification); if (performLongClick(mX, mY)) { mHasPerformedLongPress = true; } } } public void setAnchor(float x, float y) { mX = x; mY = y; } public void rememberWindowAttachCount() { mOriginalWindowAttachCount = mWindowAttachCount; } public void rememberPressedState() { mOriginalPressedState = isPressed(); } public void setClassification(int classification) { mClassification = classification; } } private final class CheckForTap implements Runnable { public float x; public float y; @Override public void run() { mPrivateFlags &= ~PFLAG_PREPRESSED; setPressed(true, x, y); final long delay = ViewConfiguration.getLongPressTimeout() - ViewConfiguration.getTapTimeout(); checkForLongClick(delay, x, y, TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); } } private final class PerformClick implements Runnable { @Override public void run() { recordGestureClassification(TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP); performClickInternal(); } } private void recordGestureClassification(int classification) { if (classification == TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION) { return; } FrameworkStatsLog.write(FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED, getClass().getName(), classification); } public ViewPropertyAnimator animate() { if (mAnimator == null) { mAnimator = new ViewPropertyAnimator(this); } return mAnimator; } public final void setTransitionName(String transitionName) { mTransitionName = transitionName; } @ViewDebug.ExportedProperty @InspectableProperty public String getTransitionName() { return mTransitionName; } public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { } public interface OnKeyListener { boolean onKey(View v, int keyCode, KeyEvent event); } public interface OnUnhandledKeyEventListener { boolean onUnhandledKeyEvent(View v, KeyEvent event); } public interface OnTouchListener { boolean onTouch(View v, MotionEvent event); } public interface OnHoverListener { boolean onHover(View v, MotionEvent event); } public interface OnGenericMotionListener { boolean onGenericMotion(View v, MotionEvent event); } public interface OnLongClickListener { boolean onLongClick(View v); default boolean onLongClickUseDefaultHapticFeedback(@NonNull View v) { return true; } } public interface OnDragListener { boolean onDrag(View v, DragEvent event); } public interface OnFocusChangeListener { void onFocusChange(View v, boolean hasFocus); } public interface OnClickListener { void onClick(View v); } public interface OnContextClickListener { boolean onContextClick(View v); } public interface OnCreateContextMenuListener { void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); } @Deprecated public interface OnSystemUiVisibilityChangeListener { public void onSystemUiVisibilityChange(int visibility); } public interface OnAttachStateChangeListener { public void onViewAttachedToWindow(@NonNull View v); public void onViewDetachedFromWindow(@NonNull View v); } public interface OnApplyWindowInsetsListener { public @NonNull WindowInsets onApplyWindowInsets(@NonNull View v, @NonNull WindowInsets insets); } private final class UnsetPressedState implements Runnable { @Override public void run() { setPressed(false); } } private static class VisibilityChangeForAutofillHandler extends Handler { private final AutofillManager mAfm; private final View mView; private VisibilityChangeForAutofillHandler(@NonNull AutofillManager afm, @NonNull View view) { mAfm = afm; mView = view; } @Override public void handleMessage(Message msg) { mAfm.notifyViewVisibilityChanged(mView, mView.isShown()); } } public static class BaseSavedState extends AbsSavedState { static final int START_ACTIVITY_REQUESTED_WHO_SAVED = 0b1; static final int IS_AUTOFILLED = 0b10; static final int AUTOFILL_ID = 0b100; int mSavedData; String mStartActivityRequestWhoSaved; boolean mIsAutofilled; boolean mHideHighlight; int mAutofillViewId; public BaseSavedState(Parcel source) { this(source, null); } public BaseSavedState(Parcel source, ClassLoader loader) { super(source, loader); mSavedData = source.readInt(); mStartActivityRequestWhoSaved = source.readString(); mIsAutofilled = source.readBoolean(); mHideHighlight = source.readBoolean(); mAutofillViewId = source.readInt(); } public BaseSavedState(Parcelable superState) { super(superState); } @Override public void writeToParcel(Parcel out, int flags) { super.writeToParcel(out, flags); out.writeInt(mSavedData); out.writeString(mStartActivityRequestWhoSaved); out.writeBoolean(mIsAutofilled); out.writeBoolean(mHideHighlight); out.writeInt(mAutofillViewId); } public static final @android.annotation.NonNull Parcelable.Creator<BaseSavedState> CREATOR = new Parcelable.ClassLoaderCreator<BaseSavedState>() { @Override public BaseSavedState createFromParcel(Parcel in) { return new BaseSavedState(in); } @Override public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { return new BaseSavedState(in, loader); } @Override public BaseSavedState[] newArray(int size) { return new BaseSavedState[size]; } }; } final static class AttachInfo { interface Callbacks { void playSoundEffect(int effectId); boolean performHapticFeedback(int effectId, boolean always, boolean fromIme); } static class InvalidateInfo { @UnsupportedAppUsage InvalidateInfo() { } private static final int POOL_LIMIT = 10; private static final SynchronizedPool<InvalidateInfo> sPool = new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); @UnsupportedAppUsage View target; @UnsupportedAppUsage int left; @UnsupportedAppUsage int top; @UnsupportedAppUsage int right; @UnsupportedAppUsage int bottom; public static InvalidateInfo obtain() { InvalidateInfo instance = sPool.acquire(); return (instance != null) ? instance : new InvalidateInfo(); } public void recycle() { target = null; sPool.release(this); } } @UnsupportedAppUsage final IWindowSession mSession; @UnsupportedAppUsage final IWindow mWindow; final IBinder mWindowToken; Display mDisplay; final Callbacks mRootCallbacks; IWindowId mIWindowId; WindowId mWindowId; View mRootView; IBinder mPanelParentWindowToken; boolean mHardwareAccelerated; boolean mHardwareAccelerationRequested; ThreadedRenderer mThreadedRenderer; List<RenderNode> mPendingAnimatingRenderNodes; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) int mDisplayState = Display.STATE_UNKNOWN; @UnsupportedAppUsage float mApplicationScale; @UnsupportedAppUsage boolean mScalingRequired; int mWindowLeft; int mWindowTop; boolean mUse32BitDrawingCache; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") final Rect mContentInsets = new Rect(); @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") final Rect mVisibleInsets = new Rect(); @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") final Rect mStableInsets = new Rect(); final Rect mCaptionInsets = new Rect(); boolean mAlwaysConsumeSystemBars; @UnsupportedAppUsage final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets = new ViewTreeObserver.InternalInsetsInfo(); boolean mHasNonEmptyGivenInternalInsets; @UnsupportedAppUsage final ArrayList<View> mScrollContainers = new ArrayList<View>(); @UnsupportedAppUsage final KeyEvent.DispatcherState mKeyDispatchState = new KeyEvent.DispatcherState(); @UnsupportedAppUsage boolean mHasWindowFocus; int mWindowVisibility; @UnsupportedAppUsage long mDrawingTime; @UnsupportedAppUsage boolean mInTouchMode; boolean mUnbufferedDispatchRequested; @UnsupportedAppUsage boolean mRecomputeGlobalAttributes; boolean mForceReportNewAttributes; @UnsupportedAppUsage boolean mKeepScreenOn; boolean mNeedsUpdateLightCenter; int mSystemUiVisibility; int mDisabledSystemUiVisibility; boolean mHasSystemUiListeners; @UnsupportedAppUsage boolean mViewVisibilityChanged; @UnsupportedAppUsage boolean mViewScrollChanged; boolean mHandlingPointerEvent; Matrix mWindowMatrixInEmbeddedHierarchy; final int[] mTransparentLocation = new int[2]; final int[] mInvalidateChildLocation = new int[2]; final int[] mTmpLocation = new int[2]; final float[] mTmpTransformLocation = new float[2]; @UnsupportedAppUsage final ViewTreeObserver mTreeObserver; Canvas mCanvas; final ViewRootImpl mViewRootImpl; @UnsupportedAppUsage final Handler mHandler; final Rect mTmpInvalRect = new Rect(); final RectF mTmpTransformRect = new RectF(); final RectF mTmpTransformRect1 = new RectF(); final List<RectF> mTmpRectList = new ArrayList<>(); final Matrix mTmpMatrix = new Matrix(); final Transformation mTmpTransformation = new Transformation(); final Outline mTmpOutline = new Outline(); final ArrayList<View> mTempArrayList = new ArrayList<View>(24); boolean mNextFocusLooped = false; int mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; int mAccessibilityFetchFlags; Drawable mAccessibilityFocusDrawable; Drawable mAutofilledDrawable; boolean mDebugLayout = DisplayProperties.debug_layout().orElse(false); final Point mPoint = new Point(); View mViewRequestingLayout; IBinder mDragToken; ClipData mDragData; public Surface mDragSurface; View mTooltipHost; boolean mReadyForContentCaptureUpdates; SparseArray<ArrayList<Object>> mContentCaptureEvents; ContentCaptureManager mContentCaptureManager; OnContentApplyWindowInsetsListener mContentOnApplyWindowInsetsListener; IBinder mLeashedParentToken; int mLeashedParentAccessibilityViewId; ScrollCaptureInternal mScrollCaptureInternal; int mSensitiveViewsCount; final boolean mViewVelocityApi = viewVelocityApi(); final float mDensity; final float mDisplayPixelCount; AttachInfo(IWindowSession session, IWindow window, Display display, ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, Context context) { mSession = session; mWindow = window; mWindowToken = window.asBinder(); mDisplay = display; mViewRootImpl = viewRootImpl; mHandler = handler; mRootCallbacks = effectPlayer; mTreeObserver = new ViewTreeObserver(context); DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); mDensity = displayMetrics.density; mDisplayPixelCount = pixelCount == 0f ? Float.POSITIVE_INFINITY : pixelCount; } void increaseSensitiveViewsCount() { if (mSensitiveViewsCount == 0) { mViewRootImpl.addSensitiveContentAppProtection(); } mSensitiveViewsCount++; } void decreaseSensitiveViewsCount() { mSensitiveViewsCount--; if (mSensitiveViewsCount == 0) { mViewRootImpl.removeSensitiveContentAppProtection(); } if (mSensitiveViewsCount < 0) { Log.wtf(VIEW_LOG_TAG, "mSensitiveViewsCount is negative" + mSensitiveViewsCount); mSensitiveViewsCount = 0; } } @Nullable ContentCaptureManager getContentCaptureManager(@NonNull Context context) { if (mContentCaptureManager != null) { return mContentCaptureManager; } mContentCaptureManager = context.getSystemService(ContentCaptureManager.class); return mContentCaptureManager; } void delayNotifyContentCaptureInsetsEvent(@NonNull Insets insets) { if (mContentCaptureManager == null) { return; } ArrayList<Object> events = ensureEvents( mContentCaptureManager.getMainContentCaptureSession()); events.add(insets); } private void delayNotifyContentCaptureEvent(@NonNull ContentCaptureSession session, @NonNull View view, boolean appeared) { ArrayList<Object> events = ensureEvents(session); events.add(appeared ? view : view.getAutofillId()); } @NonNull private ArrayList<Object> ensureEvents(@NonNull ContentCaptureSession session) { if (mContentCaptureEvents == null) { mContentCaptureEvents = new SparseArray<>(1); } int sessionId = session.getId(); ArrayList<Object> events = mContentCaptureEvents.get(sessionId); if (events == null) { events = new ArrayList<>(); mContentCaptureEvents.put(sessionId, events); } return events; } private boolean canPerformHapticFeedback() { return mSession != null && (mDisplay.getFlags() & Display.FLAG_TOUCH_FEEDBACK_DISABLED) == 0; } @Nullable ScrollCaptureInternal getScrollCaptureInternal() { if (mScrollCaptureInternal != null) { mScrollCaptureInternal = new ScrollCaptureInternal(); } return mScrollCaptureInternal; } AttachedSurfaceControl getRootSurfaceControl() { return mViewRootImpl; } public void dump(String prefix, PrintWriter writer) { String innerPrefix = prefix + " "; writer.println(prefix + "AttachInfo:"); writer.println(innerPrefix + "mHasWindowFocus=" + mHasWindowFocus); writer.println(innerPrefix + "mWindowVisibility=" + mWindowVisibility); writer.println(innerPrefix + "mInTouchMode=" + mInTouchMode); writer.println(innerPrefix + "mUnbufferedDispatchRequested=" + mUnbufferedDispatchRequested); } } private static class ScrollabilityCache implements Runnable { public static final int OFF = 0; public static final int ON = 1; public static final int FADING = 2; public boolean fadeScrollBars; public int fadingEdgeLength; public int scrollBarDefaultDelayBeforeFade; public int scrollBarFadeDuration; public int scrollBarSize; public int scrollBarMinTouchTarget; @UnsupportedAppUsage public ScrollBarDrawable scrollBar; public float[] interpolatorValues; @UnsupportedAppUsage public View host; public final Paint paint; public final Matrix matrix; public Shader shader; public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); private static final float[] OPAQUE = { 255 }; private static final float[] TRANSPARENT = { 0.0f }; public long fadeStartTime; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public int state = OFF; private int mLastColor; public final Rect mScrollBarBounds = new Rect(); public final Rect mScrollBarTouchBounds = new Rect(); public static final int NOT_DRAGGING = 0; public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; public int mScrollBarDraggingState = NOT_DRAGGING; public float mScrollBarDraggingPos = 0; public ScrollabilityCache(ViewConfiguration configuration, View host) { fadingEdgeLength = configuration.getScaledFadingEdgeLength(); scrollBarSize = configuration.getScaledScrollBarSize(); scrollBarMinTouchTarget = configuration.getScaledMinScrollbarTouchTarget(); scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); paint = new Paint(); matrix = new Matrix(); shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); paint.setShader(shader); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); this.host = host; } public void setFadeColor(int color) { if (color != mLastColor) { mLastColor = color; if (color != 0) { shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, color & 0x00FFFFFF, Shader.TileMode.CLAMP); paint.setShader(shader); paint.setXfermode(null); } else { shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); paint.setShader(shader); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); } } } public void run() { long now = AnimationUtils.currentAnimationTimeMillis(); if (now >= fadeStartTime) { int nextFrame = (int) now; int framesCount = 0; Interpolator interpolator = scrollBarInterpolator; interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); nextFrame += scrollBarFadeDuration; interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); state = FADING; host.invalidate(true); } } } private class SendAccessibilityEventThrottle implements Runnable { public volatile boolean mIsPending; private AccessibilityEvent mAccessibilityEvent; public void post(AccessibilityEvent accessibilityEvent) { updateWithAccessibilityEvent(accessibilityEvent); if (!mIsPending) { mIsPending = true; postDelayed(this, ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); } } @Override public void run() { if (AccessibilityManager.getInstance(mContext).isEnabled() && isShown()) { requestParentSendAccessibilityEvent(mAccessibilityEvent); } reset(); } public void updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent) { mAccessibilityEvent = accessibilityEvent; } public void reset() { mIsPending = false; mAccessibilityEvent = null; } } private class SendViewScrolledAccessibilityEvent extends SendAccessibilityEventThrottle { public int mDeltaX; public int mDeltaY; @Override public void updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent) { super.updateWithAccessibilityEvent(accessibilityEvent); mDeltaX += accessibilityEvent.getScrollDeltaX(); mDeltaY += accessibilityEvent.getScrollDeltaY(); accessibilityEvent.setScrollDeltaX(mDeltaX); accessibilityEvent.setScrollDeltaY(mDeltaY); } @Override public void reset() { super.reset(); mDeltaX = 0; mDeltaY = 0; } } @UnsupportedAppUsage private void cancel(@Nullable SendAccessibilityEventThrottle callback) { if (callback == null || !callback.mIsPending) return; removeCallbacks(callback); callback.reset(); } public static class AccessibilityDelegate { public void sendAccessibilityEvent(@NonNull View host, int eventType) { host.sendAccessibilityEventInternal(eventType); } public boolean performAccessibilityAction(@NonNull View host, int action, @Nullable Bundle args) { return host.performAccessibilityActionInternal(action, args); } public void sendAccessibilityEventUnchecked(@NonNull View host, @NonNull AccessibilityEvent event) { host.sendAccessibilityEventUncheckedInternal(event); } public boolean dispatchPopulateAccessibilityEvent(@NonNull View host, @NonNull AccessibilityEvent event) { return host.dispatchPopulateAccessibilityEventInternal(event); } public void onPopulateAccessibilityEvent(@NonNull View host, @NonNull AccessibilityEvent event) { host.onPopulateAccessibilityEventInternal(event); } public void onInitializeAccessibilityEvent(@NonNull View host, @NonNull AccessibilityEvent event) { host.onInitializeAccessibilityEventInternal(event); } public void onInitializeAccessibilityNodeInfo(@NonNull View host, @NonNull AccessibilityNodeInfo info) { host.onInitializeAccessibilityNodeInfoInternal(info); } public void addExtraDataToAccessibilityNodeInfo(@NonNull View host, @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, @Nullable Bundle arguments) { host.addExtraDataToAccessibilityNodeInfo(info, extraDataKey, arguments); } public boolean onRequestSendAccessibilityEvent(@NonNull ViewGroup host, @NonNull View child, @NonNull AccessibilityEvent event) { return host.onRequestSendAccessibilityEventInternal(child, event); } public @Nullable AccessibilityNodeProvider getAccessibilityNodeProvider( @NonNull View host) { return null; } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public AccessibilityNodeInfo createAccessibilityNodeInfo(@NonNull View host) { return host.createAccessibilityNodeInfoInternal(); } } private static class MatchIdPredicate implements Predicate<View> { public int mId; @Override public boolean test(View view) { return (view.mID == mId); } } private static class MatchLabelForPredicate implements Predicate<View> { private int mLabeledId; @Override public boolean test(View view) { return (view.mLabelForId == mLabeledId); } } private static class SensitiveAutofillHintsHelper { private static final ArraySet<String> SENSITIVE_CONTENT_AUTOFILL_HINTS = new ArraySet<>(); static { SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_USERNAME); SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_PASSWORD_AUTO); SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_PASSWORD); SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_CREDIT_CARD_NUMBER); SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE); SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE); SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY); SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH); SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR); SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_CREDENTIAL_MANAGER); } static boolean containsSensitiveAutofillHint(@Nullable String[] autofillHints) { if (autofillHints == null) { return false; } int size = autofillHints.length; for (int i = 0; i < size; i++) { if (SENSITIVE_CONTENT_AUTOFILL_HINTS.contains(autofillHints[i])) { return true; } } return false; } } @ScrollCaptureHint public int getScrollCaptureHint() { return (mPrivateFlags4 & PFLAG4_SCROLL_CAPTURE_HINT_MASK) >> PFLAG4_SCROLL_CAPTURE_HINT_SHIFT; } public void setScrollCaptureHint(@ScrollCaptureHint int hint) { mPrivateFlags4 &= ~PFLAG4_SCROLL_CAPTURE_HINT_MASK; if ((hint & SCROLL_CAPTURE_HINT_EXCLUDE) != 0) { hint &= ~SCROLL_CAPTURE_HINT_INCLUDE; } mPrivateFlags4 |= ((hint << PFLAG4_SCROLL_CAPTURE_HINT_SHIFT) & PFLAG4_SCROLL_CAPTURE_HINT_MASK); } public final void setScrollCaptureCallback(@Nullable ScrollCaptureCallback callback) { getListenerInfo().mScrollCaptureCallback = callback; } @Nullable public ScrollCaptureCallback createScrollCaptureCallbackInternal(@NonNull Rect localVisibleRect, @NonNull Point windowOffset) { if (mAttachInfo == null) { return null; } if (mAttachInfo.mScrollCaptureInternal == null) { mAttachInfo.mScrollCaptureInternal = new ScrollCaptureInternal(); } return mAttachInfo.mScrollCaptureInternal.requestCallback(this, localVisibleRect, windowOffset); } public void dispatchScrollCaptureSearch( @NonNull Rect localVisibleRect, @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets) { onScrollCaptureSearch(localVisibleRect, windowOffset, targets); } public void onScrollCaptureSearch(@NonNull Rect localVisibleRect, @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets) { int hint = getScrollCaptureHint(); if ((hint & SCROLL_CAPTURE_HINT_EXCLUDE) != 0) { return; } boolean rectIsVisible = true; if (mClipBounds != null) { rectIsVisible = localVisibleRect.intersect(mClipBounds); } if (!rectIsVisible) { return; } ScrollCaptureCallback callback = (mListenerInfo == null) ? null : mListenerInfo.mScrollCaptureCallback; if (callback == null) { callback = createScrollCaptureCallbackInternal(localVisibleRect, windowOffset); } if (callback != null) { Point offset = new Point(windowOffset.x, windowOffset.y); Rect rect = new Rect(localVisibleRect); targets.accept(new ScrollCaptureTarget(this, rect, offset, callback)); } } private static void dumpFlags() { final HashMap<String, String> found = Maps.newHashMap(); try { for (Field field : View.class.getDeclaredFields()) { final int modifiers = field.getModifiers(); if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { if (field.getType().equals(int.class)) { final int value = field.getInt(null); dumpFlag(found, field.getName(), value); } else if (field.getType().equals(int[].class)) { final int[] values = (int[]) field.get(null); for (int i = 0; i < values.length; i++) { dumpFlag(found, field.getName() + "[" + i + "]", values[i]); } } } } } catch (IllegalAccessException e) { throw new RuntimeException(e); } final ArrayList<String> keys = Lists.newArrayList(); keys.addAll(found.keySet()); Collections.sort(keys); for (String key : keys) { Log.d(VIEW_LOG_TAG, found.get(key)); } } private static void dumpFlag(HashMap<String, String> found, String name, int value) { final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); final int prefix = name.indexOf('_'); final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; final String output = bits + " " + name; found.put(key, output); } public void encode(@NonNull ViewHierarchyEncoder stream) { stream.beginObject(this); encodeProperties(stream); stream.endObject(); } @CallSuper protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { Object resolveId = ViewDebug.resolveId(getContext(), mID); if (resolveId instanceof String) { stream.addProperty("id", (String) resolveId); } else { stream.addProperty("id", mID); } stream.addProperty("misc:transformation.alpha", mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); stream.addProperty("misc:transitionName", getTransitionName()); stream.addProperty("layout:left", mLeft); stream.addProperty("layout:right", mRight); stream.addProperty("layout:top", mTop); stream.addProperty("layout:bottom", mBottom); stream.addProperty("layout:width", getWidth()); stream.addProperty("layout:height", getHeight()); stream.addProperty("layout:layoutDirection", getLayoutDirection()); stream.addProperty("layout:layoutRtl", isLayoutRtl()); stream.addProperty("layout:hasTransientState", hasTransientState()); stream.addProperty("layout:baseline", getBaseline()); ViewGroup.LayoutParams layoutParams = getLayoutParams(); if (layoutParams != null) { stream.addPropertyKey("layoutParams"); layoutParams.encode(stream); } stream.addProperty("scrolling:scrollX", mScrollX); stream.addProperty("scrolling:scrollY", mScrollY); stream.addProperty("padding:paddingLeft", mPaddingLeft); stream.addProperty("padding:paddingRight", mPaddingRight); stream.addProperty("padding:paddingTop", mPaddingTop); stream.addProperty("padding:paddingBottom", mPaddingBottom); stream.addProperty("padding:userPaddingRight", mUserPaddingRight); stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); stream.addProperty("padding:userPaddingStart", mUserPaddingStart); stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); stream.addProperty("measurement:minHeight", mMinHeight); stream.addProperty("measurement:minWidth", mMinWidth); stream.addProperty("measurement:measuredWidth", mMeasuredWidth); stream.addProperty("measurement:measuredHeight", mMeasuredHeight); stream.addProperty("drawing:elevation", getElevation()); stream.addProperty("drawing:translationX", getTranslationX()); stream.addProperty("drawing:translationY", getTranslationY()); stream.addProperty("drawing:translationZ", getTranslationZ()); stream.addProperty("drawing:rotation", getRotation()); stream.addProperty("drawing:rotationX", getRotationX()); stream.addProperty("drawing:rotationY", getRotationY()); stream.addProperty("drawing:scaleX", getScaleX()); stream.addProperty("drawing:scaleY", getScaleY()); stream.addProperty("drawing:pivotX", getPivotX()); stream.addProperty("drawing:pivotY", getPivotY()); stream.addProperty("drawing:clipBounds", mClipBounds == null ? null : mClipBounds.toString()); stream.addProperty("drawing:opaque", isOpaque()); stream.addProperty("drawing:alpha", getAlpha()); stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); stream.addProperty("drawing:shadow", hasShadow()); stream.addProperty("drawing:solidColor", getSolidColor()); stream.addProperty("drawing:layerType", mLayerType); stream.addProperty("drawing:willNotDraw", willNotDraw()); stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); stream.addProperty("drawing:outlineAmbientShadowColor", getOutlineAmbientShadowColor()); stream.addProperty("drawing:outlineSpotShadowColor", getOutlineSpotShadowColor()); stream.addProperty("focus:hasFocus", hasFocus()); stream.addProperty("focus:isFocused", isFocused()); stream.addProperty("focus:focusable", getFocusable()); stream.addProperty("focus:isFocusable", isFocusable()); stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); stream.addProperty("misc:clickable", isClickable()); stream.addProperty("misc:pressed", isPressed()); stream.addProperty("misc:selected", isSelected()); stream.addProperty("misc:touchMode", isInTouchMode()); stream.addProperty("misc:hovered", isHovered()); stream.addProperty("misc:activated", isActivated()); stream.addProperty("misc:visibility", getVisibility()); stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); stream.addProperty("misc:enabled", isEnabled()); stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); Resources.Theme theme = getContext().getTheme(); if (theme != null) { stream.addPropertyKey("theme"); theme.encode(stream); } int n = mAttributes != null ? mAttributes.length : 0; stream.addProperty("meta:__attrCount__", n/2); for (int i = 0; i < n; i += 2) { stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); } stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); stream.addProperty("text:textDirection", getTextDirection()); stream.addProperty("text:textAlignment", getTextAlignment()); CharSequence contentDescription = getContentDescription(); stream.addUserProperty("accessibility:contentDescription", contentDescription == null ? "" : contentDescription.toString()); stream.addProperty("accessibility:labelFor", getLabelFor()); stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); } boolean shouldDrawRoundScrollbar() { if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { return false; } final View rootView = getRootView(); final WindowInsets insets = getRootWindowInsets(); int height = getHeight(); int width = getWidth(); int displayHeight = rootView.getHeight(); int displayWidth = rootView.getWidth(); if (height != displayHeight || width != displayWidth) { return false; } return true; } public void setTooltipText(@Nullable CharSequence tooltipText) { if (TextUtils.isEmpty(tooltipText)) { setFlags(0, TOOLTIP); hideTooltip(); mTooltipInfo = null; } else { setFlags(TOOLTIP, TOOLTIP); if (mTooltipInfo == null) { mTooltipInfo = new TooltipInfo(); mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; mTooltipInfo.mHoverSlop = ViewConfiguration.get(mContext).getScaledHoverSlop(); mTooltipInfo.clearAnchorPos(); } mTooltipInfo.mTooltipText = tooltipText; } } @UnsupportedAppUsage public void setTooltip(@Nullable CharSequence tooltipText) { setTooltipText(tooltipText); } @InspectableProperty @Nullable public CharSequence getTooltipText() { return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null; } @Nullable public CharSequence getTooltip() { return getTooltipText(); } private boolean showTooltip(int x, int y, boolean fromLongClick) { if (mAttachInfo == null || mTooltipInfo == null) { return false; } if (fromLongClick && (mViewFlags & ENABLED_MASK) != ENABLED) { return false; } if (TextUtils.isEmpty(mTooltipInfo.mTooltipText)) { return false; } hideTooltip(); mTooltipInfo.mTooltipFromLongClick = fromLongClick; mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, mTooltipInfo.mTooltipText); mAttachInfo.mTooltipHost = this; notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); return true; } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) void hideTooltip() { if (mTooltipInfo == null) { return; } removeCallbacks(mTooltipInfo.mShowTooltipRunnable); if (mTooltipInfo.mTooltipPopup == null) { return; } mTooltipInfo.mTooltipPopup.hide(); mTooltipInfo.mTooltipPopup = null; mTooltipInfo.mTooltipFromLongClick = false; mTooltipInfo.clearAnchorPos(); if (mAttachInfo != null) { mAttachInfo.mTooltipHost = null; } notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); } private boolean showLongClickTooltip(int x, int y) { removeCallbacks(mTooltipInfo.mShowTooltipRunnable); removeCallbacks(mTooltipInfo.mHideTooltipRunnable); return showTooltip(x, y, true); } private boolean showHoverTooltip() { return showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); } boolean dispatchTooltipHoverEvent(MotionEvent event) { if (mTooltipInfo == null) { return false; } switch(event.getAction()) { case MotionEvent.ACTION_HOVER_MOVE: if ((mViewFlags & TOOLTIP) != TOOLTIP) { break; } if (!mTooltipInfo.mTooltipFromLongClick && mTooltipInfo.updateAnchorPos(event)) { if (mTooltipInfo.mTooltipPopup == null) { removeCallbacks(mTooltipInfo.mShowTooltipRunnable); postDelayed(mTooltipInfo.mShowTooltipRunnable, ViewConfiguration.getHoverTooltipShowTimeout()); } final int timeout; if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) == SYSTEM_UI_FLAG_LOW_PROFILE) { timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); } else { timeout = ViewConfiguration.getHoverTooltipHideTimeout(); } removeCallbacks(mTooltipInfo.mHideTooltipRunnable); postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); } return true; case MotionEvent.ACTION_HOVER_EXIT: mTooltipInfo.clearAnchorPos(); if (!mTooltipInfo.mTooltipFromLongClick) { hideTooltip(); } break; } return false; } void handleTooltipKey(KeyEvent event) { switch (event.getAction()) { case KeyEvent.ACTION_DOWN: if (event.getRepeatCount() == 0) { hideTooltip(); } break; case KeyEvent.ACTION_UP: handleTooltipUp(); break; } } private void handleTooltipUp() { if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { return; } removeCallbacks(mTooltipInfo.mHideTooltipRunnable); postDelayed(mTooltipInfo.mHideTooltipRunnable, ViewConfiguration.getLongPressTooltipHideTimeout()); } private int getFocusableAttribute(TypedArray attributes) { TypedValue val = new TypedValue(); if (attributes.getValue(com.android.internal.R.styleable.View_focusable, val)) { if (val.type == TypedValue.TYPE_INT_BOOLEAN) { return (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE); } else { return val.data; } } else { return FOCUSABLE_AUTO; } } @TestApi public View getTooltipView() { if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { return null; } return mTooltipInfo.mTooltipPopup.getContentView(); } @TestApi public static boolean isDefaultFocusHighlightEnabled() { return sUseDefaultFocusHighlight; } View dispatchUnhandledKeyEvent(KeyEvent evt) { if (onUnhandledKeyEvent(evt)) { return this; } return null; } boolean onUnhandledKeyEvent(@NonNull KeyEvent event) { if (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null) { for (int i = mListenerInfo.mUnhandledKeyListeners.size() - 1; i >= 0; --i) { if (mListenerInfo.mUnhandledKeyListeners.get(i).onUnhandledKeyEvent(this, event)) { return true; } } } return false; } boolean hasUnhandledKeyListener() { return (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null && !mListenerInfo.mUnhandledKeyListeners.isEmpty()); } public void addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) { ArrayList<OnUnhandledKeyEventListener> listeners = getListenerInfo().mUnhandledKeyListeners; if (listeners == null) { listeners = new ArrayList<>(); getListenerInfo().mUnhandledKeyListeners = listeners; } listeners.add(listener); if (listeners.size() == 1 && mParent instanceof ViewGroup) { ((ViewGroup) mParent).incrementChildUnhandledKeyListeners(); } } public void removeOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) { if (mListenerInfo != null) { if (mListenerInfo.mUnhandledKeyListeners != null && !mListenerInfo.mUnhandledKeyListeners.isEmpty()) { mListenerInfo.mUnhandledKeyListeners.remove(listener); if (mListenerInfo.mUnhandledKeyListeners.isEmpty()) { mListenerInfo.mUnhandledKeyListeners = null; if (mParent instanceof ViewGroup) { ((ViewGroup) mParent).decrementChildUnhandledKeyListeners(); } } } } } protected void setDetached(boolean detached) { if (detached) { mPrivateFlags4 |= PFLAG4_DETACHED; } else { mPrivateFlags4 &= ~PFLAG4_DETACHED; } } public void setIsCredential(boolean isCredential) { if (isCredential) { mPrivateFlags4 |= PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER; } else { mPrivateFlags4 &= ~PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER; } } public boolean isCredential() { return ((mPrivateFlags4 & PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER) == PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER); } public void setAutoHandwritingEnabled(boolean enabled) { if (enabled) { mPrivateFlags4 |= PFLAG4_AUTO_HANDWRITING_ENABLED; } else { mPrivateFlags4 &= ~PFLAG4_AUTO_HANDWRITING_ENABLED; } updatePositionUpdateListener(); postUpdate(this::updateHandwritingArea); } public boolean isAutoHandwritingEnabled() { return (mPrivateFlags4 & PFLAG4_AUTO_HANDWRITING_ENABLED) == PFLAG4_AUTO_HANDWRITING_ENABLED; } public boolean isStylusHandwritingAvailable() { return getContext().getSystemService(InputMethodManager.class) .isStylusHandwritingAvailable(); } private void setTraversalTracingEnabled(boolean enabled) { if (enabled) { if (mTracingStrings == null) { mTracingStrings = new ViewTraversalTracingStrings(this); } mPrivateFlags4 |= PFLAG4_TRAVERSAL_TRACING_ENABLED; } else { mPrivateFlags4 &= ~PFLAG4_TRAVERSAL_TRACING_ENABLED; } } private boolean isTraversalTracingEnabled() { return (mPrivateFlags4 & PFLAG4_TRAVERSAL_TRACING_ENABLED) == PFLAG4_TRAVERSAL_TRACING_ENABLED; } private void setRelayoutTracingEnabled(boolean enabled) { if (enabled) { if (mTracingStrings == null) { mTracingStrings = new ViewTraversalTracingStrings(this); } mPrivateFlags4 |= PFLAG4_RELAYOUT_TRACING_ENABLED; } else { mPrivateFlags4 &= ~PFLAG4_RELAYOUT_TRACING_ENABLED; } } private boolean isRelayoutTracingEnabled() { return (mPrivateFlags4 & PFLAG4_RELAYOUT_TRACING_ENABLED) == PFLAG4_RELAYOUT_TRACING_ENABLED; } public void onCreateViewTranslationRequest(@NonNull @DataFormat int[] supportedFormats, @NonNull Consumer<ViewTranslationRequest> requestsCollector) { } @SuppressLint("NullableCollection") public void onCreateVirtualViewTranslationRequests(@NonNull long[] virtualIds, @NonNull @DataFormat int[] supportedFormats, @NonNull Consumer<ViewTranslationRequest> requestsCollector) { } @Nullable public ViewTranslationCallback getViewTranslationCallback() { return mViewTranslationCallback; } public void setViewTranslationCallback(@NonNull ViewTranslationCallback callback) { mViewTranslationCallback = callback; } public void clearViewTranslationCallback() { mViewTranslationCallback = null; } @Nullable public ViewTranslationResponse getViewTranslationResponse() { return mViewTranslationResponse; } public void onViewTranslationResponse(@NonNull ViewTranslationResponse response) { mViewTranslationResponse = response; } public void clearViewTranslationResponse() { mViewTranslationResponse = null; } public void onVirtualViewTranslationResponses( @NonNull LongSparseArray<ViewTranslationResponse> response) { } public void dispatchCreateViewTranslationRequest(@NonNull Map<AutofillId, long[]> viewIds, @NonNull @DataFormat int[] supportedFormats, @NonNull TranslationCapability capability, @NonNull List<ViewTranslationRequest> requests) { AutofillId autofillId = getAutofillId(); if (viewIds.containsKey(autofillId)) { if (viewIds.get(autofillId) == null) { onCreateViewTranslationRequest(supportedFormats, new ViewTranslationRequestConsumer(requests)); } else { onCreateVirtualViewTranslationRequests(viewIds.get(autofillId), supportedFormats, request -> { requests.add(request); }); } } } private class ViewTranslationRequestConsumer implements Consumer<ViewTranslationRequest> { private final List<ViewTranslationRequest> mRequests; private boolean mCalled; ViewTranslationRequestConsumer(List<ViewTranslationRequest> requests) { mRequests = requests; } @Override public void accept(ViewTranslationRequest request) { if (mCalled) { throw new IllegalStateException("The translation Consumer is not reusable."); } mCalled = true; if (request != null && request.getKeys().size() > 0) { mRequests.add(request); if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { Log.v(CONTENT_CAPTURE_LOG_TAG, "Calling setHasTransientState(true) for " + getAutofillId()); } setHasTransientState(true); setHasTranslationTransientState(true); } } } public void generateDisplayHash(@NonNull String hashAlgorithm, @Nullable Rect bounds, @NonNull Executor executor, @NonNull DisplayHashResultCallback callback) { IWindowSession session = getWindowSession(); if (session == null) { callback.onDisplayHashError(DISPLAY_HASH_ERROR_MISSING_WINDOW); return; } IWindow window = getWindow(); if (window == null) { callback.onDisplayHashError(DISPLAY_HASH_ERROR_MISSING_WINDOW); return; } Rect visibleBounds = new Rect(); getGlobalVisibleRect(visibleBounds); if (bounds != null && bounds.isEmpty()) { callback.onDisplayHashError(DISPLAY_HASH_ERROR_INVALID_BOUNDS); return; } if (bounds != null) { bounds.offset(visibleBounds.left, visibleBounds.top); visibleBounds.intersectUnchecked(bounds); } if (visibleBounds.isEmpty()) { callback.onDisplayHashError(DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN); return; } RemoteCallback remoteCallback = new RemoteCallback(result -> executor.execute(() -> { DisplayHash displayHash = result.getParcelable(EXTRA_DISPLAY_HASH, android.view.displayhash.DisplayHash.class); int errorCode = result.getInt(EXTRA_DISPLAY_HASH_ERROR_CODE, DISPLAY_HASH_ERROR_UNKNOWN); if (displayHash != null) { callback.onDisplayHashResult(displayHash); } else { callback.onDisplayHashError(errorCode); } })); try { session.generateDisplayHash(window, visibleBounds, hashAlgorithm, remoteCallback); } catch (RemoteException e) { Log.e(VIEW_LOG_TAG, "Failed to call generateDisplayHash"); callback.onDisplayHashError(DISPLAY_HASH_ERROR_UNKNOWN); } } public @Nullable AttachedSurfaceControl getRootSurfaceControl() { if (mAttachInfo != null) { return mAttachInfo.getRootSurfaceControl(); } return null; } protected int calculateFrameRateCategory() { int category; switch (getViewRootImpl().intermittentUpdateState()) { case ViewRootImpl.INTERMITTENT_STATE_INTERMITTENT -> category = FRAME_RATE_CATEGORY_NORMAL | FRAME_RATE_CATEGORY_REASON_INTERMITTENT; case ViewRootImpl.INTERMITTENT_STATE_NOT_INTERMITTENT -> category = mSizeBasedFrameRateCategoryAndReason; default -> category = mLastFrameRateCategory; } return category; } protected void votePreferredFrameRate() { ViewRootImpl viewRootImpl = getViewRootImpl(); if (viewRootImpl == null) { return; } float velocity = mFrameContentVelocity; final float frameRate = mPreferredFrameRate; ViewParent parent = mParent; if (velocity <= 0 && Float.isNaN(frameRate)) { if (mAttachInfo.mViewVelocityApi && ((mPrivateFlags4 & (PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN)) == ( PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN) || mLastFrameLeft != mLeft || mLastFrameTop != mTop) && viewRootImpl.shouldCheckFrameRate(false) && parent instanceof View && ((View) parent).mFrameContentVelocity <= 0) { viewRootImpl.votePreferredFrameRate(MAX_FRAME_RATE, FRAME_RATE_COMPATIBILITY_GTE); } if (viewRootImpl.shouldCheckFrameRateCategory()) { int frameRateCategory = calculateFrameRateCategory(); int category = frameRateCategory & ~FRAME_RATE_CATEGORY_REASON_MASK; int reason = frameRateCategory & FRAME_RATE_CATEGORY_REASON_MASK; viewRootImpl.votePreferredFrameRateCategory(category, reason, this); mLastFrameRateCategory = frameRateCategory; } mLastFrameLeft = mLeft; mLastFrameTop = mTop; return; } if (viewRootImpl.shouldCheckFrameRate(frameRate > 0f)) { float velocityFrameRate = 0f; if (mAttachInfo.mViewVelocityApi) { if (velocity < 0f && ((mPrivateFlags4 & (PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN)) == ( PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN) || mLastFrameLeft != mLeft || mLastFrameTop != mTop) && mParent instanceof View && ((View) mParent).mFrameContentVelocity <= 0 ) { velocityFrameRate = MAX_FRAME_RATE; } else if (velocity > 0f) { velocityFrameRate = convertVelocityToFrameRate(velocity); } } if (velocityFrameRate > 0f || frameRate > 0f) { int compatibility; float frameRateToSet; if (frameRate >= velocityFrameRate) { compatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; frameRateToSet = frameRate; } else { compatibility = FRAME_RATE_COMPATIBILITY_GTE; frameRateToSet = velocityFrameRate; } viewRootImpl.votePreferredFrameRate(frameRateToSet, compatibility); } } if (viewRootImpl.shouldCheckFrameRateCategory()) { if (sToolkitMetricsForFrameRateDecisionFlagValue) { int width = mRight - mLeft; int height = mBottom - mTop; viewRootImpl.recordViewPercentage(sizePercentage); } int frameRateCategory; if (Float.isNaN(frameRate)) { frameRateCategory = calculateFrameRateCategory(); } else if (frameRate < 0) { switch ((int) frameRate) { case (int) REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE -> frameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE | FRAME_RATE_CATEGORY_REASON_REQUESTED; case (int) REQUESTED_FRAME_RATE_CATEGORY_LOW -> frameRateCategory = FRAME_RATE_CATEGORY_LOW | FRAME_RATE_CATEGORY_REASON_REQUESTED; case (int) REQUESTED_FRAME_RATE_CATEGORY_NORMAL -> frameRateCategory = FRAME_RATE_CATEGORY_NORMAL | FRAME_RATE_CATEGORY_REASON_REQUESTED; case (int) REQUESTED_FRAME_RATE_CATEGORY_HIGH -> frameRateCategory = FRAME_RATE_CATEGORY_HIGH | FRAME_RATE_CATEGORY_REASON_REQUESTED; default -> { int category = sToolkitFrameRateDefaultNormalReadOnlyFlagValue ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH; frameRateCategory = category | FRAME_RATE_CATEGORY_REASON_INVALID; } } } else { frameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE | FRAME_RATE_CATEGORY_REASON_REQUESTED; } int category = frameRateCategory & ~FRAME_RATE_CATEGORY_REASON_MASK; int reason = frameRateCategory & FRAME_RATE_CATEGORY_REASON_MASK; viewRootImpl.votePreferredFrameRateCategory(category, reason, this); mLastFrameRateCategory = frameRateCategory; } mLastFrameLeft = mLeft; mLastFrameTop = mTop; } private float convertVelocityToFrameRate(float velocityPps) { float density = mAttachInfo.mDensity; float velocityDps = velocityPps / density; return (velocityDps >= 1500f) ? MAX_FRAME_RATE : 80f; } @FlaggedApi(FLAG_VIEW_VELOCITY_API) public void setFrameContentVelocity(float pixelsPerSecond) { if (mAttachInfo != null && mAttachInfo.mViewVelocityApi) { mFrameContentVelocity = Math.abs(pixelsPerSecond); if (sToolkitMetricsForFrameRateDecisionFlagValue) { Trace.setCounter("Set frame velocity", (long) mFrameContentVelocity); } } } @FlaggedApi(FLAG_VIEW_VELOCITY_API) public float getFrameContentVelocity() { if (mAttachInfo != null && mAttachInfo.mViewVelocityApi) { return Math.max(mFrameContentVelocity, 0f); } return 0; } @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) public void setRequestedFrameRate(float frameRate) { if (sToolkitSetFrameRateReadOnlyFlagValue) { mPreferredFrameRate = frameRate; } } @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) public float getRequestedFrameRate() { if (sToolkitSetFrameRateReadOnlyFlagValue) { return mPreferredFrameRate; } return 0; } }
Editor is loading...