1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.view; 18 19 import static android.view.Display.DEFAULT_DISPLAY; 20 import static android.view.Display.INVALID_DISPLAY; 21 import static android.view.InputDevice.SOURCE_CLASS_NONE; 22 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; 23 import static android.view.InsetsState.ITYPE_STATUS_BAR; 24 import static android.view.InsetsState.SIZE; 25 import static android.view.View.PFLAG_DRAW_ANIMATION; 26 import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN; 27 import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; 28 import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE; 29 import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; 30 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 31 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; 32 import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; 33 import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; 34 import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE; 35 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; 36 import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER; 37 import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM; 38 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS; 39 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; 40 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; 41 import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE; 42 import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH; 43 import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; 44 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; 45 import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; 46 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 47 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; 48 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; 49 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; 50 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; 51 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; 52 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED; 53 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED; 54 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FIT_INSETS_CONTROLLED; 55 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY; 56 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME; 57 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; 58 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; 59 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; 60 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; 61 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; 62 import static android.view.WindowManager.LayoutParams.TYPE_TOAST; 63 import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY; 64 65 import android.Manifest; 66 import android.animation.LayoutTransition; 67 import android.annotation.AnyThread; 68 import android.annotation.NonNull; 69 import android.annotation.Nullable; 70 import android.app.ActivityManager; 71 import android.app.ActivityThread; 72 import android.app.ResourcesManager; 73 import android.compat.annotation.UnsupportedAppUsage; 74 import android.content.ClipData; 75 import android.content.ClipDescription; 76 import android.content.Context; 77 import android.content.pm.ActivityInfo; 78 import android.content.pm.PackageManager; 79 import android.content.res.CompatibilityInfo; 80 import android.content.res.Configuration; 81 import android.content.res.Resources; 82 import android.content.res.TypedArray; 83 import android.graphics.BLASTBufferQueue; 84 import android.graphics.Canvas; 85 import android.graphics.Color; 86 import android.graphics.FrameInfo; 87 import android.graphics.HardwareRenderer.FrameDrawingCallback; 88 import android.graphics.Insets; 89 import android.graphics.Matrix; 90 import android.graphics.PixelFormat; 91 import android.graphics.Point; 92 import android.graphics.PointF; 93 import android.graphics.PorterDuff; 94 import android.graphics.RecordingCanvas; 95 import android.graphics.Rect; 96 import android.graphics.Region; 97 import android.graphics.RenderNode; 98 import android.graphics.drawable.Drawable; 99 import android.hardware.display.DisplayManager; 100 import android.hardware.display.DisplayManager.DisplayListener; 101 import android.hardware.input.InputManager; 102 import android.media.AudioManager; 103 import android.os.Binder; 104 import android.os.Build; 105 import android.os.Bundle; 106 import android.os.Debug; 107 import android.os.Handler; 108 import android.os.IBinder; 109 import android.os.Looper; 110 import android.os.Message; 111 import android.os.ParcelFileDescriptor; 112 import android.os.Process; 113 import android.os.RemoteException; 114 import android.os.SystemClock; 115 import android.os.SystemProperties; 116 import android.os.Trace; 117 import android.os.UserHandle; 118 import android.sysprop.DisplayProperties; 119 import android.util.AndroidRuntimeException; 120 import android.util.DisplayMetrics; 121 import android.util.Log; 122 import android.util.LongArray; 123 import android.util.MergedConfiguration; 124 import android.util.Slog; 125 import android.util.SparseArray; 126 import android.util.TimeUtils; 127 import android.util.TypedValue; 128 import android.view.InputDevice.InputSourceClass; 129 import android.view.InsetsState.InternalInsetsType; 130 import android.view.Surface.OutOfResourcesException; 131 import android.view.SurfaceControl.Transaction; 132 import android.view.View.AttachInfo; 133 import android.view.View.FocusDirection; 134 import android.view.View.MeasureSpec; 135 import android.view.Window.OnContentApplyWindowInsetsListener; 136 import android.view.WindowInsets.Type; 137 import android.view.WindowInsets.Type.InsetsType; 138 import android.view.WindowManager.LayoutParams; 139 import android.view.WindowManager.LayoutParams.SoftInputModeFlags; 140 import android.view.accessibility.AccessibilityEvent; 141 import android.view.accessibility.AccessibilityManager; 142 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener; 143 import android.view.accessibility.AccessibilityManager.HighTextContrastChangeListener; 144 import android.view.accessibility.AccessibilityNodeIdManager; 145 import android.view.accessibility.AccessibilityNodeInfo; 146 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 147 import android.view.accessibility.AccessibilityNodeProvider; 148 import android.view.accessibility.AccessibilityWindowInfo; 149 import android.view.accessibility.IAccessibilityEmbeddedConnection; 150 import android.view.accessibility.IAccessibilityInteractionConnection; 151 import android.view.accessibility.IAccessibilityInteractionConnectionCallback; 152 import android.view.animation.AccelerateDecelerateInterpolator; 153 import android.view.animation.Interpolator; 154 import android.view.autofill.AutofillId; 155 import android.view.autofill.AutofillManager; 156 import android.view.contentcapture.ContentCaptureManager; 157 import android.view.contentcapture.ContentCaptureSession; 158 import android.view.contentcapture.MainContentCaptureSession; 159 import android.view.inputmethod.InputMethodManager; 160 import android.widget.Scroller; 161 162 import com.android.internal.R; 163 import com.android.internal.annotations.GuardedBy; 164 import com.android.internal.annotations.VisibleForTesting; 165 import com.android.internal.os.IResultReceiver; 166 import com.android.internal.os.SomeArgs; 167 import com.android.internal.policy.DecorView; 168 import com.android.internal.policy.PhoneFallbackEventHandler; 169 import com.android.internal.util.Preconditions; 170 import com.android.internal.view.BaseSurfaceHolder; 171 import com.android.internal.view.RootViewSurfaceTaker; 172 import com.android.internal.view.SurfaceCallbackHelper; 173 174 import java.io.FileDescriptor; 175 import java.io.IOException; 176 import java.io.OutputStream; 177 import java.io.PrintWriter; 178 import java.lang.ref.WeakReference; 179 import java.util.ArrayList; 180 import java.util.HashSet; 181 import java.util.LinkedList; 182 import java.util.List; 183 import java.util.Queue; 184 import java.util.concurrent.CountDownLatch; 185 186 /** 187 * The top of a view hierarchy, implementing the needed protocol between View 188 * and the WindowManager. This is for the most part an internal implementation 189 * detail of {@link WindowManagerGlobal}. 190 * 191 * {@hide} 192 */ 193 @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"}) 194 public final class ViewRootImpl implements ViewParent, 195 View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks { 196 private static final String TAG = "ViewRootImpl"; 197 private static final boolean DBG = false; 198 private static final boolean LOCAL_LOGV = false; 199 /** @noinspection PointlessBooleanExpression*/ 200 private static final boolean DEBUG_DRAW = false || LOCAL_LOGV; 201 private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV; 202 private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV; 203 private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV; 204 private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV; 205 private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV; 206 private static final boolean DEBUG_IMF = false || LOCAL_LOGV; 207 private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV; 208 private static final boolean DEBUG_FPS = false; 209 private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV; 210 private static final boolean DEBUG_KEEP_SCREEN_ON = false || LOCAL_LOGV; 211 private static final boolean DEBUG_CONTENT_CAPTURE = false || LOCAL_LOGV; 212 private static final boolean DEBUG_SCROLL_CAPTURE = false || LOCAL_LOGV; 213 214 /** 215 * Set to false if we do not want to use the multi threaded renderer even though 216 * threaded renderer (aka hardware renderering) is used. Note that by disabling 217 * this, WindowCallbacks will not fire. 218 */ 219 private static final boolean MT_RENDERER_AVAILABLE = true; 220 221 /** 222 * If set to 2, the view system will switch from using rectangles retrieved from window to 223 * dispatch to the view hierarchy to using {@link InsetsController}, that derives the insets 224 * directly from the full configuration, enabling richer information about the insets state, as 225 * well as new APIs to control it frame-by-frame, and synchronize animations with it. 226 * <p> 227 * Only set this to 2 once the new insets system is productionized and the old APIs are 228 * fully migrated over. 229 * <p> 230 * If set to 1, this will switch to a mode where we only use the new approach for IME, but not 231 * for the status/navigation bar. 232 */ 233 private static final String USE_NEW_INSETS_PROPERTY = "persist.debug.new_insets"; 234 235 /** 236 * @see #USE_NEW_INSETS_PROPERTY 237 * @hide 238 */ 239 public static final int NEW_INSETS_MODE_NONE = 0; 240 241 /** 242 * @see #USE_NEW_INSETS_PROPERTY 243 * @hide 244 */ 245 public static final int NEW_INSETS_MODE_IME = 1; 246 247 /** 248 * @see #USE_NEW_INSETS_PROPERTY 249 * @hide 250 */ 251 public static final int NEW_INSETS_MODE_FULL = 2; 252 253 /** 254 * @see #USE_NEW_INSETS_PROPERTY 255 * @hide 256 */ 257 public static int sNewInsetsMode = 258 SystemProperties.getInt(USE_NEW_INSETS_PROPERTY, NEW_INSETS_MODE_FULL); 259 260 /** 261 * Set this system property to true to force the view hierarchy to render 262 * at 60 Hz. This can be used to measure the potential framerate. 263 */ 264 private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering"; 265 266 /** 267 * Maximum time we allow the user to roll the trackball enough to generate 268 * a key event, before resetting the counters. 269 */ 270 static final int MAX_TRACKBALL_DELAY = 250; 271 272 /** 273 * Initial value for {@link #mContentCaptureEnabled}. 274 */ 275 private static final int CONTENT_CAPTURE_ENABLED_NOT_CHECKED = 0; 276 277 /** 278 * Value for {@link #mContentCaptureEnabled} when it was checked and set to {@code true}. 279 */ 280 private static final int CONTENT_CAPTURE_ENABLED_TRUE = 1; 281 282 /** 283 * Value for {@link #mContentCaptureEnabled} when it was checked and set to {@code false}. 284 */ 285 private static final int CONTENT_CAPTURE_ENABLED_FALSE = 2; 286 287 @UnsupportedAppUsage 288 static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>(); 289 290 static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<>(); 291 static boolean sFirstDrawComplete = false; 292 293 /** 294 * Callback for notifying about global configuration changes. 295 */ 296 public interface ConfigChangedCallback { 297 298 /** Notifies about global config change. */ onConfigurationChanged(Configuration globalConfig)299 void onConfigurationChanged(Configuration globalConfig); 300 } 301 302 private static final ArrayList<ConfigChangedCallback> sConfigCallbacks = new ArrayList<>(); 303 304 /** 305 * Callback for notifying activities about override configuration changes. 306 */ 307 public interface ActivityConfigCallback { 308 309 /** 310 * Notifies about override config change and/or move to different display. 311 * @param overrideConfig New override config to apply to activity. 312 * @param newDisplayId New display id, {@link Display#INVALID_DISPLAY} if not changed. 313 */ onConfigurationChanged(Configuration overrideConfig, int newDisplayId)314 void onConfigurationChanged(Configuration overrideConfig, int newDisplayId); 315 } 316 317 /** 318 * Callback used to notify corresponding activity about override configuration change and make 319 * sure that all resources are set correctly before updating the ViewRootImpl's internal state. 320 */ 321 private ActivityConfigCallback mActivityConfigCallback; 322 323 /** 324 * Used when configuration change first updates the config of corresponding activity. 325 * In that case we receive a call back from {@link ActivityThread} and this flag is used to 326 * preserve the initial value. 327 * 328 * @see #performConfigurationChange(Configuration, Configuration, boolean, int) 329 */ 330 private boolean mForceNextConfigUpdate; 331 332 private boolean mUseBLASTAdapter; 333 private boolean mForceDisableBLAST; 334 private boolean mEnableTripleBuffering; 335 336 /** 337 * Signals that compatibility booleans have been initialized according to 338 * target SDK versions. 339 */ 340 private static boolean sCompatibilityDone = false; 341 342 /** 343 * Always assign focus if a focusable View is available. 344 */ 345 private static boolean sAlwaysAssignFocus; 346 347 /** 348 * This list must only be modified by the main thread, so a lock is only needed when changing 349 * the list or when accessing the list from a non-main thread. 350 */ 351 @GuardedBy("mWindowCallbacks") 352 final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList<>(); 353 @UnsupportedAppUsage 354 public final Context mContext; 355 356 @UnsupportedAppUsage 357 final IWindowSession mWindowSession; 358 @NonNull Display mDisplay; 359 final DisplayManager mDisplayManager; 360 final String mBasePackageName; 361 362 final int[] mTmpLocation = new int[2]; 363 364 final TypedValue mTmpValue = new TypedValue(); 365 366 final Thread mThread; 367 368 final WindowLeaked mLocation; 369 370 public final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams(); 371 372 final W mWindow; 373 374 final IBinder mLeashToken; 375 376 final int mTargetSdkVersion; 377 378 int mSeq; 379 380 @UnsupportedAppUsage 381 View mView; 382 383 View mAccessibilityFocusedHost; 384 AccessibilityNodeInfo mAccessibilityFocusedVirtualView; 385 386 // True if the window currently has pointer capture enabled. 387 boolean mPointerCapture; 388 389 int mViewVisibility; 390 boolean mAppVisible = true; 391 // For recents to freeform transition we need to keep drawing after the app receives information 392 // that it became invisible. This will ignore that information and depend on the decor view 393 // visibility to control drawing. The decor view visibility will get adjusted when the app get 394 // stopped and that's when the app will stop drawing further frames. 395 private boolean mForceDecorViewVisibility = false; 396 // Used for tracking app visibility updates separately in case we get double change. This will 397 // make sure that we always call relayout for the corresponding window. 398 private boolean mAppVisibilityChanged; 399 int mOrigWindowType = -1; 400 401 /** Whether the window had focus during the most recent traversal. */ 402 boolean mHadWindowFocus; 403 404 /** 405 * Whether the window lost focus during a previous traversal and has not 406 * yet gained it back. Used to determine whether a WINDOW_STATE_CHANGE 407 * accessibility events should be sent during traversal. 408 */ 409 boolean mLostWindowFocus; 410 411 // Set to true if the owner of this window is in the stopped state, 412 // so the window should no longer be active. 413 @UnsupportedAppUsage 414 boolean mStopped = false; 415 416 // Set to true if the owner of this window is in ambient mode, 417 // which means it won't receive input events. 418 boolean mIsAmbientMode = false; 419 420 // Set to true to stop input during an Activity Transition. 421 boolean mPausedForTransition = false; 422 423 boolean mLastInCompatMode = false; 424 425 SurfaceHolder.Callback2 mSurfaceHolderCallback; 426 BaseSurfaceHolder mSurfaceHolder; 427 boolean mIsCreating; 428 boolean mDrawingAllowed; 429 430 final Region mTransparentRegion; 431 final Region mPreviousTransparentRegion; 432 433 @UnsupportedAppUsage 434 int mWidth; 435 @UnsupportedAppUsage 436 int mHeight; 437 @UnsupportedAppUsage 438 Rect mDirty; 439 public boolean mIsAnimating; 440 441 private boolean mUseMTRenderer; 442 private boolean mDragResizing; 443 private boolean mInvalidateRootRequested; 444 private int mResizeMode; 445 private int mCanvasOffsetX; 446 private int mCanvasOffsetY; 447 private boolean mActivityRelaunched; 448 449 CompatibilityInfo.Translator mTranslator; 450 451 @UnsupportedAppUsage 452 final View.AttachInfo mAttachInfo; 453 final SystemUiVisibilityInfo mCompatibleVisibilityInfo; 454 int mDispatchedSystemUiVisibility = 455 ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL ? 0 : -1; 456 InputQueue.Callback mInputQueueCallback; 457 InputQueue mInputQueue; 458 @UnsupportedAppUsage 459 FallbackEventHandler mFallbackEventHandler; 460 final Choreographer mChoreographer; 461 462 // used in relayout to get SurfaceControl size 463 // for BLAST adapter surface setup 464 private final Point mSurfaceSize = new Point(); 465 466 final Rect mTempRect; // used in the transaction to not thrash the heap. 467 final Rect mVisRect; // used to retrieve visible rect of focused view. 468 private final Rect mTempBoundsRect = new Rect(); // used to set the size of the bounds surface. 469 470 // This is used to reduce the race between window focus changes being dispatched from 471 // the window manager and input events coming through the input system. 472 @GuardedBy("this") 473 boolean mWindowFocusChanged; 474 @GuardedBy("this") 475 boolean mUpcomingWindowFocus; 476 @GuardedBy("this") 477 boolean mUpcomingInTouchMode; 478 479 public boolean mTraversalScheduled; 480 int mTraversalBarrier; 481 boolean mWillDrawSoon; 482 /** Set to true while in performTraversals for detecting when die(true) is called from internal 483 * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */ 484 boolean mIsInTraversal; 485 boolean mApplyInsetsRequested; 486 boolean mLayoutRequested; 487 boolean mFirst; 488 489 @Nullable 490 int mContentCaptureEnabled = CONTENT_CAPTURE_ENABLED_NOT_CHECKED; 491 boolean mPerformContentCapture; 492 493 boolean mReportNextDraw; 494 boolean mFullRedrawNeeded; 495 boolean mNewSurfaceNeeded; 496 boolean mForceNextWindowRelayout; 497 CountDownLatch mWindowDrawCountDown; 498 499 boolean mIsDrawing; 500 int mLastSystemUiVisibility; 501 int mClientWindowLayoutFlags; 502 503 // Pool of queued input events. 504 private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10; 505 private QueuedInputEvent mQueuedInputEventPool; 506 private int mQueuedInputEventPoolSize; 507 508 /* Input event queue. 509 * Pending input events are input events waiting to be delivered to the input stages 510 * and handled by the application. 511 */ 512 QueuedInputEvent mPendingInputEventHead; 513 QueuedInputEvent mPendingInputEventTail; 514 int mPendingInputEventCount; 515 boolean mProcessInputEventsScheduled; 516 boolean mUnbufferedInputDispatch; 517 @InputSourceClass 518 int mUnbufferedInputSource = SOURCE_CLASS_NONE; 519 520 String mPendingInputEventQueueLengthCounterName = "pq"; 521 522 InputStage mFirstInputStage; 523 InputStage mFirstPostImeInputStage; 524 InputStage mSyntheticInputStage; 525 526 private final UnhandledKeyManager mUnhandledKeyManager = new UnhandledKeyManager(); 527 528 boolean mWindowAttributesChanged = false; 529 530 // These can be accessed by any thread, must be protected with a lock. 531 // Surface can never be reassigned or cleared (use Surface.clear()). 532 @UnsupportedAppUsage 533 public final Surface mSurface = new Surface(); 534 private final SurfaceControl mSurfaceControl = new SurfaceControl(); 535 private SurfaceControl mBlastSurfaceControl = new SurfaceControl(); 536 537 private BLASTBufferQueue mBlastBufferQueue; 538 539 /** 540 * Transaction object that can be used to synchronize child SurfaceControl changes with 541 * ViewRootImpl SurfaceControl changes by the server. The object is passed along with 542 * the SurfaceChangedCallback. 543 */ 544 private final Transaction mSurfaceChangedTransaction = new Transaction(); 545 /** 546 * Child container layer of {@code mSurface} with the same bounds as its parent, and cropped to 547 * the surface insets. This surface is created only if a client requests it via {@link 548 * #getBoundsLayer()}. By parenting to this bounds surface, child surfaces can ensure they do 549 * not draw into the surface inset region set by the parent window. 550 */ 551 private SurfaceControl mBoundsLayer; 552 private final SurfaceSession mSurfaceSession = new SurfaceSession(); 553 private final Transaction mTransaction = new Transaction(); 554 555 @UnsupportedAppUsage 556 boolean mAdded; 557 boolean mAddedTouchMode; 558 559 final Rect mTmpFrame = new Rect(); 560 final Rect mTmpRect = new Rect(); 561 562 // These are accessed by multiple threads. 563 final Rect mWinFrame; // frame given by window manager. 564 565 final Rect mPendingBackDropFrame = new Rect(); 566 final DisplayCutout.ParcelableWrapper mPendingDisplayCutout = 567 new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT); 568 boolean mPendingAlwaysConsumeSystemBars; 569 private final InsetsState mTempInsets = new InsetsState(); 570 private final InsetsSourceControl[] mTempControls = new InsetsSourceControl[SIZE]; 571 final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets 572 = new ViewTreeObserver.InternalInsetsInfo(); 573 574 private WindowInsets mLastWindowInsets; 575 576 // Insets types hidden by legacy window flags or system UI flags. 577 private @InsetsType int mTypesHiddenByFlags = 0; 578 579 /** Last applied configuration obtained from resources. */ 580 private final Configuration mLastConfigurationFromResources = new Configuration(); 581 /** Last configuration reported from WM or via {@link #MSG_UPDATE_CONFIGURATION}. */ 582 private final MergedConfiguration mLastReportedMergedConfiguration = new MergedConfiguration(); 583 /** Configurations waiting to be applied. */ 584 private final MergedConfiguration mPendingMergedConfiguration = new MergedConfiguration(); 585 586 boolean mScrollMayChange; 587 @SoftInputModeFlags 588 int mSoftInputMode; 589 @UnsupportedAppUsage 590 WeakReference<View> mLastScrolledFocus; 591 int mScrollY; 592 int mCurScrollY; 593 Scroller mScroller; 594 static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator(); 595 private ArrayList<LayoutTransition> mPendingTransitions; 596 597 final ViewConfiguration mViewConfiguration; 598 599 /* Drag/drop */ 600 ClipDescription mDragDescription; 601 View mCurrentDragView; 602 volatile Object mLocalDragState; 603 final PointF mDragPoint = new PointF(); 604 final PointF mLastTouchPoint = new PointF(); 605 int mLastTouchSource; 606 607 private boolean mProfileRendering; 608 private Choreographer.FrameCallback mRenderProfiler; 609 private boolean mRenderProfilingEnabled; 610 611 // Variables to track frames per second, enabled via DEBUG_FPS flag 612 private long mFpsStartTime = -1; 613 private long mFpsPrevTime = -1; 614 private int mFpsNumFrames; 615 616 private int mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED; 617 private PointerIcon mCustomPointerIcon = null; 618 619 /** 620 * see {@link #playSoundEffect(int)} 621 */ 622 AudioManager mAudioManager; 623 624 final AccessibilityManager mAccessibilityManager; 625 626 AccessibilityInteractionController mAccessibilityInteractionController; 627 628 final AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager = 629 new AccessibilityInteractionConnectionManager(); 630 final HighContrastTextManager mHighContrastTextManager; 631 632 SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent; 633 634 HashSet<View> mTempHashSet; 635 636 private final int mDensity; 637 private final int mNoncompatDensity; 638 639 private boolean mInLayout = false; 640 ArrayList<View> mLayoutRequesters = new ArrayList<View>(); 641 boolean mHandlingLayoutInLayoutRequest = false; 642 643 private int mViewLayoutDirectionInitial; 644 645 /** Set to true once doDie() has been called. */ 646 private boolean mRemoved; 647 648 private boolean mNeedsRendererSetup; 649 650 private final InputEventCompatProcessor mInputCompatProcessor; 651 652 /** 653 * Consistency verifier for debugging purposes. 654 */ 655 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 656 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 657 new InputEventConsistencyVerifier(this, 0) : null; 658 659 private final InsetsController mInsetsController; 660 private final ImeFocusController mImeFocusController; 661 662 private ScrollCaptureClient mScrollCaptureClient; 663 664 /** 665 * @return {@link ImeFocusController} for this instance. 666 */ 667 @NonNull getImeFocusController()668 public ImeFocusController getImeFocusController() { 669 return mImeFocusController; 670 } 671 672 /** @return The current {@link ScrollCaptureClient} for this instance, if any is active. */ 673 @Nullable getScrollCaptureClient()674 public ScrollCaptureClient getScrollCaptureClient() { 675 return mScrollCaptureClient; 676 } 677 678 private final GestureExclusionTracker mGestureExclusionTracker = new GestureExclusionTracker(); 679 680 private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection; 681 682 static final class SystemUiVisibilityInfo { 683 int seq; 684 int globalVisibility; 685 int localValue; 686 int localChanges; 687 } 688 689 // If set, ViewRootImpl will call BLASTBufferQueue::setNextTransaction with 690 // mRtBLASTSyncTransaction, prior to invoking draw. This provides a way 691 // to redirect the buffers in to transactions. 692 private boolean mNextDrawUseBLASTSyncTransaction; 693 // Set when calling setNextTransaction, we can't just reuse mNextDrawUseBLASTSyncTransaction 694 // because, imagine this scenario: 695 // 1. First draw is using BLAST, mNextDrawUseBLAST = true 696 // 2. We call perform draw and are waiting on the callback 697 // 3. After the first perform draw but before the first callback and the 698 // second perform draw, a second draw sets mNextDrawUseBLAST = true (it already was) 699 // 4. At this point the callback fires and we set mNextDrawUseBLAST = false; 700 // 5. We get to performDraw and fail to sync as we intended because mNextDrawUseBLAST 701 // is now false. 702 // This is why we use a two-step latch with the two booleans, one consumed from 703 // performDraw and one consumed from finishBLASTSync() 704 private boolean mNextReportConsumeBLAST; 705 // Be very careful with the threading here. This is used from the render thread while 706 // the UI thread is paused and then applied and cleared from the UI thread right after 707 // draw returns. 708 private SurfaceControl.Transaction mRtBLASTSyncTransaction = new SurfaceControl.Transaction(); 709 710 // Keeps track of whether the WM requested us to use BLAST Sync when calling relayout. 711 // We use this to make sure we don't send the WM transactions from an internal BLAST sync 712 // (e.g. SurfaceView) 713 private boolean mSendNextFrameToWm = false; 714 715 private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks; 716 717 private String mTag = TAG; 718 ViewRootImpl(Context context, Display display)719 public ViewRootImpl(Context context, Display display) { 720 this(context, display, WindowManagerGlobal.getWindowSession(), 721 false /* useSfChoreographer */); 722 } 723 ViewRootImpl(Context context, Display display, IWindowSession session)724 public ViewRootImpl(Context context, Display display, IWindowSession session) { 725 this(context, display, session, false /* useSfChoreographer */); 726 } 727 ViewRootImpl(Context context, Display display, IWindowSession session, boolean useSfChoreographer)728 public ViewRootImpl(Context context, Display display, IWindowSession session, 729 boolean useSfChoreographer) { 730 mContext = context; 731 mWindowSession = session; 732 mDisplay = display; 733 mBasePackageName = context.getBasePackageName(); 734 mThread = Thread.currentThread(); 735 mLocation = new WindowLeaked(null); 736 mLocation.fillInStackTrace(); 737 mWidth = -1; 738 mHeight = -1; 739 mDirty = new Rect(); 740 mTempRect = new Rect(); 741 mVisRect = new Rect(); 742 mWinFrame = new Rect(); 743 mWindow = new W(this); 744 mLeashToken = new Binder(); 745 mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion; 746 mViewVisibility = View.GONE; 747 mTransparentRegion = new Region(); 748 mPreviousTransparentRegion = new Region(); 749 mFirst = true; // true for the first time the view is added 750 mPerformContentCapture = true; // also true for the first time the view is added 751 mAdded = false; 752 mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this, 753 context); 754 mCompatibleVisibilityInfo = new SystemUiVisibilityInfo(); 755 mAccessibilityManager = AccessibilityManager.getInstance(context); 756 mAccessibilityManager.addAccessibilityStateChangeListener( 757 mAccessibilityInteractionConnectionManager, mHandler); 758 mHighContrastTextManager = new HighContrastTextManager(); 759 mAccessibilityManager.addHighTextContrastStateChangeListener( 760 mHighContrastTextManager, mHandler); 761 mViewConfiguration = ViewConfiguration.get(context); 762 mDensity = context.getResources().getDisplayMetrics().densityDpi; 763 mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi; 764 mFallbackEventHandler = new PhoneFallbackEventHandler(context); 765 mChoreographer = useSfChoreographer 766 ? Choreographer.getSfInstance() : Choreographer.getInstance(); 767 mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); 768 mInsetsController = new InsetsController(new ViewRootInsetsControllerHost(this)); 769 770 String processorOverrideName = context.getResources().getString( 771 R.string.config_inputEventCompatProcessorOverrideClassName); 772 if (processorOverrideName.isEmpty()) { 773 // No compatibility processor override, using default. 774 mInputCompatProcessor = new InputEventCompatProcessor(context); 775 } else { 776 InputEventCompatProcessor compatProcessor = null; 777 try { 778 final Class<? extends InputEventCompatProcessor> klass = 779 (Class<? extends InputEventCompatProcessor>) Class.forName( 780 processorOverrideName); 781 compatProcessor = klass.getConstructor(Context.class).newInstance(context); 782 } catch (Exception e) { 783 Log.e(TAG, "Unable to create the InputEventCompatProcessor. ", e); 784 } finally { 785 mInputCompatProcessor = compatProcessor; 786 } 787 } 788 789 if (!sCompatibilityDone) { 790 sAlwaysAssignFocus = mTargetSdkVersion < Build.VERSION_CODES.P; 791 792 sCompatibilityDone = true; 793 } 794 795 loadSystemProperties(); 796 mImeFocusController = new ImeFocusController(this); 797 } 798 799 public static void addFirstDrawHandler(Runnable callback) { 800 synchronized (sFirstDrawHandlers) { 801 if (!sFirstDrawComplete) { 802 sFirstDrawHandlers.add(callback); 803 } 804 } 805 } 806 807 /** Add static config callback to be notified about global config changes. */ 808 @UnsupportedAppUsage 809 public static void addConfigCallback(ConfigChangedCallback callback) { 810 synchronized (sConfigCallbacks) { 811 sConfigCallbacks.add(callback); 812 } 813 } 814 815 /** Add activity config callback to be notified about override config changes. */ 816 public void setActivityConfigCallback(ActivityConfigCallback callback) { 817 mActivityConfigCallback = callback; 818 } 819 820 public void setOnContentApplyWindowInsetsListener(OnContentApplyWindowInsetsListener listener) { 821 mAttachInfo.mContentOnApplyWindowInsetsListener = listener; 822 823 // System windows will be fitted on first traversal, so no reason to request additional 824 // (possibly getting executed after the first traversal). 825 if (!mFirst) { 826 requestFitSystemWindows(); 827 } 828 } 829 830 public void addWindowCallbacks(WindowCallbacks callback) { 831 synchronized (mWindowCallbacks) { 832 mWindowCallbacks.add(callback); 833 } 834 } 835 836 public void removeWindowCallbacks(WindowCallbacks callback) { 837 synchronized (mWindowCallbacks) { 838 mWindowCallbacks.remove(callback); 839 } 840 } 841 842 public void reportDrawFinish() { 843 if (mWindowDrawCountDown != null) { 844 mWindowDrawCountDown.countDown(); 845 } 846 } 847 848 // FIXME for perf testing only 849 private boolean mProfile = false; 850 851 /** 852 * Call this to profile the next traversal call. 853 * FIXME for perf testing only. Remove eventually 854 */ 855 public void profile() { 856 mProfile = true; 857 } 858 859 /** 860 * Indicates whether we are in touch mode. Calling this method triggers an IPC 861 * call and should be avoided whenever possible. 862 * 863 * @return True, if the device is in touch mode, false otherwise. 864 * 865 * @hide 866 */ 867 static boolean isInTouchMode() { 868 IWindowSession windowSession = WindowManagerGlobal.peekWindowSession(); 869 if (windowSession != null) { 870 try { 871 return windowSession.getInTouchMode(); 872 } catch (RemoteException e) { 873 } 874 } 875 return false; 876 } 877 878 /** 879 * Notifies us that our child has been rebuilt, following 880 * a window preservation operation. In these cases we 881 * keep the same DecorView, but the activity controlling it 882 * is a different instance, and we need to update our 883 * callbacks. 884 * 885 * @hide 886 */ 887 public void notifyChildRebuilt() { 888 if (mView instanceof RootViewSurfaceTaker) { 889 if (mSurfaceHolderCallback != null) { 890 mSurfaceHolder.removeCallback(mSurfaceHolderCallback); 891 } 892 893 mSurfaceHolderCallback = 894 ((RootViewSurfaceTaker)mView).willYouTakeTheSurface(); 895 896 if (mSurfaceHolderCallback != null) { 897 mSurfaceHolder = new TakenSurfaceHolder(); 898 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN); 899 mSurfaceHolder.addCallback(mSurfaceHolderCallback); 900 } else { 901 mSurfaceHolder = null; 902 } 903 904 mInputQueueCallback = 905 ((RootViewSurfaceTaker)mView).willYouTakeTheInputQueue(); 906 if (mInputQueueCallback != null) { 907 mInputQueueCallback.onInputQueueCreated(mInputQueue); 908 } 909 } 910 } 911 912 /** 913 * We have one child 914 */ 915 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { 916 setView(view, attrs, panelParentView, UserHandle.myUserId()); 917 } 918 919 /** 920 * We have one child 921 */ 922 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, 923 int userId) { 924 synchronized (this) { 925 if (mView == null) { 926 mView = view; 927 928 mAttachInfo.mDisplayState = mDisplay.getState(); 929 mDisplayManager.registerDisplayListener(mDisplayListener, mHandler); 930 931 mViewLayoutDirectionInitial = mView.getRawLayoutDirection(); 932 mFallbackEventHandler.setView(view); 933 mWindowAttributes.copyFrom(attrs); 934 if (mWindowAttributes.packageName == null) { 935 mWindowAttributes.packageName = mBasePackageName; 936 } 937 mWindowAttributes.privateFlags |= 938 WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST; 939 940 attrs = mWindowAttributes; 941 setTag(); 942 943 if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags 944 & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0 945 && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) { 946 Slog.d(mTag, "setView: FLAG_KEEP_SCREEN_ON changed from true to false!"); 947 } 948 // Keep track of the actual window flags supplied by the client. 949 mClientWindowLayoutFlags = attrs.flags; 950 951 setAccessibilityFocus(null, null); 952 953 if (view instanceof RootViewSurfaceTaker) { 954 mSurfaceHolderCallback = 955 ((RootViewSurfaceTaker)view).willYouTakeTheSurface(); 956 if (mSurfaceHolderCallback != null) { 957 mSurfaceHolder = new TakenSurfaceHolder(); 958 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN); 959 mSurfaceHolder.addCallback(mSurfaceHolderCallback); 960 } 961 } 962 963 // Compute surface insets required to draw at specified Z value. 964 // TODO: Use real shadow insets for a constant max Z. 965 if (!attrs.hasManualSurfaceInsets) { 966 attrs.setSurfaceInsets(view, false /*manual*/, true /*preservePrevious*/); 967 } 968 969 CompatibilityInfo compatibilityInfo = 970 mDisplay.getDisplayAdjustments().getCompatibilityInfo(); 971 mTranslator = compatibilityInfo.getTranslator(); 972 973 // If the application owns the surface, don't enable hardware acceleration 974 if (mSurfaceHolder == null) { 975 // While this is supposed to enable only, it can effectively disable 976 // the acceleration too. 977 enableHardwareAcceleration(attrs); 978 final boolean useMTRenderer = MT_RENDERER_AVAILABLE 979 && mAttachInfo.mThreadedRenderer != null; 980 if (mUseMTRenderer != useMTRenderer) { 981 // Shouldn't be resizing, as it's done only in window setup, 982 // but end just in case. 983 endDragResizing(); 984 mUseMTRenderer = useMTRenderer; 985 } 986 } 987 988 boolean restore = false; 989 if (mTranslator != null) { 990 mSurface.setCompatibilityTranslator(mTranslator); 991 restore = true; 992 attrs.backup(); 993 mTranslator.translateWindowLayout(attrs); 994 } 995 if (DEBUG_LAYOUT) Log.d(mTag, "WindowLayout in setView:" + attrs); 996 997 if (!compatibilityInfo.supportsScreen()) { 998 attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; 999 mLastInCompatMode = true; 1000 } 1001 1002 mSoftInputMode = attrs.softInputMode; 1003 mWindowAttributesChanged = true; 1004 mAttachInfo.mRootView = view; 1005 mAttachInfo.mScalingRequired = mTranslator != null; 1006 mAttachInfo.mApplicationScale = 1007 mTranslator == null ? 1.0f : mTranslator.applicationScale; 1008 if (panelParentView != null) { 1009 mAttachInfo.mPanelParentWindowToken 1010 = panelParentView.getApplicationWindowToken(); 1011 } 1012 mAdded = true; 1013 int res; /* = WindowManagerImpl.ADD_OKAY; */ 1014 1015 // Schedule the first layout -before- adding to the window 1016 // manager, to make sure we do the relayout before receiving 1017 // any other events from the system. 1018 requestLayout(); 1019 InputChannel inputChannel = null; 1020 if ((mWindowAttributes.inputFeatures 1021 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) { 1022 inputChannel = new InputChannel(); 1023 } 1024 mForceDecorViewVisibility = (mWindowAttributes.privateFlags 1025 & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0; 1026 try { 1027 mOrigWindowType = mWindowAttributes.type; 1028 mAttachInfo.mRecomputeGlobalAttributes = true; 1029 collectViewAttributes(); 1030 adjustLayoutParamsForCompatibility(mWindowAttributes); 1031 res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes, 1032 getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame, 1033 mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, 1034 mAttachInfo.mDisplayCutout, inputChannel, 1035 mTempInsets, mTempControls); 1036 setFrame(mTmpFrame); 1037 } catch (RemoteException e) { 1038 mAdded = false; 1039 mView = null; 1040 mAttachInfo.mRootView = null; 1041 inputChannel = null; 1042 mFallbackEventHandler.setView(null); 1043 unscheduleTraversals(); 1044 setAccessibilityFocus(null, null); 1045 throw new RuntimeException("Adding window failed", e); 1046 } finally { 1047 if (restore) { 1048 attrs.restore(); 1049 } 1050 } 1051 1052 if (mTranslator != null) { 1053 mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets); 1054 } 1055 mPendingDisplayCutout.set(mAttachInfo.mDisplayCutout); 1056 mAttachInfo.mAlwaysConsumeSystemBars = 1057 (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS) != 0; 1058 mPendingAlwaysConsumeSystemBars = mAttachInfo.mAlwaysConsumeSystemBars; 1059 mInsetsController.onStateChanged(mTempInsets); 1060 mInsetsController.onControlsChanged(mTempControls); 1061 if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow); 1062 if (res < WindowManagerGlobal.ADD_OKAY) { 1063 mAttachInfo.mRootView = null; 1064 mAdded = false; 1065 mFallbackEventHandler.setView(null); 1066 unscheduleTraversals(); 1067 setAccessibilityFocus(null, null); 1068 switch (res) { 1069 case WindowManagerGlobal.ADD_BAD_APP_TOKEN: 1070 case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN: 1071 throw new WindowManager.BadTokenException( 1072 "Unable to add window -- token " + attrs.token 1073 + " is not valid; is your activity running?"); 1074 case WindowManagerGlobal.ADD_NOT_APP_TOKEN: 1075 throw new WindowManager.BadTokenException( 1076 "Unable to add window -- token " + attrs.token 1077 + " is not for an application"); 1078 case WindowManagerGlobal.ADD_APP_EXITING: 1079 throw new WindowManager.BadTokenException( 1080 "Unable to add window -- app for token " + attrs.token 1081 + " is exiting"); 1082 case WindowManagerGlobal.ADD_DUPLICATE_ADD: 1083 throw new WindowManager.BadTokenException( 1084 "Unable to add window -- window " + mWindow 1085 + " has already been added"); 1086 case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED: 1087 // Silently ignore -- we would have just removed it 1088 // right away, anyway. 1089 return; 1090 case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON: 1091 throw new WindowManager.BadTokenException("Unable to add window " 1092 + mWindow + " -- another window of type " 1093 + mWindowAttributes.type + " already exists"); 1094 case WindowManagerGlobal.ADD_PERMISSION_DENIED: 1095 throw new WindowManager.BadTokenException("Unable to add window " 1096 + mWindow + " -- permission denied for window type " 1097 + mWindowAttributes.type); 1098 case WindowManagerGlobal.ADD_INVALID_DISPLAY: 1099 throw new WindowManager.InvalidDisplayException("Unable to add window " 1100 + mWindow + " -- the specified display can not be found"); 1101 case WindowManagerGlobal.ADD_INVALID_TYPE: 1102 throw new WindowManager.InvalidDisplayException("Unable to add window " 1103 + mWindow + " -- the specified window type " 1104 + mWindowAttributes.type + " is not valid"); 1105 case WindowManagerGlobal.ADD_INVALID_USER: 1106 throw new WindowManager.BadTokenException("Unable to add Window " 1107 + mWindow + " -- requested userId is not valid"); 1108 } 1109 throw new RuntimeException( 1110 "Unable to add window -- unknown error code " + res); 1111 } 1112 1113 if ((res & WindowManagerGlobal.ADD_FLAG_USE_BLAST) != 0) { 1114 mUseBLASTAdapter = true; 1115 } 1116 if ((res & WindowManagerGlobal.ADD_FLAG_USE_TRIPLE_BUFFERING) != 0) { 1117 mEnableTripleBuffering = true; 1118 } 1119 1120 if (view instanceof RootViewSurfaceTaker) { 1121 mInputQueueCallback = 1122 ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue(); 1123 } 1124 if (inputChannel != null) { 1125 if (mInputQueueCallback != null) { 1126 mInputQueue = new InputQueue(); 1127 mInputQueueCallback.onInputQueueCreated(mInputQueue); 1128 } 1129 mInputEventReceiver = new WindowInputEventReceiver(inputChannel, 1130 Looper.myLooper()); 1131 } 1132 1133 view.assignParent(this); 1134 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0; 1135 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0; 1136 1137 if (mAccessibilityManager.isEnabled()) { 1138 mAccessibilityInteractionConnectionManager.ensureConnection(); 1139 } 1140 1141 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 1142 view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); 1143 } 1144 1145 // Set up the input pipeline. 1146 CharSequence counterSuffix = attrs.getTitle(); 1147 mSyntheticInputStage = new SyntheticInputStage(); 1148 InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage); 1149 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage, 1150 "aq:native-post-ime:" + counterSuffix); 1151 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage); 1152 InputStage imeStage = new ImeInputStage(earlyPostImeStage, 1153 "aq:ime:" + counterSuffix); 1154 InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage); 1155 InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage, 1156 "aq:native-pre-ime:" + counterSuffix); 1157 1158 mFirstInputStage = nativePreImeStage; 1159 mFirstPostImeInputStage = earlyPostImeStage; 1160 mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix; 1161 1162 if (mView instanceof RootViewSurfaceTaker) { 1163 PendingInsetsController pendingInsetsController = 1164 ((RootViewSurfaceTaker) mView).providePendingInsetsController(); 1165 if (pendingInsetsController != null) { 1166 pendingInsetsController.replayAndAttach(mInsetsController); 1167 } 1168 } 1169 } 1170 } 1171 } 1172 1173 private void setTag() { 1174 final String[] split = mWindowAttributes.getTitle().toString().split("\\."); 1175 if (split.length > 0) { 1176 mTag = TAG + "[" + split[split.length - 1] + "]"; 1177 } 1178 } 1179 1180 @UnsupportedAppUsage 1181 public int getWindowFlags() { 1182 return mWindowAttributes.flags; 1183 } 1184 1185 public int getDisplayId() { 1186 return mDisplay.getDisplayId(); 1187 } 1188 1189 public CharSequence getTitle() { 1190 return mWindowAttributes.getTitle(); 1191 } 1192 1193 /** 1194 * @return the width of the root view. Note that this will return {@code -1} until the first 1195 * layout traversal, when the width is set. 1196 * 1197 * @hide 1198 */ 1199 public int getWidth() { 1200 return mWidth; 1201 } 1202 1203 /** 1204 * @return the height of the root view. Note that this will return {@code -1} until the first 1205 * layout traversal, when the height is set. 1206 * 1207 * @hide 1208 */ 1209 public int getHeight() { 1210 return mHeight; 1211 } 1212 1213 /** 1214 * Destroys hardware rendering resources for this ViewRootImpl 1215 * 1216 * May be called on any thread 1217 */ 1218 @AnyThread 1219 void destroyHardwareResources() { 1220 final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer; 1221 if (renderer != null) { 1222 // This is called by WindowManagerGlobal which may or may not be on the right thread 1223 if (Looper.myLooper() != mAttachInfo.mHandler.getLooper()) { 1224 mAttachInfo.mHandler.postAtFrontOfQueue(this::destroyHardwareResources); 1225 return; 1226 } 1227 renderer.destroyHardwareResources(mView); 1228 renderer.destroy(); 1229 } 1230 } 1231 1232 @UnsupportedAppUsage 1233 public void detachFunctor(long functor) { 1234 if (mAttachInfo.mThreadedRenderer != null) { 1235 // Fence so that any pending invokeFunctor() messages will be processed 1236 // before we return from detachFunctor. 1237 mAttachInfo.mThreadedRenderer.stopDrawing(); 1238 } 1239 } 1240 1241 /** 1242 * Schedules the functor for execution in either kModeProcess or 1243 * kModeProcessNoContext, depending on whether or not there is an EGLContext. 1244 * 1245 * @param functor The native functor to invoke 1246 * @param waitForCompletion If true, this will not return until the functor 1247 * has invoked. If false, the functor may be invoked 1248 * asynchronously. 1249 */ 1250 @UnsupportedAppUsage 1251 public static void invokeFunctor(long functor, boolean waitForCompletion) { 1252 ThreadedRenderer.invokeFunctor(functor, waitForCompletion); 1253 } 1254 1255 /** 1256 * @param animator animator to register with the hardware renderer 1257 */ 1258 public void registerAnimatingRenderNode(RenderNode animator) { 1259 if (mAttachInfo.mThreadedRenderer != null) { 1260 mAttachInfo.mThreadedRenderer.registerAnimatingRenderNode(animator); 1261 } else { 1262 if (mAttachInfo.mPendingAnimatingRenderNodes == null) { 1263 mAttachInfo.mPendingAnimatingRenderNodes = new ArrayList<RenderNode>(); 1264 } 1265 mAttachInfo.mPendingAnimatingRenderNodes.add(animator); 1266 } 1267 } 1268 1269 /** 1270 * @param animator animator to register with the hardware renderer 1271 */ 1272 public void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator) { 1273 if (mAttachInfo.mThreadedRenderer != null) { 1274 mAttachInfo.mThreadedRenderer.registerVectorDrawableAnimator(animator); 1275 } 1276 } 1277 1278 /** 1279 * Registers a callback to be executed when the next frame is being drawn on RenderThread. This 1280 * callback will be executed on a RenderThread worker thread, and only used for the next frame 1281 * and thus it will only fire once. 1282 * 1283 * @param callback The callback to register. 1284 */ 1285 public void registerRtFrameCallback(@NonNull FrameDrawingCallback callback) { 1286 if (mAttachInfo.mThreadedRenderer != null) { 1287 mAttachInfo.mThreadedRenderer.registerRtFrameCallback(frame -> { 1288 try { 1289 callback.onFrameDraw(frame); 1290 } catch (Exception e) { 1291 Log.e(TAG, "Exception while executing onFrameDraw", e); 1292 } 1293 }); 1294 } 1295 } 1296 1297 @UnsupportedAppUsage enableHardwareAcceleration(WindowManager.LayoutParams attrs)1298 private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) { 1299 mAttachInfo.mHardwareAccelerated = false; 1300 mAttachInfo.mHardwareAccelerationRequested = false; 1301 1302 // Don't enable hardware acceleration when the application is in compatibility mode 1303 if (mTranslator != null) return; 1304 1305 // Try to enable hardware acceleration if requested 1306 final boolean hardwareAccelerated = 1307 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0; 1308 1309 if (hardwareAccelerated) { 1310 if (!ThreadedRenderer.isAvailable()) { 1311 return; 1312 } 1313 1314 // Persistent processes (including the system) should not do 1315 // accelerated rendering on low-end devices. In that case, 1316 // sRendererDisabled will be set. In addition, the system process 1317 // itself should never do accelerated rendering. In that case, both 1318 // sRendererDisabled and sSystemRendererDisabled are set. When 1319 // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED 1320 // can be used by code on the system process to escape that and enable 1321 // HW accelerated drawing. (This is basically for the lock screen.) 1322 1323 final boolean fakeHwAccelerated = (attrs.privateFlags & 1324 WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0; 1325 final boolean forceHwAccelerated = (attrs.privateFlags & 1326 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0; 1327 1328 if (fakeHwAccelerated) { 1329 // This is exclusively for the preview windows the window manager 1330 // shows for launching applications, so they will look more like 1331 // the app being launched. 1332 mAttachInfo.mHardwareAccelerationRequested = true; 1333 } else if (!ThreadedRenderer.sRendererDisabled 1334 || (ThreadedRenderer.sSystemRendererDisabled && forceHwAccelerated)) { 1335 if (mAttachInfo.mThreadedRenderer != null) { 1336 mAttachInfo.mThreadedRenderer.destroy(); 1337 } 1338 1339 final Rect insets = attrs.surfaceInsets; 1340 final boolean hasSurfaceInsets = insets.left != 0 || insets.right != 0 1341 || insets.top != 0 || insets.bottom != 0; 1342 final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets; 1343 final boolean wideGamut = 1344 mContext.getResources().getConfiguration().isScreenWideColorGamut() 1345 && attrs.getColorMode() == ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT; 1346 1347 mAttachInfo.mThreadedRenderer = ThreadedRenderer.create(mContext, translucent, 1348 attrs.getTitle().toString()); 1349 mAttachInfo.mThreadedRenderer.setWideGamut(wideGamut); 1350 updateForceDarkMode(); 1351 if (mAttachInfo.mThreadedRenderer != null) { 1352 mAttachInfo.mHardwareAccelerated = 1353 mAttachInfo.mHardwareAccelerationRequested = true; 1354 } 1355 } 1356 } 1357 } 1358 getNightMode()1359 private int getNightMode() { 1360 return mContext.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; 1361 } 1362 updateForceDarkMode()1363 private void updateForceDarkMode() { 1364 if (mAttachInfo.mThreadedRenderer == null) return; 1365 1366 boolean useAutoDark = getNightMode() == Configuration.UI_MODE_NIGHT_YES; 1367 1368 if (useAutoDark) { 1369 boolean forceDarkAllowedDefault = 1370 SystemProperties.getBoolean(ThreadedRenderer.DEBUG_FORCE_DARK, false); 1371 TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme); 1372 useAutoDark = a.getBoolean(R.styleable.Theme_isLightTheme, true) 1373 && a.getBoolean(R.styleable.Theme_forceDarkAllowed, forceDarkAllowedDefault); 1374 a.recycle(); 1375 } 1376 1377 if (mAttachInfo.mThreadedRenderer.setForceDark(useAutoDark)) { 1378 // TODO: Don't require regenerating all display lists to apply this setting 1379 invalidateWorld(mView); 1380 } 1381 } 1382 1383 @UnsupportedAppUsage getView()1384 public View getView() { 1385 return mView; 1386 } 1387 getLocation()1388 final WindowLeaked getLocation() { 1389 return mLocation; 1390 } 1391 setLayoutParams(WindowManager.LayoutParams attrs, boolean newView)1392 void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) { 1393 synchronized (this) { 1394 final int oldInsetLeft = mWindowAttributes.surfaceInsets.left; 1395 final int oldInsetTop = mWindowAttributes.surfaceInsets.top; 1396 final int oldInsetRight = mWindowAttributes.surfaceInsets.right; 1397 final int oldInsetBottom = mWindowAttributes.surfaceInsets.bottom; 1398 final int oldSoftInputMode = mWindowAttributes.softInputMode; 1399 final boolean oldHasManualSurfaceInsets = mWindowAttributes.hasManualSurfaceInsets; 1400 1401 if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags 1402 & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0 1403 && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) { 1404 Slog.d(mTag, "setLayoutParams: FLAG_KEEP_SCREEN_ON from true to false!"); 1405 } 1406 1407 // Keep track of the actual window flags supplied by the client. 1408 mClientWindowLayoutFlags = attrs.flags; 1409 1410 // Preserve compatible window flag if exists. 1411 final int compatibleWindowFlag = mWindowAttributes.privateFlags 1412 & WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; 1413 1414 // Transfer over system UI visibility values as they carry current state. 1415 attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility; 1416 attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility; 1417 1418 final int changes = mWindowAttributes.copyFrom(attrs); 1419 if ((changes & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) { 1420 // Recompute system ui visibility. 1421 mAttachInfo.mRecomputeGlobalAttributes = true; 1422 } 1423 if ((changes & WindowManager.LayoutParams.LAYOUT_CHANGED) != 0) { 1424 // Request to update light center. 1425 mAttachInfo.mNeedsUpdateLightCenter = true; 1426 } 1427 if (mWindowAttributes.packageName == null) { 1428 mWindowAttributes.packageName = mBasePackageName; 1429 } 1430 mWindowAttributes.privateFlags |= compatibleWindowFlag; 1431 1432 mWindowAttributes.privateFlags |= 1433 WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST; 1434 1435 if (mWindowAttributes.preservePreviousSurfaceInsets) { 1436 // Restore old surface insets. 1437 mWindowAttributes.surfaceInsets.set( 1438 oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom); 1439 mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets; 1440 } else if (mWindowAttributes.surfaceInsets.left != oldInsetLeft 1441 || mWindowAttributes.surfaceInsets.top != oldInsetTop 1442 || mWindowAttributes.surfaceInsets.right != oldInsetRight 1443 || mWindowAttributes.surfaceInsets.bottom != oldInsetBottom) { 1444 mNeedsRendererSetup = true; 1445 } 1446 1447 applyKeepScreenOnFlag(mWindowAttributes); 1448 1449 if (newView) { 1450 mSoftInputMode = attrs.softInputMode; 1451 requestLayout(); 1452 } 1453 1454 // Don't lose the mode we last auto-computed. 1455 if ((attrs.softInputMode & SOFT_INPUT_MASK_ADJUST) 1456 == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) { 1457 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode 1458 & ~SOFT_INPUT_MASK_ADJUST) | (oldSoftInputMode & SOFT_INPUT_MASK_ADJUST); 1459 } 1460 1461 if (mWindowAttributes.softInputMode != oldSoftInputMode) { 1462 requestFitSystemWindows(); 1463 } 1464 1465 mWindowAttributesChanged = true; 1466 scheduleTraversals(); 1467 } 1468 } 1469 handleAppVisibility(boolean visible)1470 void handleAppVisibility(boolean visible) { 1471 if (mAppVisible != visible) { 1472 mAppVisible = visible; 1473 mAppVisibilityChanged = true; 1474 scheduleTraversals(); 1475 if (!mAppVisible) { 1476 WindowManagerGlobal.trimForeground(); 1477 } 1478 } 1479 } 1480 handleGetNewSurface()1481 void handleGetNewSurface() { 1482 mNewSurfaceNeeded = true; 1483 mFullRedrawNeeded = true; 1484 scheduleTraversals(); 1485 } 1486 1487 private final DisplayListener mDisplayListener = new DisplayListener() { 1488 @Override 1489 public void onDisplayChanged(int displayId) { 1490 if (mView != null && mDisplay.getDisplayId() == displayId) { 1491 final int oldDisplayState = mAttachInfo.mDisplayState; 1492 final int newDisplayState = mDisplay.getState(); 1493 if (oldDisplayState != newDisplayState) { 1494 mAttachInfo.mDisplayState = newDisplayState; 1495 pokeDrawLockIfNeeded(); 1496 if (oldDisplayState != Display.STATE_UNKNOWN) { 1497 final int oldScreenState = toViewScreenState(oldDisplayState); 1498 final int newScreenState = toViewScreenState(newDisplayState); 1499 if (oldScreenState != newScreenState) { 1500 mView.dispatchScreenStateChanged(newScreenState); 1501 } 1502 if (oldDisplayState == Display.STATE_OFF) { 1503 // Draw was suppressed so we need to for it to happen here. 1504 mFullRedrawNeeded = true; 1505 scheduleTraversals(); 1506 } 1507 } 1508 } 1509 } 1510 } 1511 1512 @Override 1513 public void onDisplayRemoved(int displayId) { 1514 } 1515 1516 @Override 1517 public void onDisplayAdded(int displayId) { 1518 } 1519 1520 private int toViewScreenState(int displayState) { 1521 return displayState == Display.STATE_OFF ? 1522 View.SCREEN_STATE_OFF : View.SCREEN_STATE_ON; 1523 } 1524 }; 1525 1526 /** 1527 * Notify about move to a different display. 1528 * @param displayId The id of the display where this view root is moved to. 1529 * @param config Configuration of the resources on new display after move. 1530 * 1531 * @hide 1532 */ onMovedToDisplay(int displayId, Configuration config)1533 public void onMovedToDisplay(int displayId, Configuration config) { 1534 if (mDisplay.getDisplayId() == displayId) { 1535 return; 1536 } 1537 1538 // Get new instance of display based on current display adjustments. It may be updated later 1539 // if moving between the displays also involved a configuration change. 1540 updateInternalDisplay(displayId, mView.getResources()); 1541 mImeFocusController.onMovedToDisplay(); 1542 mAttachInfo.mDisplayState = mDisplay.getState(); 1543 // Internal state updated, now notify the view hierarchy. 1544 mView.dispatchMovedToDisplay(mDisplay, config); 1545 } 1546 1547 /** 1548 * Updates {@link #mDisplay} to the display object corresponding to {@param displayId}. 1549 * Uses DEFAULT_DISPLAY if there isn't a display object in the system corresponding 1550 * to {@param displayId}. 1551 */ updateInternalDisplay(int displayId, Resources resources)1552 private void updateInternalDisplay(int displayId, Resources resources) { 1553 final Display preferredDisplay = 1554 ResourcesManager.getInstance().getAdjustedDisplay(displayId, resources); 1555 if (preferredDisplay == null) { 1556 // Fallback to use default display. 1557 Slog.w(TAG, "Cannot get desired display with Id: " + displayId); 1558 mDisplay = ResourcesManager.getInstance() 1559 .getAdjustedDisplay(DEFAULT_DISPLAY, resources); 1560 } else { 1561 mDisplay = preferredDisplay; 1562 } 1563 mContext.updateDisplay(mDisplay.getDisplayId()); 1564 } 1565 pokeDrawLockIfNeeded()1566 void pokeDrawLockIfNeeded() { 1567 final int displayState = mAttachInfo.mDisplayState; 1568 if (mView != null && mAdded && mTraversalScheduled 1569 && (displayState == Display.STATE_DOZE 1570 || displayState == Display.STATE_DOZE_SUSPEND)) { 1571 try { 1572 mWindowSession.pokeDrawLock(mWindow); 1573 } catch (RemoteException ex) { 1574 // System server died, oh well. 1575 } 1576 } 1577 } 1578 1579 @Override requestFitSystemWindows()1580 public void requestFitSystemWindows() { 1581 checkThread(); 1582 mApplyInsetsRequested = true; 1583 scheduleTraversals(); 1584 } 1585 notifyInsetsChanged()1586 void notifyInsetsChanged() { 1587 if (sNewInsetsMode == NEW_INSETS_MODE_NONE) { 1588 return; 1589 } 1590 mApplyInsetsRequested = true; 1591 requestLayout(); 1592 1593 // See comment for View.sForceLayoutWhenInsetsChanged 1594 if (View.sForceLayoutWhenInsetsChanged && mView != null) { 1595 forceLayout(mView); 1596 } 1597 1598 // If this changes during traversal, no need to schedule another one as it will dispatch it 1599 // during the current traversal. 1600 if (!mIsInTraversal) { 1601 scheduleTraversals(); 1602 } 1603 } 1604 1605 @Override requestLayout()1606 public void requestLayout() { 1607 if (!mHandlingLayoutInLayoutRequest) { 1608 checkThread(); 1609 mLayoutRequested = true; 1610 scheduleTraversals(); 1611 } 1612 } 1613 1614 @Override isLayoutRequested()1615 public boolean isLayoutRequested() { 1616 return mLayoutRequested; 1617 } 1618 1619 @Override onDescendantInvalidated(@onNull View child, @NonNull View descendant)1620 public void onDescendantInvalidated(@NonNull View child, @NonNull View descendant) { 1621 // TODO: Re-enable after camera is fixed or consider targetSdk checking this 1622 // checkThread(); 1623 if ((descendant.mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 1624 mIsAnimating = true; 1625 } 1626 invalidate(); 1627 } 1628 1629 @UnsupportedAppUsage invalidate()1630 void invalidate() { 1631 mDirty.set(0, 0, mWidth, mHeight); 1632 if (!mWillDrawSoon) { 1633 scheduleTraversals(); 1634 } 1635 } 1636 invalidateWorld(View view)1637 void invalidateWorld(View view) { 1638 view.invalidate(); 1639 if (view instanceof ViewGroup) { 1640 ViewGroup parent = (ViewGroup) view; 1641 for (int i = 0; i < parent.getChildCount(); i++) { 1642 invalidateWorld(parent.getChildAt(i)); 1643 } 1644 } 1645 } 1646 1647 @Override invalidateChild(View child, Rect dirty)1648 public void invalidateChild(View child, Rect dirty) { 1649 invalidateChildInParent(null, dirty); 1650 } 1651 1652 @Override invalidateChildInParent(int[] location, Rect dirty)1653 public ViewParent invalidateChildInParent(int[] location, Rect dirty) { 1654 checkThread(); 1655 if (DEBUG_DRAW) Log.v(mTag, "Invalidate child: " + dirty); 1656 1657 if (dirty == null) { 1658 invalidate(); 1659 return null; 1660 } else if (dirty.isEmpty() && !mIsAnimating) { 1661 return null; 1662 } 1663 1664 if (mCurScrollY != 0 || mTranslator != null) { 1665 mTempRect.set(dirty); 1666 dirty = mTempRect; 1667 if (mCurScrollY != 0) { 1668 dirty.offset(0, -mCurScrollY); 1669 } 1670 if (mTranslator != null) { 1671 mTranslator.translateRectInAppWindowToScreen(dirty); 1672 } 1673 if (mAttachInfo.mScalingRequired) { 1674 dirty.inset(-1, -1); 1675 } 1676 } 1677 1678 invalidateRectOnScreen(dirty); 1679 1680 return null; 1681 } 1682 invalidateRectOnScreen(Rect dirty)1683 private void invalidateRectOnScreen(Rect dirty) { 1684 final Rect localDirty = mDirty; 1685 1686 // Add the new dirty rect to the current one 1687 localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom); 1688 // Intersect with the bounds of the window to skip 1689 // updates that lie outside of the visible region 1690 final float appScale = mAttachInfo.mApplicationScale; 1691 final boolean intersected = localDirty.intersect(0, 0, 1692 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f)); 1693 if (!intersected) { 1694 localDirty.setEmpty(); 1695 } 1696 if (!mWillDrawSoon && (intersected || mIsAnimating)) { 1697 scheduleTraversals(); 1698 } 1699 } 1700 setIsAmbientMode(boolean ambient)1701 public void setIsAmbientMode(boolean ambient) { 1702 mIsAmbientMode = ambient; 1703 } 1704 setWindowStopped(boolean stopped)1705 void setWindowStopped(boolean stopped) { 1706 checkThread(); 1707 if (mStopped != stopped) { 1708 mStopped = stopped; 1709 final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer; 1710 if (renderer != null) { 1711 if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped); 1712 renderer.setStopped(mStopped); 1713 } 1714 if (!mStopped) { 1715 mNewSurfaceNeeded = true; 1716 scheduleTraversals(); 1717 } else { 1718 if (renderer != null) { 1719 renderer.destroyHardwareResources(mView); 1720 } 1721 1722 if (mSurface.isValid()) { 1723 if (mSurfaceHolder != null) { 1724 notifyHolderSurfaceDestroyed(); 1725 } 1726 notifySurfaceDestroyed(); 1727 } 1728 destroySurface(); 1729 } 1730 } 1731 scheduleConsumeBatchedInputImmediately(); 1732 } 1733 1734 1735 /** Register callbacks to be notified when the ViewRootImpl surface changes. */ 1736 interface SurfaceChangedCallback { surfaceCreated(Transaction t)1737 void surfaceCreated(Transaction t); surfaceReplaced(Transaction t)1738 void surfaceReplaced(Transaction t); surfaceDestroyed()1739 void surfaceDestroyed(); 1740 } 1741 1742 private final ArrayList<SurfaceChangedCallback> mSurfaceChangedCallbacks = new ArrayList<>(); addSurfaceChangedCallback(SurfaceChangedCallback c)1743 void addSurfaceChangedCallback(SurfaceChangedCallback c) { 1744 mSurfaceChangedCallbacks.add(c); 1745 } 1746 removeSurfaceChangedCallback(SurfaceChangedCallback c)1747 void removeSurfaceChangedCallback(SurfaceChangedCallback c) { 1748 mSurfaceChangedCallbacks.remove(c); 1749 } 1750 notifySurfaceCreated()1751 private void notifySurfaceCreated() { 1752 for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) { 1753 mSurfaceChangedCallbacks.get(i).surfaceCreated(mSurfaceChangedTransaction); 1754 } 1755 } 1756 1757 /** 1758 * Notify listeners when the ViewRootImpl surface has been replaced. This callback will not be 1759 * called if a new surface is created, only if the valid surface has been replaced with another 1760 * valid surface. 1761 */ notifySurfaceReplaced()1762 private void notifySurfaceReplaced() { 1763 for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) { 1764 mSurfaceChangedCallbacks.get(i).surfaceReplaced(mSurfaceChangedTransaction); 1765 } 1766 } 1767 notifySurfaceDestroyed()1768 private void notifySurfaceDestroyed() { 1769 for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) { 1770 mSurfaceChangedCallbacks.get(i).surfaceDestroyed(); 1771 } 1772 } 1773 1774 /** 1775 * @return child layer with the same bounds as its parent {@code mSurface} and cropped to the 1776 * surface insets. If the layer does not exist, it is created. 1777 * 1778 * <p>Parenting to this layer will ensure that its children are cropped by the view's surface 1779 * insets. 1780 */ getBoundsLayer()1781 public SurfaceControl getBoundsLayer() { 1782 if (mBoundsLayer == null) { 1783 mBoundsLayer = new SurfaceControl.Builder(mSurfaceSession) 1784 .setContainerLayer() 1785 .setName("Bounds for - " + getTitle().toString()) 1786 .setParent(getRenderSurfaceControl()) 1787 .setCallsite("ViewRootImpl.getBoundsLayer") 1788 .build(); 1789 setBoundsLayerCrop(); 1790 mTransaction.show(mBoundsLayer).apply(); 1791 } 1792 return mBoundsLayer; 1793 } 1794 getOrCreateBLASTSurface(int width, int height)1795 Surface getOrCreateBLASTSurface(int width, int height) { 1796 if (mSurfaceControl == null 1797 || !mSurfaceControl.isValid() 1798 || mBlastSurfaceControl == null 1799 || !mBlastSurfaceControl.isValid()) { 1800 return null; 1801 } 1802 1803 Surface ret = null; 1804 if (mBlastBufferQueue == null) { 1805 mBlastBufferQueue = new BLASTBufferQueue( 1806 mBlastSurfaceControl, width, height, mEnableTripleBuffering); 1807 // We only return the Surface the first time, as otherwise 1808 // it hasn't changed and there is no need to update. 1809 ret = mBlastBufferQueue.getSurface(); 1810 } else { 1811 mBlastBufferQueue.update(mBlastSurfaceControl, width, height); 1812 } 1813 1814 return ret; 1815 } 1816 setBoundsLayerCrop()1817 private void setBoundsLayerCrop() { 1818 // mWinFrame is already adjusted for surface insets. So offset it and use it as 1819 // the cropping bounds. 1820 mTempBoundsRect.set(mWinFrame); 1821 mTempBoundsRect.offsetTo(mWindowAttributes.surfaceInsets.left, 1822 mWindowAttributes.surfaceInsets.top); 1823 mTransaction.setWindowCrop(mBoundsLayer, mTempBoundsRect); 1824 } 1825 1826 /** 1827 * Called after window layout to update the bounds surface. If the surface insets have changed 1828 * or the surface has resized, update the bounds surface. 1829 */ updateBoundsLayer()1830 private void updateBoundsLayer() { 1831 if (mBoundsLayer != null) { 1832 setBoundsLayerCrop(); 1833 mTransaction.deferTransactionUntil(mBoundsLayer, 1834 getRenderSurfaceControl(), mSurface.getNextFrameNumber()) 1835 .apply(); 1836 } 1837 } 1838 destroySurface()1839 private void destroySurface() { 1840 if (mBoundsLayer != null) { 1841 mBoundsLayer.release(); 1842 mBoundsLayer = null; 1843 } 1844 mSurface.release(); 1845 mSurfaceControl.release(); 1846 1847 mBlastSurfaceControl.release(); 1848 // We should probably add an explicit dispose. 1849 mBlastBufferQueue = null; 1850 } 1851 1852 /** 1853 * Block the input events during an Activity Transition. The KEYCODE_BACK event is allowed 1854 * through to allow quick reversal of the Activity Transition. 1855 * 1856 * @param paused true to pause, false to resume. 1857 */ setPausedForTransition(boolean paused)1858 public void setPausedForTransition(boolean paused) { 1859 mPausedForTransition = paused; 1860 } 1861 1862 @Override getParent()1863 public ViewParent getParent() { 1864 return null; 1865 } 1866 1867 @Override getChildVisibleRect(View child, Rect r, android.graphics.Point offset)1868 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) { 1869 if (child != mView) { 1870 throw new RuntimeException("child is not mine, honest!"); 1871 } 1872 // Note: don't apply scroll offset, because we want to know its 1873 // visibility in the virtual canvas being given to the view hierarchy. 1874 return r.intersect(0, 0, mWidth, mHeight); 1875 } 1876 1877 @Override bringChildToFront(View child)1878 public void bringChildToFront(View child) { 1879 } 1880 getHostVisibility()1881 int getHostVisibility() { 1882 return (mAppVisible || mForceDecorViewVisibility) ? mView.getVisibility() : View.GONE; 1883 } 1884 1885 /** 1886 * Add LayoutTransition to the list of transitions to be started in the next traversal. 1887 * This list will be cleared after the transitions on the list are start()'ed. These 1888 * transitionsa re added by LayoutTransition itself when it sets up animations. The setup 1889 * happens during the layout phase of traversal, which we want to complete before any of the 1890 * animations are started (because those animations may side-effect properties that layout 1891 * depends upon, like the bounding rectangles of the affected views). So we add the transition 1892 * to the list and it is started just prior to starting the drawing phase of traversal. 1893 * 1894 * @param transition The LayoutTransition to be started on the next traversal. 1895 * 1896 * @hide 1897 */ requestTransitionStart(LayoutTransition transition)1898 public void requestTransitionStart(LayoutTransition transition) { 1899 if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) { 1900 if (mPendingTransitions == null) { 1901 mPendingTransitions = new ArrayList<LayoutTransition>(); 1902 } 1903 mPendingTransitions.add(transition); 1904 } 1905 } 1906 1907 /** 1908 * Notifies the HardwareRenderer that a new frame will be coming soon. 1909 * Currently only {@link ThreadedRenderer} cares about this, and uses 1910 * this knowledge to adjust the scheduling of off-thread animations 1911 */ notifyRendererOfFramePending()1912 void notifyRendererOfFramePending() { 1913 if (mAttachInfo.mThreadedRenderer != null) { 1914 mAttachInfo.mThreadedRenderer.notifyFramePending(); 1915 } 1916 } 1917 1918 @UnsupportedAppUsage scheduleTraversals()1919 void scheduleTraversals() { 1920 if (!mTraversalScheduled) { 1921 mTraversalScheduled = true; 1922 mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); 1923 mChoreographer.postCallback( 1924 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); 1925 notifyRendererOfFramePending(); 1926 pokeDrawLockIfNeeded(); 1927 } 1928 } 1929 unscheduleTraversals()1930 void unscheduleTraversals() { 1931 if (mTraversalScheduled) { 1932 mTraversalScheduled = false; 1933 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); 1934 mChoreographer.removeCallbacks( 1935 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); 1936 } 1937 } 1938 doTraversal()1939 void doTraversal() { 1940 if (mTraversalScheduled) { 1941 mTraversalScheduled = false; 1942 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); 1943 1944 if (mProfile) { 1945 Debug.startMethodTracing("ViewAncestor"); 1946 } 1947 1948 performTraversals(); 1949 1950 if (mProfile) { 1951 Debug.stopMethodTracing(); 1952 mProfile = false; 1953 } 1954 } 1955 } 1956 applyKeepScreenOnFlag(WindowManager.LayoutParams params)1957 private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) { 1958 // Update window's global keep screen on flag: if a view has requested 1959 // that the screen be kept on, then it is always set; otherwise, it is 1960 // set to whatever the client last requested for the global state. 1961 if (mAttachInfo.mKeepScreenOn) { 1962 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; 1963 } else { 1964 params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) 1965 | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 1966 } 1967 } 1968 collectViewAttributes()1969 private boolean collectViewAttributes() { 1970 if (mAttachInfo.mRecomputeGlobalAttributes) { 1971 //Log.i(mTag, "Computing view hierarchy attributes!"); 1972 mAttachInfo.mRecomputeGlobalAttributes = false; 1973 boolean oldScreenOn = mAttachInfo.mKeepScreenOn; 1974 mAttachInfo.mKeepScreenOn = false; 1975 mAttachInfo.mSystemUiVisibility = 0; 1976 mAttachInfo.mHasSystemUiListeners = false; 1977 mView.dispatchCollectViewAttributes(mAttachInfo, 0); 1978 mAttachInfo.mSystemUiVisibility &= ~mAttachInfo.mDisabledSystemUiVisibility; 1979 WindowManager.LayoutParams params = mWindowAttributes; 1980 mAttachInfo.mSystemUiVisibility |= getImpliedSystemUiVisibility(params); 1981 mCompatibleVisibilityInfo.globalVisibility = 1982 (mCompatibleVisibilityInfo.globalVisibility & ~View.SYSTEM_UI_FLAG_LOW_PROFILE) 1983 | (mAttachInfo.mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE); 1984 dispatchDispatchSystemUiVisibilityChanged(mCompatibleVisibilityInfo); 1985 if (mAttachInfo.mKeepScreenOn != oldScreenOn 1986 || mAttachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility 1987 || mAttachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) { 1988 applyKeepScreenOnFlag(params); 1989 params.subtreeSystemUiVisibility = mAttachInfo.mSystemUiVisibility; 1990 params.hasSystemUiListeners = mAttachInfo.mHasSystemUiListeners; 1991 mView.dispatchWindowSystemUiVisiblityChanged(mAttachInfo.mSystemUiVisibility); 1992 return true; 1993 } 1994 } 1995 return false; 1996 } 1997 getImpliedSystemUiVisibility(WindowManager.LayoutParams params)1998 private int getImpliedSystemUiVisibility(WindowManager.LayoutParams params) { 1999 int vis = 0; 2000 // Translucent decor window flags imply stable system ui visibility. 2001 if ((params.flags & FLAG_TRANSLUCENT_STATUS) != 0) { 2002 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 2003 } 2004 if ((params.flags & FLAG_TRANSLUCENT_NAVIGATION) != 0) { 2005 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; 2006 } 2007 return vis; 2008 } 2009 2010 /** 2011 * Update the compatible system UI visibility for dispatching it to the legacy app. 2012 * 2013 * @param type Indicates which type of the insets source we are handling. 2014 * @param visible True if the insets source is visible. 2015 * @param hasControl True if we can control the insets source. 2016 */ updateCompatSysUiVisibility(@nternalInsetsType int type, boolean visible, boolean hasControl)2017 void updateCompatSysUiVisibility(@InternalInsetsType int type, boolean visible, 2018 boolean hasControl) { 2019 if ((type != ITYPE_STATUS_BAR && type != ITYPE_NAVIGATION_BAR) 2020 || ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL) { 2021 return; 2022 } 2023 final SystemUiVisibilityInfo info = mCompatibleVisibilityInfo; 2024 final int systemUiFlag = type == ITYPE_STATUS_BAR 2025 ? View.SYSTEM_UI_FLAG_FULLSCREEN 2026 : View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; 2027 final boolean wasVisible = (info.globalVisibility & systemUiFlag) == 0; 2028 if (visible) { 2029 info.globalVisibility &= ~systemUiFlag; 2030 if (!wasVisible && hasControl) { 2031 // The local system UI visibility can only be cleared while we have the control. 2032 info.localChanges |= systemUiFlag; 2033 } 2034 } else { 2035 info.globalVisibility |= systemUiFlag; 2036 info.localChanges &= ~systemUiFlag; 2037 } 2038 dispatchDispatchSystemUiVisibilityChanged(info); 2039 } 2040 2041 /** 2042 * If the system is forcing showing any system bar, the legacy low profile flag should be 2043 * cleared for compatibility. 2044 * 2045 * @param showTypes {@link InsetsType types} shown by the system. 2046 * @param fromIme {@code true} if the invocation is from IME. 2047 */ clearLowProfileModeIfNeeded(@nsetsType int showTypes, boolean fromIme)2048 private void clearLowProfileModeIfNeeded(@InsetsType int showTypes, boolean fromIme) { 2049 final SystemUiVisibilityInfo info = mCompatibleVisibilityInfo; 2050 if ((showTypes & Type.systemBars()) != 0 && !fromIme 2051 && (info.globalVisibility & SYSTEM_UI_FLAG_LOW_PROFILE) != 0) { 2052 info.globalVisibility &= ~SYSTEM_UI_FLAG_LOW_PROFILE; 2053 info.localChanges |= SYSTEM_UI_FLAG_LOW_PROFILE; 2054 dispatchDispatchSystemUiVisibilityChanged(info); 2055 } 2056 } 2057 dispatchDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args)2058 private void dispatchDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) { 2059 if (mDispatchedSystemUiVisibility != args.globalVisibility) { 2060 mHandler.removeMessages(MSG_DISPATCH_SYSTEM_UI_VISIBILITY); 2061 mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args)); 2062 } 2063 } 2064 handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args)2065 private void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) { 2066 if (mSeq != args.seq && sNewInsetsMode != NEW_INSETS_MODE_FULL) { 2067 // The sequence has changed, so we need to update our value and make 2068 // sure to do a traversal afterward so the window manager is given our 2069 // most recent data. 2070 mSeq = args.seq; 2071 mAttachInfo.mForceReportNewAttributes = true; 2072 scheduleTraversals(); 2073 } 2074 if (mView == null) return; 2075 if (args.localChanges != 0) { 2076 mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges); 2077 args.localChanges = 0; 2078 } 2079 2080 final int visibility = args.globalVisibility & View.SYSTEM_UI_CLEARABLE_FLAGS; 2081 if (mDispatchedSystemUiVisibility != visibility) { 2082 mDispatchedSystemUiVisibility = visibility; 2083 mView.dispatchSystemUiVisibilityChanged(visibility); 2084 } 2085 } 2086 2087 @VisibleForTesting adjustLayoutParamsForCompatibility(WindowManager.LayoutParams inOutParams)2088 public static void adjustLayoutParamsForCompatibility(WindowManager.LayoutParams inOutParams) { 2089 if (sNewInsetsMode != NEW_INSETS_MODE_FULL) { 2090 return; 2091 } 2092 final int sysUiVis = inOutParams.systemUiVisibility | inOutParams.subtreeSystemUiVisibility; 2093 final int flags = inOutParams.flags; 2094 final int type = inOutParams.type; 2095 final int adjust = inOutParams.softInputMode & SOFT_INPUT_MASK_ADJUST; 2096 2097 if ((inOutParams.privateFlags & PRIVATE_FLAG_APPEARANCE_CONTROLLED) == 0) { 2098 inOutParams.insetsFlags.appearance = 0; 2099 if ((sysUiVis & SYSTEM_UI_FLAG_LOW_PROFILE) != 0) { 2100 inOutParams.insetsFlags.appearance |= APPEARANCE_LOW_PROFILE_BARS; 2101 } 2102 if ((sysUiVis & SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0) { 2103 inOutParams.insetsFlags.appearance |= APPEARANCE_LIGHT_STATUS_BARS; 2104 } 2105 if ((sysUiVis & SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0) { 2106 inOutParams.insetsFlags.appearance |= APPEARANCE_LIGHT_NAVIGATION_BARS; 2107 } 2108 } 2109 2110 if ((inOutParams.privateFlags & PRIVATE_FLAG_BEHAVIOR_CONTROLLED) == 0) { 2111 if ((sysUiVis & SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0 2112 || (flags & FLAG_FULLSCREEN) != 0) { 2113 inOutParams.insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; 2114 } else if ((sysUiVis & SYSTEM_UI_FLAG_IMMERSIVE) != 0) { 2115 inOutParams.insetsFlags.behavior = BEHAVIOR_SHOW_BARS_BY_SWIPE; 2116 } else { 2117 inOutParams.insetsFlags.behavior = BEHAVIOR_SHOW_BARS_BY_TOUCH; 2118 } 2119 } 2120 2121 inOutParams.privateFlags &= ~PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME; 2122 2123 if ((inOutParams.privateFlags & PRIVATE_FLAG_FIT_INSETS_CONTROLLED) != 0) { 2124 return; 2125 } 2126 2127 int types = inOutParams.getFitInsetsTypes(); 2128 boolean ignoreVis = inOutParams.isFitInsetsIgnoringVisibility(); 2129 2130 if (((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0 2131 || (flags & FLAG_LAYOUT_IN_SCREEN) != 0) 2132 || (flags & FLAG_TRANSLUCENT_STATUS) != 0) { 2133 types &= ~Type.statusBars(); 2134 } 2135 if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0 2136 || (flags & FLAG_TRANSLUCENT_NAVIGATION) != 0) { 2137 types &= ~Type.systemBars(); 2138 } 2139 if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) { 2140 ignoreVis = true; 2141 } else if ((types & Type.systemBars()) == Type.systemBars()) { 2142 if (adjust == SOFT_INPUT_ADJUST_RESIZE) { 2143 types |= Type.ime(); 2144 } else { 2145 inOutParams.privateFlags |= PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME; 2146 } 2147 } 2148 inOutParams.setFitInsetsTypes(types); 2149 inOutParams.setFitInsetsIgnoringVisibility(ignoreVis); 2150 2151 // The fitting of insets are not really controlled by the clients, so we remove the flag. 2152 inOutParams.privateFlags &= ~PRIVATE_FLAG_FIT_INSETS_CONTROLLED; 2153 } 2154 controlInsetsForCompatibility(WindowManager.LayoutParams params)2155 private void controlInsetsForCompatibility(WindowManager.LayoutParams params) { 2156 if (sNewInsetsMode != NEW_INSETS_MODE_FULL) { 2157 return; 2158 } 2159 final int sysUiVis = params.systemUiVisibility | params.subtreeSystemUiVisibility; 2160 final int flags = params.flags; 2161 final boolean matchParent = params.width == MATCH_PARENT && params.height == MATCH_PARENT; 2162 final boolean nonAttachedAppWindow = params.type >= FIRST_APPLICATION_WINDOW 2163 && params.type <= LAST_APPLICATION_WINDOW; 2164 final boolean statusWasHiddenByFlags = (mTypesHiddenByFlags & Type.statusBars()) != 0; 2165 final boolean statusIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_FULLSCREEN) != 0 2166 || ((flags & FLAG_FULLSCREEN) != 0 && matchParent && nonAttachedAppWindow); 2167 final boolean navWasHiddenByFlags = (mTypesHiddenByFlags & Type.navigationBars()) != 0; 2168 final boolean navIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0; 2169 2170 @InsetsType int typesToHide = 0; 2171 @InsetsType int typesToShow = 0; 2172 if (statusIsHiddenByFlags && !statusWasHiddenByFlags) { 2173 typesToHide |= Type.statusBars(); 2174 } else if (!statusIsHiddenByFlags && statusWasHiddenByFlags) { 2175 typesToShow |= Type.statusBars(); 2176 } 2177 if (navIsHiddenByFlags && !navWasHiddenByFlags) { 2178 typesToHide |= Type.navigationBars(); 2179 } else if (!navIsHiddenByFlags && navWasHiddenByFlags) { 2180 typesToShow |= Type.navigationBars(); 2181 } 2182 if (typesToHide != 0) { 2183 getInsetsController().hide(typesToHide); 2184 } 2185 if (typesToShow != 0) { 2186 getInsetsController().show(typesToShow); 2187 } 2188 mTypesHiddenByFlags |= typesToHide; 2189 mTypesHiddenByFlags &= ~typesToShow; 2190 } 2191 measureHierarchy(final View host, final WindowManager.LayoutParams lp, final Resources res, final int desiredWindowWidth, final int desiredWindowHeight)2192 private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp, 2193 final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) { 2194 int childWidthMeasureSpec; 2195 int childHeightMeasureSpec; 2196 boolean windowSizeMayChange = false; 2197 2198 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(mTag, 2199 "Measuring " + host + " in display " + desiredWindowWidth 2200 + "x" + desiredWindowHeight + "..."); 2201 2202 boolean goodMeasure = false; 2203 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) { 2204 // On large screens, we don't want to allow dialogs to just 2205 // stretch to fill the entire width of the screen to display 2206 // one line of text. First try doing the layout at a smaller 2207 // size to see if it will fit. 2208 final DisplayMetrics packageMetrics = res.getDisplayMetrics(); 2209 res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true); 2210 int baseSize = 0; 2211 if (mTmpValue.type == TypedValue.TYPE_DIMENSION) { 2212 baseSize = (int)mTmpValue.getDimension(packageMetrics); 2213 } 2214 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": baseSize=" + baseSize 2215 + ", desiredWindowWidth=" + desiredWindowWidth); 2216 if (baseSize != 0 && desiredWindowWidth > baseSize) { 2217 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width); 2218 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height); 2219 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 2220 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured (" 2221 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() 2222 + ") from width spec: " + MeasureSpec.toString(childWidthMeasureSpec) 2223 + " and height spec: " + MeasureSpec.toString(childHeightMeasureSpec)); 2224 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) { 2225 goodMeasure = true; 2226 } else { 2227 // Didn't fit in that size... try expanding a bit. 2228 baseSize = (baseSize+desiredWindowWidth)/2; 2229 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": next baseSize=" 2230 + baseSize); 2231 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width); 2232 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 2233 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured (" 2234 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")"); 2235 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) { 2236 if (DEBUG_DIALOG) Log.v(mTag, "Good!"); 2237 goodMeasure = true; 2238 } 2239 } 2240 } 2241 } 2242 2243 if (!goodMeasure) { 2244 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width); 2245 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height); 2246 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 2247 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) { 2248 windowSizeMayChange = true; 2249 } 2250 } 2251 2252 if (DBG) { 2253 System.out.println("======================================"); 2254 System.out.println("performTraversals -- after measure"); 2255 host.debug(); 2256 } 2257 2258 return windowSizeMayChange; 2259 } 2260 2261 /** 2262 * Modifies the input matrix such that it maps view-local coordinates to 2263 * on-screen coordinates. 2264 * 2265 * @param m input matrix to modify 2266 */ transformMatrixToGlobal(Matrix m)2267 void transformMatrixToGlobal(Matrix m) { 2268 m.preTranslate(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 2269 } 2270 2271 /** 2272 * Modifies the input matrix such that it maps on-screen coordinates to 2273 * view-local coordinates. 2274 * 2275 * @param m input matrix to modify 2276 */ transformMatrixToLocal(Matrix m)2277 void transformMatrixToLocal(Matrix m) { 2278 m.postTranslate(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop); 2279 } 2280 getWindowInsets(boolean forceConstruct)2281 /* package */ WindowInsets getWindowInsets(boolean forceConstruct) { 2282 if (mLastWindowInsets == null || forceConstruct) { 2283 mLastWindowInsets = mInsetsController.calculateInsets( 2284 mContext.getResources().getConfiguration().isScreenRound(), 2285 mAttachInfo.mAlwaysConsumeSystemBars, mPendingDisplayCutout.get(), 2286 mWindowAttributes.softInputMode, mWindowAttributes.flags, 2287 (mWindowAttributes.systemUiVisibility 2288 | mWindowAttributes.subtreeSystemUiVisibility)); 2289 2290 Rect visibleInsets = mInsetsController.calculateVisibleInsets( 2291 mWindowAttributes.softInputMode); 2292 2293 mAttachInfo.mVisibleInsets.set(visibleInsets); 2294 mAttachInfo.mContentInsets.set(mLastWindowInsets.getSystemWindowInsets().toRect()); 2295 mAttachInfo.mStableInsets.set(mLastWindowInsets.getStableInsets().toRect()); 2296 } 2297 return mLastWindowInsets; 2298 } 2299 dispatchApplyInsets(View host)2300 public void dispatchApplyInsets(View host) { 2301 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchApplyInsets"); 2302 mApplyInsetsRequested = false; 2303 WindowInsets insets = getWindowInsets(true /* forceConstruct */); 2304 if (!shouldDispatchCutout()) { 2305 // Window is either not laid out in cutout or the status bar inset takes care of 2306 // clearing the cutout, so we don't need to dispatch the cutout to the hierarchy. 2307 insets = insets.consumeDisplayCutout(); 2308 } 2309 host.dispatchApplyWindowInsets(insets); 2310 mAttachInfo.delayNotifyContentCaptureInsetsEvent(insets.getInsets(Type.all())); 2311 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 2312 } 2313 updateCaptionInsets()2314 private boolean updateCaptionInsets() { 2315 if (!(mView instanceof DecorView)) return false; 2316 final int captionInsetsHeight = ((DecorView) mView).getCaptionInsetsHeight(); 2317 final Rect captionFrame = new Rect(); 2318 if (captionInsetsHeight != 0) { 2319 captionFrame.set(mWinFrame.left, mWinFrame.top, mWinFrame.right, 2320 mWinFrame.top + captionInsetsHeight); 2321 } 2322 if (mAttachInfo.mCaptionInsets.equals(captionFrame)) return false; 2323 mAttachInfo.mCaptionInsets.set(captionFrame); 2324 return true; 2325 } 2326 shouldDispatchCutout()2327 private boolean shouldDispatchCutout() { 2328 return mWindowAttributes.layoutInDisplayCutoutMode 2329 == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS 2330 || mWindowAttributes.layoutInDisplayCutoutMode 2331 == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; 2332 } 2333 2334 @VisibleForTesting getInsetsController()2335 public InsetsController getInsetsController() { 2336 return mInsetsController; 2337 } 2338 shouldUseDisplaySize(final WindowManager.LayoutParams lp)2339 private static boolean shouldUseDisplaySize(final WindowManager.LayoutParams lp) { 2340 return lp.type == TYPE_STATUS_BAR_ADDITIONAL 2341 || lp.type == TYPE_INPUT_METHOD 2342 || lp.type == TYPE_VOLUME_OVERLAY; 2343 } 2344 dipToPx(int dip)2345 int dipToPx(int dip) { 2346 final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics(); 2347 return (int) (displayMetrics.density * dip + 0.5f); 2348 } 2349 performTraversals()2350 private void performTraversals() { 2351 // cache mView since it is used so much below... 2352 final View host = mView; 2353 2354 if (DBG) { 2355 System.out.println("======================================"); 2356 System.out.println("performTraversals"); 2357 host.debug(); 2358 } 2359 2360 if (host == null || !mAdded) 2361 return; 2362 2363 mIsInTraversal = true; 2364 mWillDrawSoon = true; 2365 boolean windowSizeMayChange = false; 2366 WindowManager.LayoutParams lp = mWindowAttributes; 2367 2368 int desiredWindowWidth; 2369 int desiredWindowHeight; 2370 2371 final int viewVisibility = getHostVisibility(); 2372 final boolean viewVisibilityChanged = !mFirst 2373 && (mViewVisibility != viewVisibility || mNewSurfaceNeeded 2374 // Also check for possible double visibility update, which will make current 2375 // viewVisibility value equal to mViewVisibility and we may miss it. 2376 || mAppVisibilityChanged); 2377 mAppVisibilityChanged = false; 2378 final boolean viewUserVisibilityChanged = !mFirst && 2379 ((mViewVisibility == View.VISIBLE) != (viewVisibility == View.VISIBLE)); 2380 2381 WindowManager.LayoutParams params = null; 2382 CompatibilityInfo compatibilityInfo = 2383 mDisplay.getDisplayAdjustments().getCompatibilityInfo(); 2384 if (compatibilityInfo.supportsScreen() == mLastInCompatMode) { 2385 params = lp; 2386 mFullRedrawNeeded = true; 2387 mLayoutRequested = true; 2388 if (mLastInCompatMode) { 2389 params.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; 2390 mLastInCompatMode = false; 2391 } else { 2392 params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; 2393 mLastInCompatMode = true; 2394 } 2395 } 2396 2397 Rect frame = mWinFrame; 2398 if (mFirst) { 2399 mFullRedrawNeeded = true; 2400 mLayoutRequested = true; 2401 2402 final Configuration config = mContext.getResources().getConfiguration(); 2403 if (shouldUseDisplaySize(lp)) { 2404 // NOTE -- system code, won't try to do compat mode. 2405 Point size = new Point(); 2406 mDisplay.getRealSize(size); 2407 desiredWindowWidth = size.x; 2408 desiredWindowHeight = size.y; 2409 } else if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT 2410 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) { 2411 // For wrap content, we have to remeasure later on anyways. Use size consistent with 2412 // below so we get best use of the measure cache. 2413 desiredWindowWidth = dipToPx(config.screenWidthDp); 2414 desiredWindowHeight = dipToPx(config.screenHeightDp); 2415 } else { 2416 // After addToDisplay, the frame contains the frameHint from window manager, which 2417 // for most windows is going to be the same size as the result of relayoutWindow. 2418 // Using this here allows us to avoid remeasuring after relayoutWindow 2419 desiredWindowWidth = frame.width(); 2420 desiredWindowHeight = frame.height(); 2421 } 2422 2423 // We used to use the following condition to choose 32 bits drawing caches: 2424 // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888 2425 // However, windows are now always 32 bits by default, so choose 32 bits 2426 mAttachInfo.mUse32BitDrawingCache = true; 2427 mAttachInfo.mWindowVisibility = viewVisibility; 2428 mAttachInfo.mRecomputeGlobalAttributes = false; 2429 mLastConfigurationFromResources.setTo(config); 2430 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility; 2431 // Set the layout direction if it has not been set before (inherit is the default) 2432 if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) { 2433 host.setLayoutDirection(config.getLayoutDirection()); 2434 } 2435 host.dispatchAttachedToWindow(mAttachInfo, 0); 2436 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true); 2437 dispatchApplyInsets(host); 2438 } else { 2439 desiredWindowWidth = frame.width(); 2440 desiredWindowHeight = frame.height(); 2441 if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) { 2442 if (DEBUG_ORIENTATION) Log.v(mTag, "View " + host + " resized to: " + frame); 2443 mFullRedrawNeeded = true; 2444 mLayoutRequested = true; 2445 windowSizeMayChange = true; 2446 } 2447 } 2448 2449 if (viewVisibilityChanged) { 2450 mAttachInfo.mWindowVisibility = viewVisibility; 2451 host.dispatchWindowVisibilityChanged(viewVisibility); 2452 if (viewUserVisibilityChanged) { 2453 host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE); 2454 } 2455 if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) { 2456 endDragResizing(); 2457 destroyHardwareResources(); 2458 } 2459 } 2460 2461 // Non-visible windows can't hold accessibility focus. 2462 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 2463 host.clearAccessibilityFocus(); 2464 } 2465 2466 // Execute enqueued actions on every traversal in case a detached view enqueued an action 2467 getRunQueue().executeActions(mAttachInfo.mHandler); 2468 2469 boolean cutoutChanged = false; 2470 2471 boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw); 2472 if (layoutRequested) { 2473 2474 final Resources res = mView.getContext().getResources(); 2475 2476 if (mFirst) { 2477 // make sure touch mode code executes by setting cached value 2478 // to opposite of the added touch mode. 2479 mAttachInfo.mInTouchMode = !mAddedTouchMode; 2480 ensureTouchModeLocally(mAddedTouchMode); 2481 } else { 2482 if (!mPendingDisplayCutout.equals(mAttachInfo.mDisplayCutout)) { 2483 cutoutChanged = true; 2484 } 2485 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT 2486 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) { 2487 windowSizeMayChange = true; 2488 2489 if (shouldUseDisplaySize(lp)) { 2490 // NOTE -- system code, won't try to do compat mode. 2491 Point size = new Point(); 2492 mDisplay.getRealSize(size); 2493 desiredWindowWidth = size.x; 2494 desiredWindowHeight = size.y; 2495 } else { 2496 Configuration config = res.getConfiguration(); 2497 desiredWindowWidth = dipToPx(config.screenWidthDp); 2498 desiredWindowHeight = dipToPx(config.screenHeightDp); 2499 } 2500 } 2501 } 2502 2503 // Ask host how big it wants to be 2504 windowSizeMayChange |= measureHierarchy(host, lp, res, 2505 desiredWindowWidth, desiredWindowHeight); 2506 } 2507 2508 if (collectViewAttributes()) { 2509 params = lp; 2510 } 2511 if (mAttachInfo.mForceReportNewAttributes) { 2512 mAttachInfo.mForceReportNewAttributes = false; 2513 params = lp; 2514 } 2515 2516 if (mFirst || mAttachInfo.mViewVisibilityChanged) { 2517 mAttachInfo.mViewVisibilityChanged = false; 2518 int resizeMode = mSoftInputMode & SOFT_INPUT_MASK_ADJUST; 2519 // If we are in auto resize mode, then we need to determine 2520 // what mode to use now. 2521 if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) { 2522 final int N = mAttachInfo.mScrollContainers.size(); 2523 for (int i=0; i<N; i++) { 2524 if (mAttachInfo.mScrollContainers.get(i).isShown()) { 2525 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; 2526 } 2527 } 2528 if (resizeMode == 0) { 2529 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN; 2530 } 2531 if ((lp.softInputMode & SOFT_INPUT_MASK_ADJUST) != resizeMode) { 2532 lp.softInputMode = (lp.softInputMode & ~SOFT_INPUT_MASK_ADJUST) | resizeMode; 2533 params = lp; 2534 } 2535 } 2536 } 2537 2538 if (mApplyInsetsRequested) { 2539 dispatchApplyInsets(host); 2540 if (mLayoutRequested) { 2541 // Short-circuit catching a new layout request here, so 2542 // we don't need to go through two layout passes when things 2543 // change due to fitting system windows, which can happen a lot. 2544 windowSizeMayChange |= measureHierarchy(host, lp, 2545 mView.getContext().getResources(), 2546 desiredWindowWidth, desiredWindowHeight); 2547 } 2548 } 2549 2550 if (layoutRequested) { 2551 // Clear this now, so that if anything requests a layout in the 2552 // rest of this function we will catch it and re-run a full 2553 // layout pass. 2554 mLayoutRequested = false; 2555 } 2556 2557 boolean windowShouldResize = layoutRequested && windowSizeMayChange 2558 && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) 2559 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT && 2560 frame.width() < desiredWindowWidth && frame.width() != mWidth) 2561 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT && 2562 frame.height() < desiredWindowHeight && frame.height() != mHeight)); 2563 windowShouldResize |= mDragResizing && mResizeMode == RESIZE_MODE_FREEFORM; 2564 2565 // If the activity was just relaunched, it might have unfrozen the task bounds (while 2566 // relaunching), so we need to force a call into window manager to pick up the latest 2567 // bounds. 2568 windowShouldResize |= mActivityRelaunched; 2569 2570 // Determine whether to compute insets. 2571 // If there are no inset listeners remaining then we may still need to compute 2572 // insets in case the old insets were non-empty and must be reset. 2573 final boolean computesInternalInsets = 2574 mAttachInfo.mTreeObserver.hasComputeInternalInsetsListeners() 2575 || mAttachInfo.mHasNonEmptyGivenInternalInsets; 2576 2577 boolean insetsPending = false; 2578 int relayoutResult = 0; 2579 boolean updatedConfiguration = false; 2580 2581 final int surfaceGenerationId = mSurface.getGenerationId(); 2582 2583 final boolean isViewVisible = viewVisibility == View.VISIBLE; 2584 final boolean windowRelayoutWasForced = mForceNextWindowRelayout; 2585 boolean surfaceSizeChanged = false; 2586 boolean surfaceCreated = false; 2587 boolean surfaceDestroyed = false; 2588 /* True if surface generation id changes. */ 2589 boolean surfaceReplaced = false; 2590 2591 final boolean windowAttributesChanged = mWindowAttributesChanged; 2592 if (windowAttributesChanged) { 2593 mWindowAttributesChanged = false; 2594 params = lp; 2595 } 2596 2597 if (params != null) { 2598 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0 2599 && !PixelFormat.formatHasAlpha(params.format)) { 2600 params.format = PixelFormat.TRANSLUCENT; 2601 } 2602 adjustLayoutParamsForCompatibility(params); 2603 controlInsetsForCompatibility(params); 2604 } 2605 2606 if (mFirst || windowShouldResize || viewVisibilityChanged || cutoutChanged || params != null 2607 || mForceNextWindowRelayout) { 2608 mForceNextWindowRelayout = false; 2609 2610 if (isViewVisible) { 2611 // If this window is giving internal insets to the window 2612 // manager, and it is being added or changing its visibility, 2613 // then we want to first give the window manager "fake" 2614 // insets to cause it to effectively ignore the content of 2615 // the window during layout. This avoids it briefly causing 2616 // other windows to resize/move based on the raw frame of the 2617 // window, waiting until we can finish laying out this window 2618 // and get back to the window manager with the ultimately 2619 // computed insets. 2620 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged); 2621 } 2622 2623 if (mSurfaceHolder != null) { 2624 mSurfaceHolder.mSurfaceLock.lock(); 2625 mDrawingAllowed = true; 2626 } 2627 2628 boolean hwInitialized = false; 2629 boolean dispatchApplyInsets = false; 2630 boolean hadSurface = mSurface.isValid(); 2631 2632 try { 2633 if (DEBUG_LAYOUT) { 2634 Log.i(mTag, "host=w:" + host.getMeasuredWidth() + ", h:" + 2635 host.getMeasuredHeight() + ", params=" + params); 2636 } 2637 2638 if (mAttachInfo.mThreadedRenderer != null) { 2639 // relayoutWindow may decide to destroy mSurface. As that decision 2640 // happens in WindowManager service, we need to be defensive here 2641 // and stop using the surface in case it gets destroyed. 2642 if (mAttachInfo.mThreadedRenderer.pause()) { 2643 // Animations were running so we need to push a frame 2644 // to resume them 2645 mDirty.set(0, 0, mWidth, mHeight); 2646 } 2647 mChoreographer.mFrameInfo.addFlags(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED); 2648 } 2649 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending); 2650 2651 if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString() 2652 + " cutout=" + mPendingDisplayCutout.get().toString() 2653 + " surface=" + mSurface); 2654 2655 // If the pending {@link MergedConfiguration} handed back from 2656 // {@link #relayoutWindow} does not match the one last reported, 2657 // WindowManagerService has reported back a frame from a configuration not yet 2658 // handled by the client. In this case, we need to accept the configuration so we 2659 // do not lay out and draw with the wrong configuration. 2660 if (!mPendingMergedConfiguration.equals(mLastReportedMergedConfiguration)) { 2661 if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: " 2662 + mPendingMergedConfiguration.getMergedConfiguration()); 2663 performConfigurationChange(mPendingMergedConfiguration, !mFirst, 2664 INVALID_DISPLAY /* same display */); 2665 updatedConfiguration = true; 2666 } 2667 2668 cutoutChanged = !mPendingDisplayCutout.equals(mAttachInfo.mDisplayCutout); 2669 surfaceSizeChanged = (relayoutResult 2670 & WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0; 2671 final boolean alwaysConsumeSystemBarsChanged = 2672 mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars; 2673 final boolean colorModeChanged = hasColorModeChanged(lp.getColorMode()); 2674 surfaceCreated = !hadSurface && mSurface.isValid(); 2675 surfaceDestroyed = hadSurface && !mSurface.isValid(); 2676 surfaceReplaced = (surfaceGenerationId != mSurface.getGenerationId()) 2677 && mSurface.isValid(); 2678 2679 if (cutoutChanged) { 2680 mAttachInfo.mDisplayCutout.set(mPendingDisplayCutout); 2681 if (DEBUG_LAYOUT) { 2682 Log.v(mTag, "DisplayCutout changing to: " + mAttachInfo.mDisplayCutout); 2683 } 2684 // Need to relayout with content insets. 2685 dispatchApplyInsets = true; 2686 } 2687 if (alwaysConsumeSystemBarsChanged) { 2688 mAttachInfo.mAlwaysConsumeSystemBars = mPendingAlwaysConsumeSystemBars; 2689 dispatchApplyInsets = true; 2690 } 2691 if (updateCaptionInsets()) { 2692 dispatchApplyInsets = true; 2693 } 2694 if (dispatchApplyInsets || mLastSystemUiVisibility != 2695 mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested) { 2696 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility; 2697 dispatchApplyInsets(host); 2698 // We applied insets so force contentInsetsChanged to ensure the 2699 // hierarchy is measured below. 2700 dispatchApplyInsets = true; 2701 } 2702 if (colorModeChanged && mAttachInfo.mThreadedRenderer != null) { 2703 mAttachInfo.mThreadedRenderer.setWideGamut( 2704 lp.getColorMode() == ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT); 2705 } 2706 2707 if (surfaceCreated) { 2708 // If we are creating a new surface, then we need to 2709 // completely redraw it. 2710 mFullRedrawNeeded = true; 2711 mPreviousTransparentRegion.setEmpty(); 2712 2713 // Only initialize up-front if transparent regions are not 2714 // requested, otherwise defer to see if the entire window 2715 // will be transparent 2716 if (mAttachInfo.mThreadedRenderer != null) { 2717 try { 2718 hwInitialized = mAttachInfo.mThreadedRenderer.initialize(mSurface); 2719 if (hwInitialized && (host.mPrivateFlags 2720 & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) { 2721 // Don't pre-allocate if transparent regions 2722 // are requested as they may not be needed 2723 mAttachInfo.mThreadedRenderer.allocateBuffers(); 2724 } 2725 } catch (OutOfResourcesException e) { 2726 handleOutOfResourcesException(e); 2727 return; 2728 } 2729 } 2730 notifySurfaceCreated(); 2731 } else if (surfaceDestroyed) { 2732 // If the surface has been removed, then reset the scroll 2733 // positions. 2734 if (mLastScrolledFocus != null) { 2735 mLastScrolledFocus.clear(); 2736 } 2737 mScrollY = mCurScrollY = 0; 2738 if (mView instanceof RootViewSurfaceTaker) { 2739 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY); 2740 } 2741 if (mScroller != null) { 2742 mScroller.abortAnimation(); 2743 } 2744 // Our surface is gone 2745 if (mAttachInfo.mThreadedRenderer != null && 2746 mAttachInfo.mThreadedRenderer.isEnabled()) { 2747 mAttachInfo.mThreadedRenderer.destroy(); 2748 } 2749 } else if ((surfaceReplaced 2750 || surfaceSizeChanged || windowRelayoutWasForced || colorModeChanged) 2751 && mSurfaceHolder == null 2752 && mAttachInfo.mThreadedRenderer != null 2753 && mSurface.isValid()) { 2754 mFullRedrawNeeded = true; 2755 try { 2756 // Need to do updateSurface (which leads to CanvasContext::setSurface and 2757 // re-create the EGLSurface) if either the Surface changed (as indicated by 2758 // generation id), or WindowManager changed the surface size. The latter is 2759 // because on some chips, changing the consumer side's BufferQueue size may 2760 // not take effect immediately unless we create a new EGLSurface. 2761 // Note that frame size change doesn't always imply surface size change (eg. 2762 // drag resizing uses fullscreen surface), need to check surfaceSizeChanged 2763 // flag from WindowManager. 2764 mAttachInfo.mThreadedRenderer.updateSurface(mSurface); 2765 } catch (OutOfResourcesException e) { 2766 handleOutOfResourcesException(e); 2767 return; 2768 } 2769 } 2770 2771 if (!surfaceCreated && surfaceReplaced) { 2772 notifySurfaceReplaced(); 2773 } 2774 2775 final boolean freeformResizing = (relayoutResult 2776 & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFORM) != 0; 2777 final boolean dockedResizing = (relayoutResult 2778 & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_DOCKED) != 0; 2779 final boolean dragResizing = freeformResizing || dockedResizing; 2780 if (mDragResizing != dragResizing) { 2781 if (dragResizing) { 2782 mResizeMode = freeformResizing 2783 ? RESIZE_MODE_FREEFORM 2784 : RESIZE_MODE_DOCKED_DIVIDER; 2785 final boolean backdropSizeMatchesFrame = 2786 mWinFrame.width() == mPendingBackDropFrame.width() 2787 && mWinFrame.height() == mPendingBackDropFrame.height(); 2788 // TODO: Need cutout? 2789 startDragResizing(mPendingBackDropFrame, !backdropSizeMatchesFrame, 2790 mLastWindowInsets.getSystemWindowInsets().toRect(), 2791 mLastWindowInsets.getStableInsets().toRect(), mResizeMode); 2792 } else { 2793 // We shouldn't come here, but if we come we should end the resize. 2794 endDragResizing(); 2795 } 2796 } 2797 if (!mUseMTRenderer) { 2798 if (dragResizing) { 2799 mCanvasOffsetX = mWinFrame.left; 2800 mCanvasOffsetY = mWinFrame.top; 2801 } else { 2802 mCanvasOffsetX = mCanvasOffsetY = 0; 2803 } 2804 } 2805 } catch (RemoteException e) { 2806 } 2807 2808 if (DEBUG_ORIENTATION) Log.v( 2809 TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface); 2810 2811 mAttachInfo.mWindowLeft = frame.left; 2812 mAttachInfo.mWindowTop = frame.top; 2813 2814 // !!FIXME!! This next section handles the case where we did not get the 2815 // window size we asked for. We should avoid this by getting a maximum size from 2816 // the window session beforehand. 2817 if (mWidth != frame.width() || mHeight != frame.height()) { 2818 mWidth = frame.width(); 2819 mHeight = frame.height(); 2820 } 2821 2822 if (mSurfaceHolder != null) { 2823 // The app owns the surface; tell it about what is going on. 2824 if (mSurface.isValid()) { 2825 // XXX .copyFrom() doesn't work! 2826 //mSurfaceHolder.mSurface.copyFrom(mSurface); 2827 mSurfaceHolder.mSurface = mSurface; 2828 } 2829 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight); 2830 mSurfaceHolder.mSurfaceLock.unlock(); 2831 if (surfaceCreated) { 2832 mSurfaceHolder.ungetCallbacks(); 2833 2834 mIsCreating = true; 2835 SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks(); 2836 if (callbacks != null) { 2837 for (SurfaceHolder.Callback c : callbacks) { 2838 c.surfaceCreated(mSurfaceHolder); 2839 } 2840 } 2841 } 2842 2843 if ((surfaceCreated || surfaceReplaced || surfaceSizeChanged 2844 || windowAttributesChanged) && mSurface.isValid()) { 2845 SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks(); 2846 if (callbacks != null) { 2847 for (SurfaceHolder.Callback c : callbacks) { 2848 c.surfaceChanged(mSurfaceHolder, lp.format, 2849 mWidth, mHeight); 2850 } 2851 } 2852 mIsCreating = false; 2853 } 2854 2855 if (surfaceDestroyed) { 2856 notifyHolderSurfaceDestroyed(); 2857 mSurfaceHolder.mSurfaceLock.lock(); 2858 try { 2859 mSurfaceHolder.mSurface = new Surface(); 2860 } finally { 2861 mSurfaceHolder.mSurfaceLock.unlock(); 2862 } 2863 } 2864 } 2865 2866 final ThreadedRenderer threadedRenderer = mAttachInfo.mThreadedRenderer; 2867 if (threadedRenderer != null && threadedRenderer.isEnabled()) { 2868 if (hwInitialized 2869 || mWidth != threadedRenderer.getWidth() 2870 || mHeight != threadedRenderer.getHeight() 2871 || mNeedsRendererSetup) { 2872 threadedRenderer.setup(mWidth, mHeight, mAttachInfo, 2873 mWindowAttributes.surfaceInsets); 2874 mNeedsRendererSetup = false; 2875 } 2876 } 2877 2878 if (!mStopped || mReportNextDraw) { 2879 boolean focusChangedDueToTouchMode = ensureTouchModeLocally( 2880 (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0); 2881 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth() 2882 || mHeight != host.getMeasuredHeight() || dispatchApplyInsets || 2883 updatedConfiguration) { 2884 int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width); 2885 int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height); 2886 2887 if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed! mWidth=" 2888 + mWidth + " measuredWidth=" + host.getMeasuredWidth() 2889 + " mHeight=" + mHeight 2890 + " measuredHeight=" + host.getMeasuredHeight() 2891 + " dispatchApplyInsets=" + dispatchApplyInsets); 2892 2893 // Ask host how big it wants to be 2894 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 2895 2896 // Implementation of weights from WindowManager.LayoutParams 2897 // We just grow the dimensions as needed and re-measure if 2898 // needs be 2899 int width = host.getMeasuredWidth(); 2900 int height = host.getMeasuredHeight(); 2901 boolean measureAgain = false; 2902 2903 if (lp.horizontalWeight > 0.0f) { 2904 width += (int) ((mWidth - width) * lp.horizontalWeight); 2905 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width, 2906 MeasureSpec.EXACTLY); 2907 measureAgain = true; 2908 } 2909 if (lp.verticalWeight > 0.0f) { 2910 height += (int) ((mHeight - height) * lp.verticalWeight); 2911 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, 2912 MeasureSpec.EXACTLY); 2913 measureAgain = true; 2914 } 2915 2916 if (measureAgain) { 2917 if (DEBUG_LAYOUT) Log.v(mTag, 2918 "And hey let's measure once more: width=" + width 2919 + " height=" + height); 2920 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 2921 } 2922 2923 layoutRequested = true; 2924 } 2925 } 2926 } else { 2927 // Not the first pass and no window/insets/visibility change but the window 2928 // may have moved and we need check that and if so to update the left and right 2929 // in the attach info. We translate only the window frame since on window move 2930 // the window manager tells us only for the new frame but the insets are the 2931 // same and we do not want to translate them more than once. 2932 maybeHandleWindowMove(frame); 2933 } 2934 2935 if (surfaceSizeChanged || surfaceReplaced || surfaceCreated || windowAttributesChanged) { 2936 updateBoundsLayer(); 2937 } 2938 2939 final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw); 2940 boolean triggerGlobalLayoutListener = didLayout 2941 || mAttachInfo.mRecomputeGlobalAttributes; 2942 if (didLayout) { 2943 performLayout(lp, mWidth, mHeight); 2944 2945 // By this point all views have been sized and positioned 2946 // We can compute the transparent area 2947 2948 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 2949 // start out transparent 2950 // TODO: AVOID THAT CALL BY CACHING THE RESULT? 2951 host.getLocationInWindow(mTmpLocation); 2952 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1], 2953 mTmpLocation[0] + host.mRight - host.mLeft, 2954 mTmpLocation[1] + host.mBottom - host.mTop); 2955 2956 host.gatherTransparentRegion(mTransparentRegion); 2957 if (mTranslator != null) { 2958 mTranslator.translateRegionInWindowToScreen(mTransparentRegion); 2959 } 2960 2961 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) { 2962 mPreviousTransparentRegion.set(mTransparentRegion); 2963 mFullRedrawNeeded = true; 2964 // reconfigure window manager 2965 try { 2966 mWindowSession.setTransparentRegion(mWindow, mTransparentRegion); 2967 } catch (RemoteException e) { 2968 } 2969 } 2970 } 2971 2972 if (DBG) { 2973 System.out.println("======================================"); 2974 System.out.println("performTraversals -- after setFrame"); 2975 host.debug(); 2976 } 2977 } 2978 2979 if (surfaceDestroyed) { 2980 notifySurfaceDestroyed(); 2981 } 2982 2983 if (triggerGlobalLayoutListener) { 2984 mAttachInfo.mRecomputeGlobalAttributes = false; 2985 mAttachInfo.mTreeObserver.dispatchOnGlobalLayout(); 2986 } 2987 2988 if (computesInternalInsets) { 2989 // Clear the original insets. 2990 final ViewTreeObserver.InternalInsetsInfo insets = mAttachInfo.mGivenInternalInsets; 2991 insets.reset(); 2992 2993 // Compute new insets in place. 2994 mAttachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets); 2995 mAttachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty(); 2996 2997 // Tell the window manager. 2998 if (insetsPending || !mLastGivenInsets.equals(insets)) { 2999 mLastGivenInsets.set(insets); 3000 3001 // Translate insets to screen coordinates if needed. 3002 final Rect contentInsets; 3003 final Rect visibleInsets; 3004 final Region touchableRegion; 3005 if (mTranslator != null) { 3006 contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets); 3007 visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets); 3008 touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion); 3009 } else { 3010 contentInsets = insets.contentInsets; 3011 visibleInsets = insets.visibleInsets; 3012 touchableRegion = insets.touchableRegion; 3013 } 3014 3015 try { 3016 mWindowSession.setInsets(mWindow, insets.mTouchableInsets, 3017 contentInsets, visibleInsets, touchableRegion); 3018 } catch (RemoteException e) { 3019 } 3020 } 3021 } 3022 3023 if (mFirst) { 3024 if (sAlwaysAssignFocus || !isInTouchMode()) { 3025 // handle first focus request 3026 if (DEBUG_INPUT_RESIZE) { 3027 Log.v(mTag, "First: mView.hasFocus()=" + mView.hasFocus()); 3028 } 3029 if (mView != null) { 3030 if (!mView.hasFocus()) { 3031 mView.restoreDefaultFocus(); 3032 if (DEBUG_INPUT_RESIZE) { 3033 Log.v(mTag, "First: requested focused view=" + mView.findFocus()); 3034 } 3035 } else { 3036 if (DEBUG_INPUT_RESIZE) { 3037 Log.v(mTag, "First: existing focused view=" + mView.findFocus()); 3038 } 3039 } 3040 } 3041 } else { 3042 // Some views (like ScrollView) won't hand focus to descendants that aren't within 3043 // their viewport. Before layout, there's a good change these views are size 0 3044 // which means no children can get focus. After layout, this view now has size, but 3045 // is not guaranteed to hand-off focus to a focusable child (specifically, the edge- 3046 // case where the child has a size prior to layout and thus won't trigger 3047 // focusableViewAvailable). 3048 View focused = mView.findFocus(); 3049 if (focused instanceof ViewGroup 3050 && ((ViewGroup) focused).getDescendantFocusability() 3051 == ViewGroup.FOCUS_AFTER_DESCENDANTS) { 3052 focused.restoreDefaultFocus(); 3053 } 3054 } 3055 } 3056 3057 final boolean changedVisibility = (viewVisibilityChanged || mFirst) && isViewVisible; 3058 final boolean hasWindowFocus = mAttachInfo.mHasWindowFocus && isViewVisible; 3059 final boolean regainedFocus = hasWindowFocus && mLostWindowFocus; 3060 if (regainedFocus) { 3061 mLostWindowFocus = false; 3062 } else if (!hasWindowFocus && mHadWindowFocus) { 3063 mLostWindowFocus = true; 3064 } 3065 3066 if (changedVisibility || regainedFocus) { 3067 // Toasts are presented as notifications - don't present them as windows as well 3068 boolean isToast = (mWindowAttributes == null) ? false 3069 : (mWindowAttributes.type == TYPE_TOAST); 3070 if (!isToast) { 3071 host.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 3072 } 3073 } 3074 3075 mFirst = false; 3076 mWillDrawSoon = false; 3077 mNewSurfaceNeeded = false; 3078 mActivityRelaunched = false; 3079 mViewVisibility = viewVisibility; 3080 mHadWindowFocus = hasWindowFocus; 3081 3082 mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes); 3083 3084 // Remember if we must report the next draw. 3085 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { 3086 reportNextDraw(); 3087 } 3088 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_BLAST_SYNC) != 0) { 3089 reportNextDraw(); 3090 setUseBLASTSyncTransaction(); 3091 mSendNextFrameToWm = true; 3092 } 3093 3094 boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible; 3095 3096 if (!cancelDraw) { 3097 if (mPendingTransitions != null && mPendingTransitions.size() > 0) { 3098 for (int i = 0; i < mPendingTransitions.size(); ++i) { 3099 mPendingTransitions.get(i).startChangingAnimations(); 3100 } 3101 mPendingTransitions.clear(); 3102 } 3103 3104 performDraw(); 3105 } else { 3106 if (isViewVisible) { 3107 // Try again 3108 scheduleTraversals(); 3109 } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) { 3110 for (int i = 0; i < mPendingTransitions.size(); ++i) { 3111 mPendingTransitions.get(i).endChangingAnimations(); 3112 } 3113 mPendingTransitions.clear(); 3114 } 3115 } 3116 3117 if (mAttachInfo.mContentCaptureEvents != null) { 3118 notifyContentCatpureEvents(); 3119 } 3120 3121 mIsInTraversal = false; 3122 } 3123 notifyContentCatpureEvents()3124 private void notifyContentCatpureEvents() { 3125 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "notifyContentCaptureEvents"); 3126 try { 3127 MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager 3128 .getMainContentCaptureSession(); 3129 for (int i = 0; i < mAttachInfo.mContentCaptureEvents.size(); i++) { 3130 int sessionId = mAttachInfo.mContentCaptureEvents.keyAt(i); 3131 mainSession.notifyViewTreeEvent(sessionId, /* started= */ true); 3132 ArrayList<Object> events = mAttachInfo.mContentCaptureEvents 3133 .valueAt(i); 3134 for_each_event: for (int j = 0; j < events.size(); j++) { 3135 Object event = events.get(j); 3136 if (event instanceof AutofillId) { 3137 mainSession.notifyViewDisappeared(sessionId, (AutofillId) event); 3138 } else if (event instanceof View) { 3139 View view = (View) event; 3140 ContentCaptureSession session = view.getContentCaptureSession(); 3141 if (session == null) { 3142 Log.w(mTag, "no content capture session on view: " + view); 3143 continue for_each_event; 3144 } 3145 int actualId = session.getId(); 3146 if (actualId != sessionId) { 3147 Log.w(mTag, "content capture session mismatch for view (" + view 3148 + "): was " + sessionId + " before, it's " + actualId + " now"); 3149 continue for_each_event; 3150 } 3151 ViewStructure structure = session.newViewStructure(view); 3152 view.onProvideContentCaptureStructure(structure, /* flags= */ 0); 3153 session.notifyViewAppeared(structure); 3154 } else if (event instanceof Insets) { 3155 mainSession.notifyViewInsetsChanged(sessionId, (Insets) event); 3156 } else { 3157 Log.w(mTag, "invalid content capture event: " + event); 3158 } 3159 } 3160 mainSession.notifyViewTreeEvent(sessionId, /* started= */ false); 3161 } 3162 mAttachInfo.mContentCaptureEvents = null; 3163 } finally { 3164 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 3165 } 3166 } 3167 notifyHolderSurfaceDestroyed()3168 private void notifyHolderSurfaceDestroyed() { 3169 mSurfaceHolder.ungetCallbacks(); 3170 SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks(); 3171 if (callbacks != null) { 3172 for (SurfaceHolder.Callback c : callbacks) { 3173 c.surfaceDestroyed(mSurfaceHolder); 3174 } 3175 } 3176 } 3177 maybeHandleWindowMove(Rect frame)3178 private void maybeHandleWindowMove(Rect frame) { 3179 // TODO: Well, we are checking whether the frame has changed similarly 3180 // to how this is done for the insets. This is however incorrect since 3181 // the insets and the frame are translated. For example, the old frame 3182 // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new 3183 // reported frame is (2, 2 - 2, 2) which implies no change but this is not 3184 // true since we are comparing a not translated value to a translated one. 3185 // This scenario is rare but we may want to fix that. 3186 3187 final boolean windowMoved = mAttachInfo.mWindowLeft != frame.left 3188 || mAttachInfo.mWindowTop != frame.top; 3189 if (windowMoved) { 3190 if (mTranslator != null) { 3191 mTranslator.translateRectInScreenToAppWinFrame(frame); 3192 } 3193 mAttachInfo.mWindowLeft = frame.left; 3194 mAttachInfo.mWindowTop = frame.top; 3195 } 3196 if (windowMoved || mAttachInfo.mNeedsUpdateLightCenter) { 3197 // Update the light position for the new offsets. 3198 if (mAttachInfo.mThreadedRenderer != null) { 3199 mAttachInfo.mThreadedRenderer.setLightCenter(mAttachInfo); 3200 } 3201 mAttachInfo.mNeedsUpdateLightCenter = false; 3202 } 3203 } 3204 handleWindowFocusChanged()3205 private void handleWindowFocusChanged() { 3206 final boolean hasWindowFocus; 3207 final boolean inTouchMode; 3208 synchronized (this) { 3209 if (!mWindowFocusChanged) { 3210 return; 3211 } 3212 mWindowFocusChanged = false; 3213 hasWindowFocus = mUpcomingWindowFocus; 3214 inTouchMode = mUpcomingInTouchMode; 3215 } 3216 if (sNewInsetsMode != NEW_INSETS_MODE_NONE) { 3217 // TODO (b/131181940): Make sure this doesn't leak Activity with mActivityConfigCallback 3218 // config changes. 3219 if (hasWindowFocus) { 3220 mInsetsController.onWindowFocusGained(); 3221 } else { 3222 mInsetsController.onWindowFocusLost(); 3223 } 3224 } 3225 3226 if (mAdded) { 3227 profileRendering(hasWindowFocus); 3228 3229 if (hasWindowFocus) { 3230 ensureTouchModeLocally(inTouchMode); 3231 if (mAttachInfo.mThreadedRenderer != null && mSurface.isValid()) { 3232 mFullRedrawNeeded = true; 3233 try { 3234 final WindowManager.LayoutParams lp = mWindowAttributes; 3235 final Rect surfaceInsets = lp != null ? lp.surfaceInsets : null; 3236 mAttachInfo.mThreadedRenderer.initializeIfNeeded( 3237 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets); 3238 } catch (OutOfResourcesException e) { 3239 Log.e(mTag, "OutOfResourcesException locking surface", e); 3240 try { 3241 if (!mWindowSession.outOfMemory(mWindow)) { 3242 Slog.w(mTag, "No processes killed for memory;" 3243 + " killing self"); 3244 Process.killProcess(Process.myPid()); 3245 } 3246 } catch (RemoteException ex) { 3247 } 3248 // Retry in a bit. 3249 mHandler.sendMessageDelayed(mHandler.obtainMessage( 3250 MSG_WINDOW_FOCUS_CHANGED), 500); 3251 return; 3252 } 3253 } 3254 } 3255 3256 mAttachInfo.mHasWindowFocus = hasWindowFocus; 3257 mImeFocusController.updateImeFocusable(mWindowAttributes, true /* force */); 3258 mImeFocusController.onPreWindowFocus(hasWindowFocus, mWindowAttributes); 3259 3260 if (mView != null) { 3261 mAttachInfo.mKeyDispatchState.reset(); 3262 mView.dispatchWindowFocusChanged(hasWindowFocus); 3263 mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus); 3264 if (mAttachInfo.mTooltipHost != null) { 3265 mAttachInfo.mTooltipHost.hideTooltip(); 3266 } 3267 } 3268 3269 // Note: must be done after the focus change callbacks, 3270 // so all of the view state is set up correctly. 3271 mImeFocusController.onPostWindowFocus(mView != null ? mView.findFocus() : null, 3272 hasWindowFocus, mWindowAttributes); 3273 3274 if (hasWindowFocus) { 3275 // Clear the forward bit. We can just do this directly, since 3276 // the window manager doesn't care about it. 3277 mWindowAttributes.softInputMode &= 3278 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; 3279 ((WindowManager.LayoutParams) mView.getLayoutParams()) 3280 .softInputMode &= 3281 ~WindowManager.LayoutParams 3282 .SOFT_INPUT_IS_FORWARD_NAVIGATION; 3283 3284 // Refocusing a window that has a focused view should fire a 3285 // focus event for the view since the global focused view changed. 3286 fireAccessibilityFocusEventIfHasFocusedNode(); 3287 } else { 3288 if (mPointerCapture) { 3289 handlePointerCaptureChanged(false); 3290 } 3291 } 3292 } 3293 mFirstInputStage.onWindowFocusChanged(hasWindowFocus); 3294 3295 // NOTE: there's no view visibility (appeared / disapparead) events when the windows focus 3296 // is lost, so we don't need to to force a flush - there might be other events such as 3297 // text changes, but these should be flushed independently. 3298 if (hasWindowFocus) { 3299 handleContentCaptureFlush(); 3300 } 3301 } 3302 fireAccessibilityFocusEventIfHasFocusedNode()3303 private void fireAccessibilityFocusEventIfHasFocusedNode() { 3304 if (!AccessibilityManager.getInstance(mContext).isEnabled()) { 3305 return; 3306 } 3307 final View focusedView = mView.findFocus(); 3308 if (focusedView == null) { 3309 return; 3310 } 3311 final AccessibilityNodeProvider provider = focusedView.getAccessibilityNodeProvider(); 3312 if (provider == null) { 3313 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 3314 } else { 3315 final AccessibilityNodeInfo focusedNode = findFocusedVirtualNode(provider); 3316 if (focusedNode != null) { 3317 final int virtualId = AccessibilityNodeInfo.getVirtualDescendantId( 3318 focusedNode.getSourceNodeId()); 3319 // This is a best effort since clearing and setting the focus via the 3320 // provider APIs could have side effects. We don't have a provider API 3321 // similar to that on View to ask a given event to be fired. 3322 final AccessibilityEvent event = AccessibilityEvent.obtain( 3323 AccessibilityEvent.TYPE_VIEW_FOCUSED); 3324 event.setSource(focusedView, virtualId); 3325 event.setPackageName(focusedNode.getPackageName()); 3326 event.setChecked(focusedNode.isChecked()); 3327 event.setContentDescription(focusedNode.getContentDescription()); 3328 event.setPassword(focusedNode.isPassword()); 3329 event.getText().add(focusedNode.getText()); 3330 event.setEnabled(focusedNode.isEnabled()); 3331 focusedView.getParent().requestSendAccessibilityEvent(focusedView, event); 3332 focusedNode.recycle(); 3333 } 3334 } 3335 } 3336 findFocusedVirtualNode(AccessibilityNodeProvider provider)3337 private AccessibilityNodeInfo findFocusedVirtualNode(AccessibilityNodeProvider provider) { 3338 AccessibilityNodeInfo focusedNode = provider.findFocus( 3339 AccessibilityNodeInfo.FOCUS_INPUT); 3340 if (focusedNode != null) { 3341 return focusedNode; 3342 } 3343 3344 if (!mContext.isAutofillCompatibilityEnabled()) { 3345 return null; 3346 } 3347 3348 // Unfortunately some provider implementations don't properly 3349 // implement AccessibilityNodeProvider#findFocus 3350 AccessibilityNodeInfo current = provider.createAccessibilityNodeInfo( 3351 AccessibilityNodeProvider.HOST_VIEW_ID); 3352 if (current.isFocused()) { 3353 return current; 3354 } 3355 3356 final Queue<AccessibilityNodeInfo> fringe = new LinkedList<>(); 3357 fringe.offer(current); 3358 3359 while (!fringe.isEmpty()) { 3360 current = fringe.poll(); 3361 final LongArray childNodeIds = current.getChildNodeIds(); 3362 if (childNodeIds== null || childNodeIds.size() <= 0) { 3363 continue; 3364 } 3365 final int childCount = childNodeIds.size(); 3366 for (int i = 0; i < childCount; i++) { 3367 final int virtualId = AccessibilityNodeInfo.getVirtualDescendantId( 3368 childNodeIds.get(i)); 3369 final AccessibilityNodeInfo child = provider.createAccessibilityNodeInfo(virtualId); 3370 if (child != null) { 3371 if (child.isFocused()) { 3372 return child; 3373 } 3374 fringe.offer(child); 3375 } 3376 } 3377 current.recycle(); 3378 } 3379 3380 return null; 3381 } 3382 handleOutOfResourcesException(Surface.OutOfResourcesException e)3383 private void handleOutOfResourcesException(Surface.OutOfResourcesException e) { 3384 Log.e(mTag, "OutOfResourcesException initializing HW surface", e); 3385 try { 3386 if (!mWindowSession.outOfMemory(mWindow) && 3387 Process.myUid() != Process.SYSTEM_UID) { 3388 Slog.w(mTag, "No processes killed for memory; killing self"); 3389 Process.killProcess(Process.myPid()); 3390 } 3391 } catch (RemoteException ex) { 3392 } 3393 mLayoutRequested = true; // ask wm for a new surface next time. 3394 } 3395 performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec)3396 private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) { 3397 if (mView == null) { 3398 return; 3399 } 3400 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure"); 3401 try { 3402 mView.measure(childWidthMeasureSpec, childHeightMeasureSpec); 3403 } finally { 3404 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 3405 } 3406 } 3407 3408 /** 3409 * Called by {@link android.view.View#isInLayout()} to determine whether the view hierarchy 3410 * is currently undergoing a layout pass. 3411 * 3412 * @return whether the view hierarchy is currently undergoing a layout pass 3413 */ isInLayout()3414 boolean isInLayout() { 3415 return mInLayout; 3416 } 3417 3418 /** 3419 * Called by {@link android.view.View#requestLayout()} if the view hierarchy is currently 3420 * undergoing a layout pass. requestLayout() should not generally be called during layout, 3421 * unless the container hierarchy knows what it is doing (i.e., it is fine as long as 3422 * all children in that container hierarchy are measured and laid out at the end of the layout 3423 * pass for that container). If requestLayout() is called anyway, we handle it correctly 3424 * by registering all requesters during a frame as it proceeds. At the end of the frame, 3425 * we check all of those views to see if any still have pending layout requests, which 3426 * indicates that they were not correctly handled by their container hierarchy. If that is 3427 * the case, we clear all such flags in the tree, to remove the buggy flag state that leads 3428 * to blank containers, and force a second request/measure/layout pass in this frame. If 3429 * more requestLayout() calls are received during that second layout pass, we post those 3430 * requests to the next frame to avoid possible infinite loops. 3431 * 3432 * <p>The return value from this method indicates whether the request should proceed 3433 * (if it is a request during the first layout pass) or should be skipped and posted to the 3434 * next frame (if it is a request during the second layout pass).</p> 3435 * 3436 * @param view the view that requested the layout. 3437 * 3438 * @return true if request should proceed, false otherwise. 3439 */ requestLayoutDuringLayout(final View view)3440 boolean requestLayoutDuringLayout(final View view) { 3441 if (view.mParent == null || view.mAttachInfo == null) { 3442 // Would not normally trigger another layout, so just let it pass through as usual 3443 return true; 3444 } 3445 if (!mLayoutRequesters.contains(view)) { 3446 mLayoutRequesters.add(view); 3447 } 3448 if (!mHandlingLayoutInLayoutRequest) { 3449 // Let the request proceed normally; it will be processed in a second layout pass 3450 // if necessary 3451 return true; 3452 } else { 3453 // Don't let the request proceed during the second layout pass. 3454 // It will post to the next frame instead. 3455 return false; 3456 } 3457 } 3458 performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, int desiredWindowHeight)3459 private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, 3460 int desiredWindowHeight) { 3461 mScrollMayChange = true; 3462 mInLayout = true; 3463 3464 final View host = mView; 3465 if (host == null) { 3466 return; 3467 } 3468 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) { 3469 Log.v(mTag, "Laying out " + host + " to (" + 3470 host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")"); 3471 } 3472 3473 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout"); 3474 try { 3475 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight()); 3476 3477 mInLayout = false; 3478 int numViewsRequestingLayout = mLayoutRequesters.size(); 3479 if (numViewsRequestingLayout > 0) { 3480 // requestLayout() was called during layout. 3481 // If no layout-request flags are set on the requesting views, there is no problem. 3482 // If some requests are still pending, then we need to clear those flags and do 3483 // a full request/measure/layout pass to handle this situation. 3484 ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, 3485 false); 3486 if (validLayoutRequesters != null) { 3487 // Set this flag to indicate that any further requests are happening during 3488 // the second pass, which may result in posting those requests to the next 3489 // frame instead 3490 mHandlingLayoutInLayoutRequest = true; 3491 3492 // Process fresh layout requests, then measure and layout 3493 int numValidRequests = validLayoutRequesters.size(); 3494 for (int i = 0; i < numValidRequests; ++i) { 3495 final View view = validLayoutRequesters.get(i); 3496 Log.w("View", "requestLayout() improperly called by " + view + 3497 " during layout: running second layout pass"); 3498 view.requestLayout(); 3499 } 3500 measureHierarchy(host, lp, mView.getContext().getResources(), 3501 desiredWindowWidth, desiredWindowHeight); 3502 mInLayout = true; 3503 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight()); 3504 3505 mHandlingLayoutInLayoutRequest = false; 3506 3507 // Check the valid requests again, this time without checking/clearing the 3508 // layout flags, since requests happening during the second pass get noop'd 3509 validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true); 3510 if (validLayoutRequesters != null) { 3511 final ArrayList<View> finalRequesters = validLayoutRequesters; 3512 // Post second-pass requests to the next frame 3513 getRunQueue().post(new Runnable() { 3514 @Override 3515 public void run() { 3516 int numValidRequests = finalRequesters.size(); 3517 for (int i = 0; i < numValidRequests; ++i) { 3518 final View view = finalRequesters.get(i); 3519 Log.w("View", "requestLayout() improperly called by " + view + 3520 " during second layout pass: posting in next frame"); 3521 view.requestLayout(); 3522 } 3523 } 3524 }); 3525 } 3526 } 3527 3528 } 3529 } finally { 3530 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 3531 } 3532 mInLayout = false; 3533 } 3534 3535 /** 3536 * This method is called during layout when there have been calls to requestLayout() during 3537 * layout. It walks through the list of views that requested layout to determine which ones 3538 * still need it, based on visibility in the hierarchy and whether they have already been 3539 * handled (as is usually the case with ListView children). 3540 * 3541 * @param layoutRequesters The list of views that requested layout during layout 3542 * @param secondLayoutRequests Whether the requests were issued during the second layout pass. 3543 * If so, the FORCE_LAYOUT flag was not set on requesters. 3544 * @return A list of the actual views that still need to be laid out. 3545 */ getValidLayoutRequesters(ArrayList<View> layoutRequesters, boolean secondLayoutRequests)3546 private ArrayList<View> getValidLayoutRequesters(ArrayList<View> layoutRequesters, 3547 boolean secondLayoutRequests) { 3548 3549 int numViewsRequestingLayout = layoutRequesters.size(); 3550 ArrayList<View> validLayoutRequesters = null; 3551 for (int i = 0; i < numViewsRequestingLayout; ++i) { 3552 View view = layoutRequesters.get(i); 3553 if (view != null && view.mAttachInfo != null && view.mParent != null && 3554 (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) == 3555 View.PFLAG_FORCE_LAYOUT)) { 3556 boolean gone = false; 3557 View parent = view; 3558 // Only trigger new requests for views in a non-GONE hierarchy 3559 while (parent != null) { 3560 if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) { 3561 gone = true; 3562 break; 3563 } 3564 if (parent.mParent instanceof View) { 3565 parent = (View) parent.mParent; 3566 } else { 3567 parent = null; 3568 } 3569 } 3570 if (!gone) { 3571 if (validLayoutRequesters == null) { 3572 validLayoutRequesters = new ArrayList<View>(); 3573 } 3574 validLayoutRequesters.add(view); 3575 } 3576 } 3577 } 3578 if (!secondLayoutRequests) { 3579 // If we're checking the layout flags, then we need to clean them up also 3580 for (int i = 0; i < numViewsRequestingLayout; ++i) { 3581 View view = layoutRequesters.get(i); 3582 while (view != null && 3583 (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) { 3584 view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT; 3585 if (view.mParent instanceof View) { 3586 view = (View) view.mParent; 3587 } else { 3588 view = null; 3589 } 3590 } 3591 } 3592 } 3593 layoutRequesters.clear(); 3594 return validLayoutRequesters; 3595 } 3596 3597 @Override requestTransparentRegion(View child)3598 public void requestTransparentRegion(View child) { 3599 // the test below should not fail unless someone is messing with us 3600 checkThread(); 3601 if (mView != child) { 3602 return; 3603 } 3604 3605 if ((mView.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) { 3606 mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS; 3607 // Need to make sure we re-evaluate the window attributes next 3608 // time around, to ensure the window has the correct format. 3609 mWindowAttributesChanged = true; 3610 } 3611 3612 // Always request layout to apply the latest transparent region. 3613 requestLayout(); 3614 } 3615 3616 /** 3617 * Figures out the measure spec for the root view in a window based on it's 3618 * layout params. 3619 * 3620 * @param windowSize 3621 * The available width or height of the window 3622 * 3623 * @param rootDimension 3624 * The layout params for one dimension (width or height) of the 3625 * window. 3626 * 3627 * @return The measure spec to use to measure the root view. 3628 */ getRootMeasureSpec(int windowSize, int rootDimension)3629 private static int getRootMeasureSpec(int windowSize, int rootDimension) { 3630 int measureSpec; 3631 switch (rootDimension) { 3632 3633 case ViewGroup.LayoutParams.MATCH_PARENT: 3634 // Window can't resize. Force root view to be windowSize. 3635 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY); 3636 break; 3637 case ViewGroup.LayoutParams.WRAP_CONTENT: 3638 // Window can resize. Set max size for root view. 3639 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST); 3640 break; 3641 default: 3642 // Window wants to be an exact size. Force root view to be that size. 3643 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY); 3644 break; 3645 } 3646 return measureSpec; 3647 } 3648 3649 int mHardwareXOffset; 3650 int mHardwareYOffset; 3651 3652 @Override onPreDraw(RecordingCanvas canvas)3653 public void onPreDraw(RecordingCanvas canvas) { 3654 // If mCurScrollY is not 0 then this influences the hardwareYOffset. The end result is we 3655 // can apply offsets that are not handled by anything else, resulting in underdraw as 3656 // the View is shifted (thus shifting the window background) exposing unpainted 3657 // content. To handle this with minimal glitches we just clear to BLACK if the window 3658 // is opaque. If it's not opaque then HWUI already internally does a glClear to 3659 // transparent, so there's no risk of underdraw on non-opaque surfaces. 3660 if (mCurScrollY != 0 && mHardwareYOffset != 0 && mAttachInfo.mThreadedRenderer.isOpaque()) { 3661 canvas.drawColor(Color.BLACK); 3662 } 3663 canvas.translate(-mHardwareXOffset, -mHardwareYOffset); 3664 } 3665 3666 @Override onPostDraw(RecordingCanvas canvas)3667 public void onPostDraw(RecordingCanvas canvas) { 3668 drawAccessibilityFocusedDrawableIfNeeded(canvas); 3669 if (mUseMTRenderer) { 3670 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { 3671 mWindowCallbacks.get(i).onPostDraw(canvas); 3672 } 3673 } 3674 } 3675 3676 /** 3677 * @hide 3678 */ outputDisplayList(View view)3679 void outputDisplayList(View view) { 3680 view.mRenderNode.output(); 3681 } 3682 3683 /** 3684 * @see #PROPERTY_PROFILE_RENDERING 3685 */ profileRendering(boolean enabled)3686 private void profileRendering(boolean enabled) { 3687 if (mProfileRendering) { 3688 mRenderProfilingEnabled = enabled; 3689 3690 if (mRenderProfiler != null) { 3691 mChoreographer.removeFrameCallback(mRenderProfiler); 3692 } 3693 if (mRenderProfilingEnabled) { 3694 if (mRenderProfiler == null) { 3695 mRenderProfiler = new Choreographer.FrameCallback() { 3696 @Override 3697 public void doFrame(long frameTimeNanos) { 3698 mDirty.set(0, 0, mWidth, mHeight); 3699 scheduleTraversals(); 3700 if (mRenderProfilingEnabled) { 3701 mChoreographer.postFrameCallback(mRenderProfiler); 3702 } 3703 } 3704 }; 3705 } 3706 mChoreographer.postFrameCallback(mRenderProfiler); 3707 } else { 3708 mRenderProfiler = null; 3709 } 3710 } 3711 } 3712 3713 /** 3714 * Called from draw() when DEBUG_FPS is enabled 3715 */ trackFPS()3716 private void trackFPS() { 3717 // Tracks frames per second drawn. First value in a series of draws may be bogus 3718 // because it down not account for the intervening idle time 3719 long nowTime = System.currentTimeMillis(); 3720 if (mFpsStartTime < 0) { 3721 mFpsStartTime = mFpsPrevTime = nowTime; 3722 mFpsNumFrames = 0; 3723 } else { 3724 ++mFpsNumFrames; 3725 String thisHash = Integer.toHexString(System.identityHashCode(this)); 3726 long frameTime = nowTime - mFpsPrevTime; 3727 long totalTime = nowTime - mFpsStartTime; 3728 Log.v(mTag, "0x" + thisHash + "\tFrame time:\t" + frameTime); 3729 mFpsPrevTime = nowTime; 3730 if (totalTime > 1000) { 3731 float fps = (float) mFpsNumFrames * 1000 / totalTime; 3732 Log.v(mTag, "0x" + thisHash + "\tFPS:\t" + fps); 3733 mFpsStartTime = nowTime; 3734 mFpsNumFrames = 0; 3735 } 3736 } 3737 } 3738 3739 /** 3740 * A count of the number of calls to pendingDrawFinished we 3741 * require to notify the WM drawing is complete. 3742 */ 3743 int mDrawsNeededToReport = 0; 3744 3745 /** 3746 * Delay notifying WM of draw finished until 3747 * a balanced call to pendingDrawFinished. 3748 */ drawPending()3749 void drawPending() { 3750 mDrawsNeededToReport++; 3751 } 3752 pendingDrawFinished()3753 void pendingDrawFinished() { 3754 if (mDrawsNeededToReport == 0) { 3755 throw new RuntimeException("Unbalanced drawPending/pendingDrawFinished calls"); 3756 } 3757 mDrawsNeededToReport--; 3758 if (mDrawsNeededToReport == 0) { 3759 reportDrawFinished(); 3760 } 3761 } 3762 postDrawFinished()3763 private void postDrawFinished() { 3764 mHandler.sendEmptyMessage(MSG_DRAW_FINISHED); 3765 } 3766 reportDrawFinished()3767 private void reportDrawFinished() { 3768 try { 3769 mDrawsNeededToReport = 0; 3770 mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction); 3771 } catch (RemoteException e) { 3772 // Have fun! 3773 } 3774 } 3775 performDraw()3776 private void performDraw() { 3777 if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) { 3778 return; 3779 } else if (mView == null) { 3780 return; 3781 } 3782 3783 final boolean fullRedrawNeeded = mFullRedrawNeeded || mReportNextDraw; 3784 mFullRedrawNeeded = false; 3785 3786 mIsDrawing = true; 3787 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw"); 3788 3789 boolean usingAsyncReport = false; 3790 boolean reportNextDraw = mReportNextDraw; // Capture the original value 3791 if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) { 3792 ArrayList<Runnable> commitCallbacks = mAttachInfo.mTreeObserver 3793 .captureFrameCommitCallbacks(); 3794 final boolean needFrameCompleteCallback = mNextDrawUseBLASTSyncTransaction || 3795 (commitCallbacks != null && commitCallbacks.size() > 0) || 3796 mReportNextDraw; 3797 usingAsyncReport = mReportNextDraw; 3798 if (needFrameCompleteCallback) { 3799 final Handler handler = mAttachInfo.mHandler; 3800 mAttachInfo.mThreadedRenderer.setFrameCompleteCallback((long frameNr) -> { 3801 finishBLASTSync(!mSendNextFrameToWm); 3802 handler.postAtFrontOfQueue(() -> { 3803 if (reportNextDraw) { 3804 // TODO: Use the frame number 3805 pendingDrawFinished(); 3806 } 3807 if (commitCallbacks != null) { 3808 for (int i = 0; i < commitCallbacks.size(); i++) { 3809 commitCallbacks.get(i).run(); 3810 } 3811 } 3812 });}); 3813 } 3814 } 3815 3816 try { 3817 if (mNextDrawUseBLASTSyncTransaction) { 3818 // TODO(b/149747443) 3819 // We aren't prepared to handle overlapping use of mRtBLASTSyncTransaction 3820 // so if we are BLAST syncing we make sure the previous draw has 3821 // totally finished. 3822 if (mAttachInfo.mThreadedRenderer != null) { 3823 mAttachInfo.mThreadedRenderer.pause(); 3824 } 3825 3826 mNextReportConsumeBLAST = true; 3827 mNextDrawUseBLASTSyncTransaction = false; 3828 3829 if (mBlastBufferQueue != null) { 3830 mBlastBufferQueue.setNextTransaction(mRtBLASTSyncTransaction); 3831 } 3832 } 3833 boolean canUseAsync = draw(fullRedrawNeeded); 3834 if (usingAsyncReport && !canUseAsync) { 3835 mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(null); 3836 usingAsyncReport = false; 3837 finishBLASTSync(true /* apply */); 3838 } 3839 } finally { 3840 mIsDrawing = false; 3841 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 3842 } 3843 3844 // For whatever reason we didn't create a HardwareRenderer, end any 3845 // hardware animations that are now dangling 3846 if (mAttachInfo.mPendingAnimatingRenderNodes != null) { 3847 final int count = mAttachInfo.mPendingAnimatingRenderNodes.size(); 3848 for (int i = 0; i < count; i++) { 3849 mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators(); 3850 } 3851 mAttachInfo.mPendingAnimatingRenderNodes.clear(); 3852 } 3853 3854 if (mReportNextDraw) { 3855 mReportNextDraw = false; 3856 3857 // if we're using multi-thread renderer, wait for the window frame draws 3858 if (mWindowDrawCountDown != null) { 3859 try { 3860 mWindowDrawCountDown.await(); 3861 } catch (InterruptedException e) { 3862 Log.e(mTag, "Window redraw count down interrupted!"); 3863 } 3864 mWindowDrawCountDown = null; 3865 } 3866 3867 if (mAttachInfo.mThreadedRenderer != null) { 3868 mAttachInfo.mThreadedRenderer.setStopped(mStopped); 3869 } 3870 3871 if (LOCAL_LOGV) { 3872 Log.v(mTag, "FINISHED DRAWING: " + mWindowAttributes.getTitle()); 3873 } 3874 3875 if (mSurfaceHolder != null && mSurface.isValid()) { 3876 SurfaceCallbackHelper sch = new SurfaceCallbackHelper(this::postDrawFinished); 3877 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); 3878 3879 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks); 3880 } else if (!usingAsyncReport) { 3881 if (mAttachInfo.mThreadedRenderer != null) { 3882 mAttachInfo.mThreadedRenderer.fence(); 3883 } 3884 pendingDrawFinished(); 3885 } 3886 } 3887 if (mPerformContentCapture) { 3888 performContentCaptureInitialReport(); 3889 } 3890 } 3891 3892 /** 3893 * Checks (and caches) if content capture is enabled for this context. 3894 */ isContentCaptureEnabled()3895 private boolean isContentCaptureEnabled() { 3896 switch (mContentCaptureEnabled) { 3897 case CONTENT_CAPTURE_ENABLED_TRUE: 3898 return true; 3899 case CONTENT_CAPTURE_ENABLED_FALSE: 3900 return false; 3901 case CONTENT_CAPTURE_ENABLED_NOT_CHECKED: 3902 final boolean reallyEnabled = isContentCaptureReallyEnabled(); 3903 mContentCaptureEnabled = reallyEnabled ? CONTENT_CAPTURE_ENABLED_TRUE 3904 : CONTENT_CAPTURE_ENABLED_FALSE; 3905 return reallyEnabled; 3906 default: 3907 Log.w(TAG, "isContentCaptureEnabled(): invalid state " + mContentCaptureEnabled); 3908 return false; 3909 } 3910 3911 } 3912 3913 /** 3914 * Checks (without caching) if content capture is enabled for this context. 3915 */ isContentCaptureReallyEnabled()3916 private boolean isContentCaptureReallyEnabled() { 3917 // First check if context supports it, so it saves a service lookup when it doesn't 3918 if (mContext.getContentCaptureOptions() == null) return false; 3919 3920 final ContentCaptureManager ccm = mAttachInfo.getContentCaptureManager(mContext); 3921 // Then check if it's enabled in the contex itself. 3922 if (ccm == null || !ccm.isContentCaptureEnabled()) return false; 3923 3924 return true; 3925 } 3926 performContentCaptureInitialReport()3927 private void performContentCaptureInitialReport() { 3928 mPerformContentCapture = false; // One-time offer! 3929 final View rootView = mView; 3930 if (DEBUG_CONTENT_CAPTURE) { 3931 Log.v(mTag, "performContentCaptureInitialReport() on " + rootView); 3932 } 3933 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 3934 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchContentCapture() for " 3935 + getClass().getSimpleName()); 3936 } 3937 try { 3938 if (!isContentCaptureEnabled()) return; 3939 3940 // Content capture is a go! 3941 rootView.dispatchInitialProvideContentCaptureStructure(); 3942 } finally { 3943 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 3944 } 3945 } 3946 handleContentCaptureFlush()3947 private void handleContentCaptureFlush() { 3948 if (DEBUG_CONTENT_CAPTURE) { 3949 Log.v(mTag, "handleContentCaptureFlush()"); 3950 } 3951 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 3952 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "flushContentCapture for " 3953 + getClass().getSimpleName()); 3954 } 3955 try { 3956 if (!isContentCaptureEnabled()) return; 3957 3958 final ContentCaptureManager ccm = mAttachInfo.mContentCaptureManager; 3959 if (ccm == null) { 3960 Log.w(TAG, "No ContentCapture on AttachInfo"); 3961 return; 3962 } 3963 ccm.flush(ContentCaptureSession.FLUSH_REASON_VIEW_ROOT_ENTERED); 3964 } finally { 3965 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 3966 } 3967 } 3968 draw(boolean fullRedrawNeeded)3969 private boolean draw(boolean fullRedrawNeeded) { 3970 Surface surface = mSurface; 3971 if (!surface.isValid()) { 3972 return false; 3973 } 3974 3975 if (DEBUG_FPS) { 3976 trackFPS(); 3977 } 3978 3979 if (!sFirstDrawComplete) { 3980 synchronized (sFirstDrawHandlers) { 3981 sFirstDrawComplete = true; 3982 final int count = sFirstDrawHandlers.size(); 3983 for (int i = 0; i< count; i++) { 3984 mHandler.post(sFirstDrawHandlers.get(i)); 3985 } 3986 } 3987 } 3988 3989 scrollToRectOrFocus(null, false); 3990 3991 if (mAttachInfo.mViewScrollChanged) { 3992 mAttachInfo.mViewScrollChanged = false; 3993 mAttachInfo.mTreeObserver.dispatchOnScrollChanged(); 3994 } 3995 3996 boolean animating = mScroller != null && mScroller.computeScrollOffset(); 3997 final int curScrollY; 3998 if (animating) { 3999 curScrollY = mScroller.getCurrY(); 4000 } else { 4001 curScrollY = mScrollY; 4002 } 4003 if (mCurScrollY != curScrollY) { 4004 mCurScrollY = curScrollY; 4005 fullRedrawNeeded = true; 4006 if (mView instanceof RootViewSurfaceTaker) { 4007 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY); 4008 } 4009 } 4010 4011 final float appScale = mAttachInfo.mApplicationScale; 4012 final boolean scalingRequired = mAttachInfo.mScalingRequired; 4013 4014 final Rect dirty = mDirty; 4015 if (mSurfaceHolder != null) { 4016 // The app owns the surface, we won't draw. 4017 dirty.setEmpty(); 4018 if (animating && mScroller != null) { 4019 mScroller.abortAnimation(); 4020 } 4021 return false; 4022 } 4023 4024 if (fullRedrawNeeded) { 4025 dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f)); 4026 } 4027 4028 if (DEBUG_ORIENTATION || DEBUG_DRAW) { 4029 Log.v(mTag, "Draw " + mView + "/" 4030 + mWindowAttributes.getTitle() 4031 + ": dirty={" + dirty.left + "," + dirty.top 4032 + "," + dirty.right + "," + dirty.bottom + "} surface=" 4033 + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" + 4034 appScale + ", width=" + mWidth + ", height=" + mHeight); 4035 } 4036 4037 mAttachInfo.mTreeObserver.dispatchOnDraw(); 4038 4039 int xOffset = -mCanvasOffsetX; 4040 int yOffset = -mCanvasOffsetY + curScrollY; 4041 final WindowManager.LayoutParams params = mWindowAttributes; 4042 final Rect surfaceInsets = params != null ? params.surfaceInsets : null; 4043 if (surfaceInsets != null) { 4044 xOffset -= surfaceInsets.left; 4045 yOffset -= surfaceInsets.top; 4046 4047 // Offset dirty rect for surface insets. 4048 dirty.offset(surfaceInsets.left, surfaceInsets.right); 4049 } 4050 4051 boolean accessibilityFocusDirty = false; 4052 final Drawable drawable = mAttachInfo.mAccessibilityFocusDrawable; 4053 if (drawable != null) { 4054 final Rect bounds = mAttachInfo.mTmpInvalRect; 4055 final boolean hasFocus = getAccessibilityFocusedRect(bounds); 4056 if (!hasFocus) { 4057 bounds.setEmpty(); 4058 } 4059 if (!bounds.equals(drawable.getBounds())) { 4060 accessibilityFocusDirty = true; 4061 } 4062 } 4063 4064 mAttachInfo.mDrawingTime = 4065 mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS; 4066 4067 boolean useAsyncReport = false; 4068 if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) { 4069 if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) { 4070 // If accessibility focus moved, always invalidate the root. 4071 boolean invalidateRoot = accessibilityFocusDirty || mInvalidateRootRequested; 4072 mInvalidateRootRequested = false; 4073 4074 // Draw with hardware renderer. 4075 mIsAnimating = false; 4076 4077 if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) { 4078 mHardwareYOffset = yOffset; 4079 mHardwareXOffset = xOffset; 4080 invalidateRoot = true; 4081 } 4082 4083 if (invalidateRoot) { 4084 mAttachInfo.mThreadedRenderer.invalidateRoot(); 4085 } 4086 4087 dirty.setEmpty(); 4088 4089 // Stage the content drawn size now. It will be transferred to the renderer 4090 // shortly before the draw commands get send to the renderer. 4091 final boolean updated = updateContentDrawBounds(); 4092 4093 if (mReportNextDraw) { 4094 // report next draw overrides setStopped() 4095 // This value is re-sync'd to the value of mStopped 4096 // in the handling of mReportNextDraw post-draw. 4097 mAttachInfo.mThreadedRenderer.setStopped(false); 4098 } 4099 4100 if (updated) { 4101 requestDrawWindow(); 4102 } 4103 4104 useAsyncReport = true; 4105 4106 mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this); 4107 } else { 4108 // If we get here with a disabled & requested hardware renderer, something went 4109 // wrong (an invalidate posted right before we destroyed the hardware surface 4110 // for instance) so we should just bail out. Locking the surface with software 4111 // rendering at this point would lock it forever and prevent hardware renderer 4112 // from doing its job when it comes back. 4113 // Before we request a new frame we must however attempt to reinitiliaze the 4114 // hardware renderer if it's in requested state. This would happen after an 4115 // eglTerminate() for instance. 4116 if (mAttachInfo.mThreadedRenderer != null && 4117 !mAttachInfo.mThreadedRenderer.isEnabled() && 4118 mAttachInfo.mThreadedRenderer.isRequested() && 4119 mSurface.isValid()) { 4120 4121 try { 4122 mAttachInfo.mThreadedRenderer.initializeIfNeeded( 4123 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets); 4124 } catch (OutOfResourcesException e) { 4125 handleOutOfResourcesException(e); 4126 return false; 4127 } 4128 4129 mFullRedrawNeeded = true; 4130 scheduleTraversals(); 4131 return false; 4132 } 4133 4134 if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, 4135 scalingRequired, dirty, surfaceInsets)) { 4136 return false; 4137 } 4138 } 4139 } 4140 4141 if (animating) { 4142 mFullRedrawNeeded = true; 4143 scheduleTraversals(); 4144 } 4145 return useAsyncReport; 4146 } 4147 4148 /** 4149 * @return true if drawing was successful, false if an error occurred 4150 */ drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, boolean scalingRequired, Rect dirty, Rect surfaceInsets)4151 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, 4152 boolean scalingRequired, Rect dirty, Rect surfaceInsets) { 4153 4154 // Draw with software renderer. 4155 final Canvas canvas; 4156 4157 // We already have the offset of surfaceInsets in xoff, yoff and dirty region, 4158 // therefore we need to add it back when moving the dirty region. 4159 int dirtyXOffset = xoff; 4160 int dirtyYOffset = yoff; 4161 if (surfaceInsets != null) { 4162 dirtyXOffset += surfaceInsets.left; 4163 dirtyYOffset += surfaceInsets.top; 4164 } 4165 4166 try { 4167 dirty.offset(-dirtyXOffset, -dirtyYOffset); 4168 final int left = dirty.left; 4169 final int top = dirty.top; 4170 final int right = dirty.right; 4171 final int bottom = dirty.bottom; 4172 4173 canvas = mSurface.lockCanvas(dirty); 4174 4175 // TODO: Do this in native 4176 canvas.setDensity(mDensity); 4177 } catch (Surface.OutOfResourcesException e) { 4178 handleOutOfResourcesException(e); 4179 return false; 4180 } catch (IllegalArgumentException e) { 4181 Log.e(mTag, "Could not lock surface", e); 4182 // Don't assume this is due to out of memory, it could be 4183 // something else, and if it is something else then we could 4184 // kill stuff (or ourself) for no reason. 4185 mLayoutRequested = true; // ask wm for a new surface next time. 4186 return false; 4187 } finally { 4188 dirty.offset(dirtyXOffset, dirtyYOffset); // Reset to the original value. 4189 } 4190 4191 try { 4192 if (DEBUG_ORIENTATION || DEBUG_DRAW) { 4193 Log.v(mTag, "Surface " + surface + " drawing to bitmap w=" 4194 + canvas.getWidth() + ", h=" + canvas.getHeight()); 4195 //canvas.drawARGB(255, 255, 0, 0); 4196 } 4197 4198 // If this bitmap's format includes an alpha channel, we 4199 // need to clear it before drawing so that the child will 4200 // properly re-composite its drawing on a transparent 4201 // background. This automatically respects the clip/dirty region 4202 // or 4203 // If we are applying an offset, we need to clear the area 4204 // where the offset doesn't appear to avoid having garbage 4205 // left in the blank areas. 4206 if (!canvas.isOpaque() || yoff != 0 || xoff != 0) { 4207 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 4208 } 4209 4210 dirty.setEmpty(); 4211 mIsAnimating = false; 4212 mView.mPrivateFlags |= View.PFLAG_DRAWN; 4213 4214 if (DEBUG_DRAW) { 4215 Context cxt = mView.getContext(); 4216 Log.i(mTag, "Drawing: package:" + cxt.getPackageName() + 4217 ", metrics=" + cxt.getResources().getDisplayMetrics() + 4218 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo()); 4219 } 4220 canvas.translate(-xoff, -yoff); 4221 if (mTranslator != null) { 4222 mTranslator.translateCanvas(canvas); 4223 } 4224 canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0); 4225 4226 mView.draw(canvas); 4227 4228 drawAccessibilityFocusedDrawableIfNeeded(canvas); 4229 } finally { 4230 try { 4231 surface.unlockCanvasAndPost(canvas); 4232 } catch (IllegalArgumentException e) { 4233 Log.e(mTag, "Could not unlock surface", e); 4234 mLayoutRequested = true; // ask wm for a new surface next time. 4235 //noinspection ReturnInsideFinallyBlock 4236 return false; 4237 } 4238 4239 if (LOCAL_LOGV) { 4240 Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost"); 4241 } 4242 } 4243 return true; 4244 } 4245 4246 /** 4247 * We want to draw a highlight around the current accessibility focused. 4248 * Since adding a style for all possible view is not a viable option we 4249 * have this specialized drawing method. 4250 * 4251 * Note: We are doing this here to be able to draw the highlight for 4252 * virtual views in addition to real ones. 4253 * 4254 * @param canvas The canvas on which to draw. 4255 */ drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas)4256 private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) { 4257 final Rect bounds = mAttachInfo.mTmpInvalRect; 4258 if (getAccessibilityFocusedRect(bounds)) { 4259 final Drawable drawable = getAccessibilityFocusedDrawable(); 4260 if (drawable != null) { 4261 drawable.setBounds(bounds); 4262 drawable.draw(canvas); 4263 } 4264 } else if (mAttachInfo.mAccessibilityFocusDrawable != null) { 4265 mAttachInfo.mAccessibilityFocusDrawable.setBounds(0, 0, 0, 0); 4266 } 4267 } 4268 getAccessibilityFocusedRect(Rect bounds)4269 private boolean getAccessibilityFocusedRect(Rect bounds) { 4270 final AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext); 4271 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 4272 return false; 4273 } 4274 4275 final View host = mAccessibilityFocusedHost; 4276 if (host == null || host.mAttachInfo == null) { 4277 return false; 4278 } 4279 4280 final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider(); 4281 if (provider == null) { 4282 host.getBoundsOnScreen(bounds, true); 4283 } else if (mAccessibilityFocusedVirtualView != null) { 4284 mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds); 4285 } else { 4286 return false; 4287 } 4288 4289 // Transform the rect into window-relative coordinates. 4290 final AttachInfo attachInfo = mAttachInfo; 4291 bounds.offset(0, attachInfo.mViewRootImpl.mScrollY); 4292 bounds.offset(-attachInfo.mWindowLeft, -attachInfo.mWindowTop); 4293 if (!bounds.intersect(0, 0, attachInfo.mViewRootImpl.mWidth, 4294 attachInfo.mViewRootImpl.mHeight)) { 4295 // If no intersection, set bounds to empty. 4296 bounds.setEmpty(); 4297 } 4298 return !bounds.isEmpty(); 4299 } 4300 getAccessibilityFocusedDrawable()4301 private Drawable getAccessibilityFocusedDrawable() { 4302 // Lazily load the accessibility focus drawable. 4303 if (mAttachInfo.mAccessibilityFocusDrawable == null) { 4304 final TypedValue value = new TypedValue(); 4305 final boolean resolved = mView.mContext.getTheme().resolveAttribute( 4306 R.attr.accessibilityFocusedDrawable, value, true); 4307 if (resolved) { 4308 mAttachInfo.mAccessibilityFocusDrawable = 4309 mView.mContext.getDrawable(value.resourceId); 4310 } 4311 } 4312 return mAttachInfo.mAccessibilityFocusDrawable; 4313 } 4314 updateSystemGestureExclusionRectsForView(View view)4315 void updateSystemGestureExclusionRectsForView(View view) { 4316 mGestureExclusionTracker.updateRectsForView(view); 4317 mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED); 4318 } 4319 systemGestureExclusionChanged()4320 void systemGestureExclusionChanged() { 4321 final List<Rect> rectsForWindowManager = mGestureExclusionTracker.computeChangedRects(); 4322 if (rectsForWindowManager != null && mView != null) { 4323 try { 4324 mWindowSession.reportSystemGestureExclusionChanged(mWindow, rectsForWindowManager); 4325 } catch (RemoteException e) { 4326 throw e.rethrowFromSystemServer(); 4327 } 4328 mAttachInfo.mTreeObserver 4329 .dispatchOnSystemGestureExclusionRectsChanged(rectsForWindowManager); 4330 } 4331 } 4332 updateLocationInParentDisplay(int x, int y)4333 void updateLocationInParentDisplay(int x, int y) { 4334 if (mAttachInfo != null 4335 && !mAttachInfo.mLocationInParentDisplay.equals(x, y)) { 4336 mAttachInfo.mLocationInParentDisplay.set(x, y); 4337 } 4338 } 4339 4340 /** 4341 * Set the root-level system gesture exclusion rects. These are added to those provided by 4342 * the root's view hierarchy. 4343 */ setRootSystemGestureExclusionRects(@onNull List<Rect> rects)4344 public void setRootSystemGestureExclusionRects(@NonNull List<Rect> rects) { 4345 mGestureExclusionTracker.setRootSystemGestureExclusionRects(rects); 4346 mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED); 4347 } 4348 4349 /** 4350 * Returns the root-level system gesture exclusion rects. These do not include those provided by 4351 * the root's view hierarchy. 4352 */ 4353 @NonNull getRootSystemGestureExclusionRects()4354 public List<Rect> getRootSystemGestureExclusionRects() { 4355 return mGestureExclusionTracker.getRootSystemGestureExclusionRects(); 4356 } 4357 4358 /** 4359 * Requests that the root render node is invalidated next time we perform a draw, such that 4360 * {@link WindowCallbacks#onPostDraw} gets called. 4361 */ requestInvalidateRootRenderNode()4362 public void requestInvalidateRootRenderNode() { 4363 mInvalidateRootRequested = true; 4364 } 4365 scrollToRectOrFocus(Rect rectangle, boolean immediate)4366 boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) { 4367 final Rect ci = getWindowInsets(false).getSystemWindowInsetsAsRect(); 4368 final Rect vi = mAttachInfo.mVisibleInsets; 4369 int scrollY = 0; 4370 boolean handled = false; 4371 4372 if (vi.left > ci.left || vi.top > ci.top 4373 || vi.right > ci.right || vi.bottom > ci.bottom) { 4374 // We'll assume that we aren't going to change the scroll 4375 // offset, since we want to avoid that unless it is actually 4376 // going to make the focus visible... otherwise we scroll 4377 // all over the place. 4378 scrollY = mScrollY; 4379 // We can be called for two different situations: during a draw, 4380 // to update the scroll position if the focus has changed (in which 4381 // case 'rectangle' is null), or in response to a 4382 // requestChildRectangleOnScreen() call (in which case 'rectangle' 4383 // is non-null and we just want to scroll to whatever that 4384 // rectangle is). 4385 final View focus = mView.findFocus(); 4386 if (focus == null) { 4387 return false; 4388 } 4389 View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null; 4390 if (focus != lastScrolledFocus) { 4391 // If the focus has changed, then ignore any requests to scroll 4392 // to a rectangle; first we want to make sure the entire focus 4393 // view is visible. 4394 rectangle = null; 4395 } 4396 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Eval scroll: focus=" + focus 4397 + " rectangle=" + rectangle + " ci=" + ci 4398 + " vi=" + vi); 4399 if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) { 4400 // Optimization: if the focus hasn't changed since last 4401 // time, and no layout has happened, then just leave things 4402 // as they are. 4403 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Keeping scroll y=" 4404 + mScrollY + " vi=" + vi.toShortString()); 4405 } else { 4406 // We need to determine if the currently focused view is 4407 // within the visible part of the window and, if not, apply 4408 // a pan so it can be seen. 4409 mLastScrolledFocus = new WeakReference<View>(focus); 4410 mScrollMayChange = false; 4411 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Need to scroll?"); 4412 // Try to find the rectangle from the focus view. 4413 if (focus.getGlobalVisibleRect(mVisRect, null)) { 4414 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Root w=" 4415 + mView.getWidth() + " h=" + mView.getHeight() 4416 + " ci=" + ci.toShortString() 4417 + " vi=" + vi.toShortString()); 4418 if (rectangle == null) { 4419 focus.getFocusedRect(mTempRect); 4420 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Focus " + focus 4421 + ": focusRect=" + mTempRect.toShortString()); 4422 if (mView instanceof ViewGroup) { 4423 ((ViewGroup) mView).offsetDescendantRectToMyCoords( 4424 focus, mTempRect); 4425 } 4426 if (DEBUG_INPUT_RESIZE) Log.v(mTag, 4427 "Focus in window: focusRect=" 4428 + mTempRect.toShortString() 4429 + " visRect=" + mVisRect.toShortString()); 4430 } else { 4431 mTempRect.set(rectangle); 4432 if (DEBUG_INPUT_RESIZE) Log.v(mTag, 4433 "Request scroll to rect: " 4434 + mTempRect.toShortString() 4435 + " visRect=" + mVisRect.toShortString()); 4436 } 4437 if (mTempRect.intersect(mVisRect)) { 4438 if (DEBUG_INPUT_RESIZE) Log.v(mTag, 4439 "Focus window visible rect: " 4440 + mTempRect.toShortString()); 4441 if (mTempRect.height() > 4442 (mView.getHeight()-vi.top-vi.bottom)) { 4443 // If the focus simply is not going to fit, then 4444 // best is probably just to leave things as-is. 4445 if (DEBUG_INPUT_RESIZE) Log.v(mTag, 4446 "Too tall; leaving scrollY=" + scrollY); 4447 } 4448 // Next, check whether top or bottom is covered based on the non-scrolled 4449 // position, and calculate new scrollY (or set it to 0). 4450 // We can't keep using mScrollY here. For example mScrollY is non-zero 4451 // due to IME, then IME goes away. The current value of mScrollY leaves top 4452 // and bottom both visible, but we still need to scroll it back to 0. 4453 else if (mTempRect.top < vi.top) { 4454 scrollY = mTempRect.top - vi.top; 4455 if (DEBUG_INPUT_RESIZE) Log.v(mTag, 4456 "Top covered; scrollY=" + scrollY); 4457 } else if (mTempRect.bottom > (mView.getHeight()-vi.bottom)) { 4458 scrollY = mTempRect.bottom - (mView.getHeight()-vi.bottom); 4459 if (DEBUG_INPUT_RESIZE) Log.v(mTag, 4460 "Bottom covered; scrollY=" + scrollY); 4461 } else { 4462 scrollY = 0; 4463 } 4464 handled = true; 4465 } 4466 } 4467 } 4468 } 4469 4470 if (scrollY != mScrollY) { 4471 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Pan scroll changed: old=" 4472 + mScrollY + " , new=" + scrollY); 4473 if (!immediate) { 4474 if (mScroller == null) { 4475 mScroller = new Scroller(mView.getContext()); 4476 } 4477 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY); 4478 } else if (mScroller != null) { 4479 mScroller.abortAnimation(); 4480 } 4481 mScrollY = scrollY; 4482 } 4483 4484 return handled; 4485 } 4486 4487 /** 4488 * @hide 4489 */ 4490 @UnsupportedAppUsage getAccessibilityFocusedHost()4491 public View getAccessibilityFocusedHost() { 4492 return mAccessibilityFocusedHost; 4493 } 4494 4495 /** 4496 * @hide 4497 */ 4498 @UnsupportedAppUsage getAccessibilityFocusedVirtualView()4499 public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() { 4500 return mAccessibilityFocusedVirtualView; 4501 } 4502 setAccessibilityFocus(View view, AccessibilityNodeInfo node)4503 void setAccessibilityFocus(View view, AccessibilityNodeInfo node) { 4504 // If we have a virtual view with accessibility focus we need 4505 // to clear the focus and invalidate the virtual view bounds. 4506 if (mAccessibilityFocusedVirtualView != null) { 4507 4508 AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView; 4509 View focusHost = mAccessibilityFocusedHost; 4510 4511 // Wipe the state of the current accessibility focus since 4512 // the call into the provider to clear accessibility focus 4513 // will fire an accessibility event which will end up calling 4514 // this method and we want to have clean state when this 4515 // invocation happens. 4516 mAccessibilityFocusedHost = null; 4517 mAccessibilityFocusedVirtualView = null; 4518 4519 // Clear accessibility focus on the host after clearing state since 4520 // this method may be reentrant. 4521 focusHost.clearAccessibilityFocusNoCallbacks( 4522 AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 4523 4524 AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider(); 4525 if (provider != null) { 4526 // Invalidate the area of the cleared accessibility focus. 4527 focusNode.getBoundsInParent(mTempRect); 4528 focusHost.invalidate(mTempRect); 4529 // Clear accessibility focus in the virtual node. 4530 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId( 4531 focusNode.getSourceNodeId()); 4532 provider.performAction(virtualNodeId, 4533 AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null); 4534 } 4535 focusNode.recycle(); 4536 } 4537 if ((mAccessibilityFocusedHost != null) && (mAccessibilityFocusedHost != view)) { 4538 // Clear accessibility focus in the view. 4539 mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks( 4540 AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 4541 } 4542 4543 // Set the new focus host and node. 4544 mAccessibilityFocusedHost = view; 4545 mAccessibilityFocusedVirtualView = node; 4546 4547 if (mAttachInfo.mThreadedRenderer != null) { 4548 mAttachInfo.mThreadedRenderer.invalidateRoot(); 4549 } 4550 } 4551 hasPointerCapture()4552 boolean hasPointerCapture() { 4553 return mPointerCapture; 4554 } 4555 requestPointerCapture(boolean enabled)4556 void requestPointerCapture(boolean enabled) { 4557 if (mPointerCapture == enabled) { 4558 return; 4559 } 4560 InputManager.getInstance().requestPointerCapture(mAttachInfo.mWindowToken, enabled); 4561 } 4562 handlePointerCaptureChanged(boolean hasCapture)4563 private void handlePointerCaptureChanged(boolean hasCapture) { 4564 if (mPointerCapture == hasCapture) { 4565 return; 4566 } 4567 mPointerCapture = hasCapture; 4568 if (mView != null) { 4569 mView.dispatchPointerCaptureChanged(hasCapture); 4570 } 4571 } 4572 hasColorModeChanged(int colorMode)4573 private boolean hasColorModeChanged(int colorMode) { 4574 if (mAttachInfo.mThreadedRenderer == null) { 4575 return false; 4576 } 4577 final boolean isWideGamut = colorMode == ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT; 4578 if (mAttachInfo.mThreadedRenderer.isWideGamut() == isWideGamut) { 4579 return false; 4580 } 4581 if (isWideGamut && !mContext.getResources().getConfiguration().isScreenWideColorGamut()) { 4582 return false; 4583 } 4584 return true; 4585 } 4586 4587 @Override requestChildFocus(View child, View focused)4588 public void requestChildFocus(View child, View focused) { 4589 if (DEBUG_INPUT_RESIZE) { 4590 Log.v(mTag, "Request child focus: focus now " + focused); 4591 } 4592 checkThread(); 4593 scheduleTraversals(); 4594 } 4595 4596 @Override clearChildFocus(View child)4597 public void clearChildFocus(View child) { 4598 if (DEBUG_INPUT_RESIZE) { 4599 Log.v(mTag, "Clearing child focus"); 4600 } 4601 checkThread(); 4602 scheduleTraversals(); 4603 } 4604 4605 @Override getParentForAccessibility()4606 public ViewParent getParentForAccessibility() { 4607 return null; 4608 } 4609 4610 @Override focusableViewAvailable(View v)4611 public void focusableViewAvailable(View v) { 4612 checkThread(); 4613 if (mView != null) { 4614 if (!mView.hasFocus()) { 4615 if (sAlwaysAssignFocus || !mAttachInfo.mInTouchMode) { 4616 v.requestFocus(); 4617 } 4618 } else { 4619 // the one case where will transfer focus away from the current one 4620 // is if the current view is a view group that prefers to give focus 4621 // to its children first AND the view is a descendant of it. 4622 View focused = mView.findFocus(); 4623 if (focused instanceof ViewGroup) { 4624 ViewGroup group = (ViewGroup) focused; 4625 if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS 4626 && isViewDescendantOf(v, focused)) { 4627 v.requestFocus(); 4628 } 4629 } 4630 } 4631 } 4632 } 4633 4634 @Override recomputeViewAttributes(View child)4635 public void recomputeViewAttributes(View child) { 4636 checkThread(); 4637 if (mView == child) { 4638 mAttachInfo.mRecomputeGlobalAttributes = true; 4639 if (!mWillDrawSoon) { 4640 scheduleTraversals(); 4641 } 4642 } 4643 } 4644 dispatchDetachedFromWindow()4645 void dispatchDetachedFromWindow() { 4646 // Make sure we free-up insets resources if view never received onWindowFocusLost() 4647 // because of a die-signal 4648 mInsetsController.onWindowFocusLost(); 4649 mFirstInputStage.onDetachedFromWindow(); 4650 if (mView != null && mView.mAttachInfo != null) { 4651 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false); 4652 mView.dispatchDetachedFromWindow(); 4653 } 4654 4655 mAccessibilityInteractionConnectionManager.ensureNoConnection(); 4656 mAccessibilityManager.removeAccessibilityStateChangeListener( 4657 mAccessibilityInteractionConnectionManager); 4658 mAccessibilityManager.removeHighTextContrastStateChangeListener( 4659 mHighContrastTextManager); 4660 removeSendWindowContentChangedCallback(); 4661 4662 destroyHardwareRenderer(); 4663 4664 setAccessibilityFocus(null, null); 4665 4666 mInsetsController.cancelExistingAnimations(); 4667 4668 mView.assignParent(null); 4669 mView = null; 4670 mAttachInfo.mRootView = null; 4671 4672 destroySurface(); 4673 4674 if (mInputQueueCallback != null && mInputQueue != null) { 4675 mInputQueueCallback.onInputQueueDestroyed(mInputQueue); 4676 mInputQueue.dispose(); 4677 mInputQueueCallback = null; 4678 mInputQueue = null; 4679 } 4680 try { 4681 mWindowSession.remove(mWindow); 4682 } catch (RemoteException e) { 4683 } 4684 // Dispose receiver would dispose client InputChannel, too. That could send out a socket 4685 // broken event, so we need to unregister the server InputChannel when removing window to 4686 // prevent server side receive the event and prompt error. 4687 if (mInputEventReceiver != null) { 4688 mInputEventReceiver.dispose(); 4689 mInputEventReceiver = null; 4690 } 4691 4692 mDisplayManager.unregisterDisplayListener(mDisplayListener); 4693 4694 unscheduleTraversals(); 4695 } 4696 4697 /** 4698 * Notifies all callbacks that configuration and/or display has changed and updates internal 4699 * state. 4700 * @param mergedConfiguration New global and override config in {@link MergedConfiguration} 4701 * container. 4702 * @param force Flag indicating if we should force apply the config. 4703 * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} if not 4704 * changed. 4705 */ performConfigurationChange(MergedConfiguration mergedConfiguration, boolean force, int newDisplayId)4706 private void performConfigurationChange(MergedConfiguration mergedConfiguration, boolean force, 4707 int newDisplayId) { 4708 if (mergedConfiguration == null) { 4709 throw new IllegalArgumentException("No merged config provided."); 4710 } 4711 4712 Configuration globalConfig = mergedConfiguration.getGlobalConfiguration(); 4713 final Configuration overrideConfig = mergedConfiguration.getOverrideConfiguration(); 4714 if (DEBUG_CONFIGURATION) Log.v(mTag, 4715 "Applying new config to window " + mWindowAttributes.getTitle() 4716 + ", globalConfig: " + globalConfig 4717 + ", overrideConfig: " + overrideConfig); 4718 4719 final CompatibilityInfo ci = mDisplay.getDisplayAdjustments().getCompatibilityInfo(); 4720 if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) { 4721 globalConfig = new Configuration(globalConfig); 4722 ci.applyToConfiguration(mNoncompatDensity, globalConfig); 4723 } 4724 4725 synchronized (sConfigCallbacks) { 4726 for (int i=sConfigCallbacks.size()-1; i>=0; i--) { 4727 sConfigCallbacks.get(i).onConfigurationChanged(globalConfig); 4728 } 4729 } 4730 4731 mLastReportedMergedConfiguration.setConfiguration(globalConfig, overrideConfig); 4732 4733 mForceNextConfigUpdate = force; 4734 if (mActivityConfigCallback != null) { 4735 // An activity callback is set - notify it about override configuration update. 4736 // This basically initiates a round trip to ActivityThread and back, which will ensure 4737 // that corresponding activity and resources are updated before updating inner state of 4738 // ViewRootImpl. Eventually it will call #updateConfiguration(). 4739 mActivityConfigCallback.onConfigurationChanged(overrideConfig, newDisplayId); 4740 } else { 4741 // There is no activity callback - update the configuration right away. 4742 updateConfiguration(newDisplayId); 4743 } 4744 mForceNextConfigUpdate = false; 4745 } 4746 4747 /** 4748 * Update display and views if last applied merged configuration changed. 4749 * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} otherwise. 4750 */ updateConfiguration(int newDisplayId)4751 public void updateConfiguration(int newDisplayId) { 4752 if (mView == null) { 4753 return; 4754 } 4755 4756 // At this point the resources have been updated to 4757 // have the most recent config, whatever that is. Use 4758 // the one in them which may be newer. 4759 final Resources localResources = mView.getResources(); 4760 final Configuration config = localResources.getConfiguration(); 4761 4762 // Handle move to display. 4763 if (newDisplayId != INVALID_DISPLAY) { 4764 onMovedToDisplay(newDisplayId, config); 4765 } 4766 4767 // Handle configuration change. 4768 if (mForceNextConfigUpdate || mLastConfigurationFromResources.diff(config) != 0) { 4769 // Update the display with new DisplayAdjustments. 4770 updateInternalDisplay(mDisplay.getDisplayId(), localResources); 4771 4772 final int lastLayoutDirection = mLastConfigurationFromResources.getLayoutDirection(); 4773 final int currentLayoutDirection = config.getLayoutDirection(); 4774 mLastConfigurationFromResources.setTo(config); 4775 if (lastLayoutDirection != currentLayoutDirection 4776 && mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) { 4777 mView.setLayoutDirection(currentLayoutDirection); 4778 } 4779 mView.dispatchConfigurationChanged(config); 4780 4781 // We could have gotten this {@link Configuration} update after we called 4782 // {@link #performTraversals} with an older {@link Configuration}. As a result, our 4783 // window frame may be stale. We must ensure the next pass of {@link #performTraversals} 4784 // catches this. 4785 mForceNextWindowRelayout = true; 4786 requestLayout(); 4787 } 4788 4789 updateForceDarkMode(); 4790 } 4791 4792 /** 4793 * Return true if child is an ancestor of parent, (or equal to the parent). 4794 */ isViewDescendantOf(View child, View parent)4795 public static boolean isViewDescendantOf(View child, View parent) { 4796 if (child == parent) { 4797 return true; 4798 } 4799 4800 final ViewParent theParent = child.getParent(); 4801 return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent); 4802 } 4803 forceLayout(View view)4804 private static void forceLayout(View view) { 4805 view.forceLayout(); 4806 if (view instanceof ViewGroup) { 4807 ViewGroup group = (ViewGroup) view; 4808 final int count = group.getChildCount(); 4809 for (int i = 0; i < count; i++) { 4810 forceLayout(group.getChildAt(i)); 4811 } 4812 } 4813 } 4814 4815 private static final int MSG_INVALIDATE = 1; 4816 private static final int MSG_INVALIDATE_RECT = 2; 4817 private static final int MSG_DIE = 3; 4818 private static final int MSG_RESIZED = 4; 4819 private static final int MSG_RESIZED_REPORT = 5; 4820 private static final int MSG_WINDOW_FOCUS_CHANGED = 6; 4821 private static final int MSG_DISPATCH_INPUT_EVENT = 7; 4822 private static final int MSG_DISPATCH_APP_VISIBILITY = 8; 4823 private static final int MSG_DISPATCH_GET_NEW_SURFACE = 9; 4824 private static final int MSG_DISPATCH_KEY_FROM_IME = 11; 4825 private static final int MSG_DISPATCH_KEY_FROM_AUTOFILL = 12; 4826 private static final int MSG_CHECK_FOCUS = 13; 4827 private static final int MSG_CLOSE_SYSTEM_DIALOGS = 14; 4828 private static final int MSG_DISPATCH_DRAG_EVENT = 15; 4829 private static final int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16; 4830 private static final int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17; 4831 private static final int MSG_UPDATE_CONFIGURATION = 18; 4832 private static final int MSG_PROCESS_INPUT_EVENTS = 19; 4833 private static final int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21; 4834 private static final int MSG_INVALIDATE_WORLD = 22; 4835 private static final int MSG_WINDOW_MOVED = 23; 4836 private static final int MSG_SYNTHESIZE_INPUT_EVENT = 24; 4837 private static final int MSG_DISPATCH_WINDOW_SHOWN = 25; 4838 private static final int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26; 4839 private static final int MSG_UPDATE_POINTER_ICON = 27; 4840 private static final int MSG_POINTER_CAPTURE_CHANGED = 28; 4841 private static final int MSG_DRAW_FINISHED = 29; 4842 private static final int MSG_INSETS_CHANGED = 30; 4843 private static final int MSG_INSETS_CONTROL_CHANGED = 31; 4844 private static final int MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED = 32; 4845 private static final int MSG_LOCATION_IN_PARENT_DISPLAY_CHANGED = 33; 4846 private static final int MSG_SHOW_INSETS = 34; 4847 private static final int MSG_HIDE_INSETS = 35; 4848 private static final int MSG_REQUEST_SCROLL_CAPTURE = 36; 4849 4850 4851 final class ViewRootHandler extends Handler { 4852 @Override getMessageName(Message message)4853 public String getMessageName(Message message) { 4854 switch (message.what) { 4855 case MSG_INVALIDATE: 4856 return "MSG_INVALIDATE"; 4857 case MSG_INVALIDATE_RECT: 4858 return "MSG_INVALIDATE_RECT"; 4859 case MSG_DIE: 4860 return "MSG_DIE"; 4861 case MSG_RESIZED: 4862 return "MSG_RESIZED"; 4863 case MSG_RESIZED_REPORT: 4864 return "MSG_RESIZED_REPORT"; 4865 case MSG_WINDOW_FOCUS_CHANGED: 4866 return "MSG_WINDOW_FOCUS_CHANGED"; 4867 case MSG_DISPATCH_INPUT_EVENT: 4868 return "MSG_DISPATCH_INPUT_EVENT"; 4869 case MSG_DISPATCH_APP_VISIBILITY: 4870 return "MSG_DISPATCH_APP_VISIBILITY"; 4871 case MSG_DISPATCH_GET_NEW_SURFACE: 4872 return "MSG_DISPATCH_GET_NEW_SURFACE"; 4873 case MSG_DISPATCH_KEY_FROM_IME: 4874 return "MSG_DISPATCH_KEY_FROM_IME"; 4875 case MSG_DISPATCH_KEY_FROM_AUTOFILL: 4876 return "MSG_DISPATCH_KEY_FROM_AUTOFILL"; 4877 case MSG_CHECK_FOCUS: 4878 return "MSG_CHECK_FOCUS"; 4879 case MSG_CLOSE_SYSTEM_DIALOGS: 4880 return "MSG_CLOSE_SYSTEM_DIALOGS"; 4881 case MSG_DISPATCH_DRAG_EVENT: 4882 return "MSG_DISPATCH_DRAG_EVENT"; 4883 case MSG_DISPATCH_DRAG_LOCATION_EVENT: 4884 return "MSG_DISPATCH_DRAG_LOCATION_EVENT"; 4885 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: 4886 return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY"; 4887 case MSG_UPDATE_CONFIGURATION: 4888 return "MSG_UPDATE_CONFIGURATION"; 4889 case MSG_PROCESS_INPUT_EVENTS: 4890 return "MSG_PROCESS_INPUT_EVENTS"; 4891 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: 4892 return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST"; 4893 case MSG_WINDOW_MOVED: 4894 return "MSG_WINDOW_MOVED"; 4895 case MSG_SYNTHESIZE_INPUT_EVENT: 4896 return "MSG_SYNTHESIZE_INPUT_EVENT"; 4897 case MSG_DISPATCH_WINDOW_SHOWN: 4898 return "MSG_DISPATCH_WINDOW_SHOWN"; 4899 case MSG_UPDATE_POINTER_ICON: 4900 return "MSG_UPDATE_POINTER_ICON"; 4901 case MSG_POINTER_CAPTURE_CHANGED: 4902 return "MSG_POINTER_CAPTURE_CHANGED"; 4903 case MSG_DRAW_FINISHED: 4904 return "MSG_DRAW_FINISHED"; 4905 case MSG_INSETS_CHANGED: 4906 return "MSG_INSETS_CHANGED"; 4907 case MSG_INSETS_CONTROL_CHANGED: 4908 return "MSG_INSETS_CONTROL_CHANGED"; 4909 case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED: 4910 return "MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED"; 4911 case MSG_LOCATION_IN_PARENT_DISPLAY_CHANGED: 4912 return "MSG_LOCATION_IN_PARENT_DISPLAY_CHANGED"; 4913 case MSG_SHOW_INSETS: 4914 return "MSG_SHOW_INSETS"; 4915 case MSG_HIDE_INSETS: 4916 return "MSG_HIDE_INSETS"; 4917 } 4918 return super.getMessageName(message); 4919 } 4920 4921 @Override sendMessageAtTime(Message msg, long uptimeMillis)4922 public boolean sendMessageAtTime(Message msg, long uptimeMillis) { 4923 if (msg.what == MSG_REQUEST_KEYBOARD_SHORTCUTS && msg.obj == null) { 4924 // Debugging for b/27963013 4925 throw new NullPointerException( 4926 "Attempted to call MSG_REQUEST_KEYBOARD_SHORTCUTS with null receiver:"); 4927 } 4928 return super.sendMessageAtTime(msg, uptimeMillis); 4929 } 4930 4931 @Override handleMessage(Message msg)4932 public void handleMessage(Message msg) { 4933 switch (msg.what) { 4934 case MSG_INVALIDATE: 4935 ((View) msg.obj).invalidate(); 4936 break; 4937 case MSG_INVALIDATE_RECT: 4938 final View.AttachInfo.InvalidateInfo info = 4939 (View.AttachInfo.InvalidateInfo) msg.obj; 4940 info.target.invalidate(info.left, info.top, info.right, info.bottom); 4941 info.recycle(); 4942 break; 4943 case MSG_PROCESS_INPUT_EVENTS: 4944 mProcessInputEventsScheduled = false; 4945 doProcessInputEvents(); 4946 break; 4947 case MSG_DISPATCH_APP_VISIBILITY: 4948 handleAppVisibility(msg.arg1 != 0); 4949 break; 4950 case MSG_DISPATCH_GET_NEW_SURFACE: 4951 handleGetNewSurface(); 4952 break; 4953 case MSG_RESIZED: { 4954 // Recycled in the fall through... 4955 SomeArgs args = (SomeArgs) msg.obj; 4956 if (mWinFrame.equals(args.arg1) 4957 && mPendingDisplayCutout.get().equals(args.arg9) 4958 && mPendingBackDropFrame.equals(args.arg8) 4959 && mLastReportedMergedConfiguration.equals(args.arg4) 4960 && args.argi1 == 0 4961 && mDisplay.getDisplayId() == args.argi3) { 4962 break; 4963 } 4964 } // fall through... 4965 case MSG_RESIZED_REPORT: 4966 if (mAdded) { 4967 SomeArgs args = (SomeArgs) msg.obj; 4968 4969 final int displayId = args.argi3; 4970 MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg4; 4971 final boolean displayChanged = mDisplay.getDisplayId() != displayId; 4972 boolean configChanged = false; 4973 4974 if (!mLastReportedMergedConfiguration.equals(mergedConfiguration)) { 4975 // If configuration changed - notify about that and, maybe, 4976 // about move to display. 4977 performConfigurationChange(mergedConfiguration, false /* force */, 4978 displayChanged 4979 ? displayId : INVALID_DISPLAY /* same display */); 4980 configChanged = true; 4981 } else if (displayChanged) { 4982 // Moved to display without config change - report last applied one. 4983 onMovedToDisplay(displayId, mLastConfigurationFromResources); 4984 } 4985 4986 final boolean framesChanged = !mWinFrame.equals(args.arg1) 4987 || !mPendingDisplayCutout.get().equals(args.arg9); 4988 4989 setFrame((Rect) args.arg1); 4990 mPendingDisplayCutout.set((DisplayCutout) args.arg9); 4991 mPendingBackDropFrame.set((Rect) args.arg8); 4992 mForceNextWindowRelayout = args.argi1 != 0; 4993 mPendingAlwaysConsumeSystemBars = args.argi2 != 0; 4994 4995 args.recycle(); 4996 4997 if (msg.what == MSG_RESIZED_REPORT) { 4998 reportNextDraw(); 4999 } 5000 5001 if (mView != null && (framesChanged || configChanged)) { 5002 forceLayout(mView); 5003 } 5004 requestLayout(); 5005 } 5006 break; 5007 case MSG_INSETS_CHANGED: 5008 mInsetsController.onStateChanged((InsetsState) msg.obj); 5009 break; 5010 case MSG_INSETS_CONTROL_CHANGED: { 5011 SomeArgs args = (SomeArgs) msg.obj; 5012 5013 // Deliver state change before control change, such that: 5014 // a) When gaining control, controller can compare with server state to evaluate 5015 // whether it needs to run animation. 5016 // b) When loosing control, controller can restore server state by taking last 5017 // dispatched state as truth. 5018 mInsetsController.onStateChanged((InsetsState) args.arg1); 5019 mInsetsController.onControlsChanged((InsetsSourceControl[]) args.arg2); 5020 break; 5021 } 5022 case MSG_SHOW_INSETS: { 5023 if (mView == null) { 5024 Log.e(TAG, 5025 String.format("Calling showInsets(%d,%b) on window that no longer" 5026 + " has views.", msg.arg1, msg.arg2 == 1)); 5027 } 5028 clearLowProfileModeIfNeeded(msg.arg1, msg.arg2 == 1); 5029 mInsetsController.show(msg.arg1, msg.arg2 == 1); 5030 break; 5031 } 5032 case MSG_HIDE_INSETS: { 5033 mInsetsController.hide(msg.arg1, msg.arg2 == 1); 5034 break; 5035 } 5036 case MSG_WINDOW_MOVED: 5037 if (mAdded) { 5038 final int w = mWinFrame.width(); 5039 final int h = mWinFrame.height(); 5040 final int l = msg.arg1; 5041 final int t = msg.arg2; 5042 mTmpFrame.left = l; 5043 mTmpFrame.right = l + w; 5044 mTmpFrame.top = t; 5045 mTmpFrame.bottom = t + h; 5046 setFrame(mTmpFrame); 5047 5048 mPendingBackDropFrame.set(mWinFrame); 5049 maybeHandleWindowMove(mWinFrame); 5050 } 5051 break; 5052 case MSG_WINDOW_FOCUS_CHANGED: { 5053 handleWindowFocusChanged(); 5054 } break; 5055 case MSG_DIE: 5056 doDie(); 5057 break; 5058 case MSG_DISPATCH_INPUT_EVENT: { 5059 SomeArgs args = (SomeArgs) msg.obj; 5060 InputEvent event = (InputEvent) args.arg1; 5061 InputEventReceiver receiver = (InputEventReceiver) args.arg2; 5062 enqueueInputEvent(event, receiver, 0, true); 5063 args.recycle(); 5064 } break; 5065 case MSG_SYNTHESIZE_INPUT_EVENT: { 5066 InputEvent event = (InputEvent) msg.obj; 5067 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_UNHANDLED, true); 5068 } break; 5069 case MSG_DISPATCH_KEY_FROM_IME: { 5070 if (LOCAL_LOGV) { 5071 Log.v(TAG, "Dispatching key " + msg.obj + " from IME to " + mView); 5072 } 5073 KeyEvent event = (KeyEvent) msg.obj; 5074 if ((event.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) != 0) { 5075 // The IME is trying to say this event is from the 5076 // system! Bad bad bad! 5077 //noinspection UnusedAssignment 5078 event = KeyEvent.changeFlags(event, 5079 event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM); 5080 } 5081 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true); 5082 } break; 5083 case MSG_DISPATCH_KEY_FROM_AUTOFILL: { 5084 if (LOCAL_LOGV) { 5085 Log.v(TAG, "Dispatching key " + msg.obj + " from Autofill to " + mView); 5086 } 5087 KeyEvent event = (KeyEvent) msg.obj; 5088 enqueueInputEvent(event, null, 0, true); 5089 } break; 5090 case MSG_CHECK_FOCUS: { 5091 getImeFocusController().checkFocus(false, true); 5092 } break; 5093 case MSG_CLOSE_SYSTEM_DIALOGS: { 5094 if (mView != null) { 5095 mView.onCloseSystemDialogs((String) msg.obj); 5096 } 5097 } break; 5098 case MSG_DISPATCH_DRAG_EVENT: { 5099 } // fall through 5100 case MSG_DISPATCH_DRAG_LOCATION_EVENT: { 5101 DragEvent event = (DragEvent) msg.obj; 5102 // only present when this app called startDrag() 5103 event.mLocalState = mLocalDragState; 5104 handleDragEvent(event); 5105 } break; 5106 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: { 5107 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj); 5108 } break; 5109 case MSG_UPDATE_CONFIGURATION: { 5110 Configuration config = (Configuration) msg.obj; 5111 if (config.isOtherSeqNewer( 5112 mLastReportedMergedConfiguration.getMergedConfiguration())) { 5113 // If we already have a newer merged config applied - use its global part. 5114 config = mLastReportedMergedConfiguration.getGlobalConfiguration(); 5115 } 5116 5117 // Use the newer global config and last reported override config. 5118 mPendingMergedConfiguration.setConfiguration(config, 5119 mLastReportedMergedConfiguration.getOverrideConfiguration()); 5120 5121 performConfigurationChange(mPendingMergedConfiguration, false /* force */, 5122 INVALID_DISPLAY /* same display */); 5123 } break; 5124 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: { 5125 setAccessibilityFocus(null, null); 5126 } break; 5127 case MSG_INVALIDATE_WORLD: { 5128 if (mView != null) { 5129 invalidateWorld(mView); 5130 } 5131 } break; 5132 case MSG_DISPATCH_WINDOW_SHOWN: { 5133 handleDispatchWindowShown(); 5134 } break; 5135 case MSG_REQUEST_KEYBOARD_SHORTCUTS: { 5136 final IResultReceiver receiver = (IResultReceiver) msg.obj; 5137 final int deviceId = msg.arg1; 5138 handleRequestKeyboardShortcuts(receiver, deviceId); 5139 } break; 5140 case MSG_UPDATE_POINTER_ICON: { 5141 MotionEvent event = (MotionEvent) msg.obj; 5142 resetPointerIcon(event); 5143 } break; 5144 case MSG_POINTER_CAPTURE_CHANGED: { 5145 final boolean hasCapture = msg.arg1 != 0; 5146 handlePointerCaptureChanged(hasCapture); 5147 } break; 5148 case MSG_DRAW_FINISHED: { 5149 pendingDrawFinished(); 5150 } break; 5151 case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED: { 5152 systemGestureExclusionChanged(); 5153 } break; 5154 case MSG_LOCATION_IN_PARENT_DISPLAY_CHANGED: { 5155 updateLocationInParentDisplay(msg.arg1, msg.arg2); 5156 } break; 5157 case MSG_REQUEST_SCROLL_CAPTURE: 5158 handleScrollCaptureRequest((IScrollCaptureController) msg.obj); 5159 break; 5160 } 5161 } 5162 } 5163 5164 final ViewRootHandler mHandler = new ViewRootHandler(); 5165 5166 /** 5167 * Something in the current window tells us we need to change the touch mode. For 5168 * example, we are not in touch mode, and the user touches the screen. 5169 * 5170 * If the touch mode has changed, tell the window manager, and handle it locally. 5171 * 5172 * @param inTouchMode Whether we want to be in touch mode. 5173 * @return True if the touch mode changed and focus changed was changed as a result 5174 */ 5175 @UnsupportedAppUsage ensureTouchMode(boolean inTouchMode)5176 boolean ensureTouchMode(boolean inTouchMode) { 5177 if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current " 5178 + "touch mode is " + mAttachInfo.mInTouchMode); 5179 if (mAttachInfo.mInTouchMode == inTouchMode) return false; 5180 5181 // tell the window manager 5182 try { 5183 mWindowSession.setInTouchMode(inTouchMode); 5184 } catch (RemoteException e) { 5185 throw new RuntimeException(e); 5186 } 5187 5188 // handle the change 5189 return ensureTouchModeLocally(inTouchMode); 5190 } 5191 5192 /** 5193 * Ensure that the touch mode for this window is set, and if it is changing, 5194 * take the appropriate action. 5195 * @param inTouchMode Whether we want to be in touch mode. 5196 * @return True if the touch mode changed and focus changed was changed as a result 5197 */ ensureTouchModeLocally(boolean inTouchMode)5198 private boolean ensureTouchModeLocally(boolean inTouchMode) { 5199 if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current " 5200 + "touch mode is " + mAttachInfo.mInTouchMode); 5201 5202 if (mAttachInfo.mInTouchMode == inTouchMode) return false; 5203 5204 mAttachInfo.mInTouchMode = inTouchMode; 5205 mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode); 5206 5207 return (inTouchMode) ? enterTouchMode() : leaveTouchMode(); 5208 } 5209 enterTouchMode()5210 private boolean enterTouchMode() { 5211 if (mView != null && mView.hasFocus()) { 5212 // note: not relying on mFocusedView here because this could 5213 // be when the window is first being added, and mFocused isn't 5214 // set yet. 5215 final View focused = mView.findFocus(); 5216 if (focused != null && !focused.isFocusableInTouchMode()) { 5217 final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused); 5218 if (ancestorToTakeFocus != null) { 5219 // there is an ancestor that wants focus after its 5220 // descendants that is focusable in touch mode.. give it 5221 // focus 5222 return ancestorToTakeFocus.requestFocus(); 5223 } else { 5224 // There's nothing to focus. Clear and propagate through the 5225 // hierarchy, but don't attempt to place new focus. 5226 focused.clearFocusInternal(null, true, false); 5227 return true; 5228 } 5229 } 5230 } 5231 return false; 5232 } 5233 5234 /** 5235 * Find an ancestor of focused that wants focus after its descendants and is 5236 * focusable in touch mode. 5237 * @param focused The currently focused view. 5238 * @return An appropriate view, or null if no such view exists. 5239 */ findAncestorToTakeFocusInTouchMode(View focused)5240 private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) { 5241 ViewParent parent = focused.getParent(); 5242 while (parent instanceof ViewGroup) { 5243 final ViewGroup vgParent = (ViewGroup) parent; 5244 if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS 5245 && vgParent.isFocusableInTouchMode()) { 5246 return vgParent; 5247 } 5248 if (vgParent.isRootNamespace()) { 5249 return null; 5250 } else { 5251 parent = vgParent.getParent(); 5252 } 5253 } 5254 return null; 5255 } 5256 leaveTouchMode()5257 private boolean leaveTouchMode() { 5258 if (mView != null) { 5259 if (mView.hasFocus()) { 5260 View focusedView = mView.findFocus(); 5261 if (!(focusedView instanceof ViewGroup)) { 5262 // some view has focus, let it keep it 5263 return false; 5264 } else if (((ViewGroup) focusedView).getDescendantFocusability() != 5265 ViewGroup.FOCUS_AFTER_DESCENDANTS) { 5266 // some view group has focus, and doesn't prefer its children 5267 // over itself for focus, so let them keep it. 5268 return false; 5269 } 5270 } 5271 5272 // find the best view to give focus to in this brave new non-touch-mode 5273 // world 5274 return mView.restoreDefaultFocus(); 5275 } 5276 return false; 5277 } 5278 5279 /** 5280 * Base class for implementing a stage in the chain of responsibility 5281 * for processing input events. 5282 * <p> 5283 * Events are delivered to the stage by the {@link #deliver} method. The stage 5284 * then has the choice of finishing the event or forwarding it to the next stage. 5285 * </p> 5286 */ 5287 abstract class InputStage { 5288 private final InputStage mNext; 5289 5290 protected static final int FORWARD = 0; 5291 protected static final int FINISH_HANDLED = 1; 5292 protected static final int FINISH_NOT_HANDLED = 2; 5293 5294 private String mTracePrefix; 5295 5296 /** 5297 * Creates an input stage. 5298 * @param next The next stage to which events should be forwarded. 5299 */ InputStage(InputStage next)5300 public InputStage(InputStage next) { 5301 mNext = next; 5302 } 5303 5304 /** 5305 * Delivers an event to be processed. 5306 */ deliver(QueuedInputEvent q)5307 public final void deliver(QueuedInputEvent q) { 5308 if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) { 5309 forward(q); 5310 } else if (shouldDropInputEvent(q)) { 5311 finish(q, false); 5312 } else { 5313 traceEvent(q, Trace.TRACE_TAG_VIEW); 5314 final int result; 5315 try { 5316 result = onProcess(q); 5317 } finally { 5318 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 5319 } 5320 apply(q, result); 5321 } 5322 } 5323 5324 /** 5325 * Marks the the input event as finished then forwards it to the next stage. 5326 */ finish(QueuedInputEvent q, boolean handled)5327 protected void finish(QueuedInputEvent q, boolean handled) { 5328 q.mFlags |= QueuedInputEvent.FLAG_FINISHED; 5329 if (handled) { 5330 q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED; 5331 } 5332 forward(q); 5333 } 5334 5335 /** 5336 * Forwards the event to the next stage. 5337 */ forward(QueuedInputEvent q)5338 protected void forward(QueuedInputEvent q) { 5339 onDeliverToNext(q); 5340 } 5341 5342 /** 5343 * Applies a result code from {@link #onProcess} to the specified event. 5344 */ apply(QueuedInputEvent q, int result)5345 protected void apply(QueuedInputEvent q, int result) { 5346 if (result == FORWARD) { 5347 forward(q); 5348 } else if (result == FINISH_HANDLED) { 5349 finish(q, true); 5350 } else if (result == FINISH_NOT_HANDLED) { 5351 finish(q, false); 5352 } else { 5353 throw new IllegalArgumentException("Invalid result: " + result); 5354 } 5355 } 5356 5357 /** 5358 * Called when an event is ready to be processed. 5359 * @return A result code indicating how the event was handled. 5360 */ onProcess(QueuedInputEvent q)5361 protected int onProcess(QueuedInputEvent q) { 5362 return FORWARD; 5363 } 5364 5365 /** 5366 * Called when an event is being delivered to the next stage. 5367 */ onDeliverToNext(QueuedInputEvent q)5368 protected void onDeliverToNext(QueuedInputEvent q) { 5369 if (DEBUG_INPUT_STAGES) { 5370 Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q); 5371 } 5372 if (mNext != null) { 5373 mNext.deliver(q); 5374 } else { 5375 finishInputEvent(q); 5376 } 5377 } 5378 onWindowFocusChanged(boolean hasWindowFocus)5379 protected void onWindowFocusChanged(boolean hasWindowFocus) { 5380 if (mNext != null) { 5381 mNext.onWindowFocusChanged(hasWindowFocus); 5382 } 5383 } 5384 onDetachedFromWindow()5385 protected void onDetachedFromWindow() { 5386 if (mNext != null) { 5387 mNext.onDetachedFromWindow(); 5388 } 5389 } 5390 shouldDropInputEvent(QueuedInputEvent q)5391 protected boolean shouldDropInputEvent(QueuedInputEvent q) { 5392 if (mView == null || !mAdded) { 5393 Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent); 5394 return true; 5395 } else if ((!mAttachInfo.mHasWindowFocus 5396 && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER) 5397 && !isAutofillUiShowing()) || mStopped 5398 || (mIsAmbientMode && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON)) 5399 || (mPausedForTransition && !isBack(q.mEvent))) { 5400 // This is a focus event and the window doesn't currently have input focus or 5401 // has stopped. This could be an event that came back from the previous stage 5402 // but the window has lost focus or stopped in the meantime. 5403 if (isTerminalInputEvent(q.mEvent)) { 5404 // Don't drop terminal input events, however mark them as canceled. 5405 q.mEvent.cancel(); 5406 Slog.w(mTag, "Cancelling event due to no window focus: " + q.mEvent); 5407 return false; 5408 } 5409 5410 // Drop non-terminal input events. 5411 Slog.w(mTag, "Dropping event due to no window focus: " + q.mEvent); 5412 return true; 5413 } 5414 return false; 5415 } 5416 dump(String prefix, PrintWriter writer)5417 void dump(String prefix, PrintWriter writer) { 5418 if (mNext != null) { 5419 mNext.dump(prefix, writer); 5420 } 5421 } 5422 isBack(InputEvent event)5423 private boolean isBack(InputEvent event) { 5424 if (event instanceof KeyEvent) { 5425 return ((KeyEvent) event).getKeyCode() == KeyEvent.KEYCODE_BACK; 5426 } else { 5427 return false; 5428 } 5429 } 5430 traceEvent(QueuedInputEvent q, long traceTag)5431 private void traceEvent(QueuedInputEvent q, long traceTag) { 5432 if (!Trace.isTagEnabled(traceTag)) { 5433 return; 5434 } 5435 5436 if (mTracePrefix == null) { 5437 mTracePrefix = getClass().getSimpleName(); 5438 } 5439 Trace.traceBegin(traceTag, mTracePrefix + " id=0x" 5440 + Integer.toHexString(q.mEvent.getId())); 5441 } 5442 } 5443 5444 /** 5445 * Base class for implementing an input pipeline stage that supports 5446 * asynchronous and out-of-order processing of input events. 5447 * <p> 5448 * In addition to what a normal input stage can do, an asynchronous 5449 * input stage may also defer an input event that has been delivered to it 5450 * and finish or forward it later. 5451 * </p> 5452 */ 5453 abstract class AsyncInputStage extends InputStage { 5454 private final String mTraceCounter; 5455 5456 private QueuedInputEvent mQueueHead; 5457 private QueuedInputEvent mQueueTail; 5458 private int mQueueLength; 5459 5460 protected static final int DEFER = 3; 5461 5462 /** 5463 * Creates an asynchronous input stage. 5464 * @param next The next stage to which events should be forwarded. 5465 * @param traceCounter The name of a counter to record the size of 5466 * the queue of pending events. 5467 */ AsyncInputStage(InputStage next, String traceCounter)5468 public AsyncInputStage(InputStage next, String traceCounter) { 5469 super(next); 5470 mTraceCounter = traceCounter; 5471 } 5472 5473 /** 5474 * Marks the event as deferred, which is to say that it will be handled 5475 * asynchronously. The caller is responsible for calling {@link #forward} 5476 * or {@link #finish} later when it is done handling the event. 5477 */ defer(QueuedInputEvent q)5478 protected void defer(QueuedInputEvent q) { 5479 q.mFlags |= QueuedInputEvent.FLAG_DEFERRED; 5480 enqueue(q); 5481 } 5482 5483 @Override forward(QueuedInputEvent q)5484 protected void forward(QueuedInputEvent q) { 5485 // Clear the deferred flag. 5486 q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED; 5487 5488 // Fast path if the queue is empty. 5489 QueuedInputEvent curr = mQueueHead; 5490 if (curr == null) { 5491 super.forward(q); 5492 return; 5493 } 5494 5495 // Determine whether the event must be serialized behind any others 5496 // before it can be delivered to the next stage. This is done because 5497 // deferred events might be handled out of order by the stage. 5498 final int deviceId = q.mEvent.getDeviceId(); 5499 QueuedInputEvent prev = null; 5500 boolean blocked = false; 5501 while (curr != null && curr != q) { 5502 if (!blocked && deviceId == curr.mEvent.getDeviceId()) { 5503 blocked = true; 5504 } 5505 prev = curr; 5506 curr = curr.mNext; 5507 } 5508 5509 // If the event is blocked, then leave it in the queue to be delivered later. 5510 // Note that the event might not yet be in the queue if it was not previously 5511 // deferred so we will enqueue it if needed. 5512 if (blocked) { 5513 if (curr == null) { 5514 enqueue(q); 5515 } 5516 return; 5517 } 5518 5519 // The event is not blocked. Deliver it immediately. 5520 if (curr != null) { 5521 curr = curr.mNext; 5522 dequeue(q, prev); 5523 } 5524 super.forward(q); 5525 5526 // Dequeuing this event may have unblocked successors. Deliver them. 5527 while (curr != null) { 5528 if (deviceId == curr.mEvent.getDeviceId()) { 5529 if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) { 5530 break; 5531 } 5532 QueuedInputEvent next = curr.mNext; 5533 dequeue(curr, prev); 5534 super.forward(curr); 5535 curr = next; 5536 } else { 5537 prev = curr; 5538 curr = curr.mNext; 5539 } 5540 } 5541 } 5542 5543 @Override apply(QueuedInputEvent q, int result)5544 protected void apply(QueuedInputEvent q, int result) { 5545 if (result == DEFER) { 5546 defer(q); 5547 } else { 5548 super.apply(q, result); 5549 } 5550 } 5551 enqueue(QueuedInputEvent q)5552 private void enqueue(QueuedInputEvent q) { 5553 if (mQueueTail == null) { 5554 mQueueHead = q; 5555 mQueueTail = q; 5556 } else { 5557 mQueueTail.mNext = q; 5558 mQueueTail = q; 5559 } 5560 5561 mQueueLength += 1; 5562 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength); 5563 } 5564 dequeue(QueuedInputEvent q, QueuedInputEvent prev)5565 private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) { 5566 if (prev == null) { 5567 mQueueHead = q.mNext; 5568 } else { 5569 prev.mNext = q.mNext; 5570 } 5571 if (mQueueTail == q) { 5572 mQueueTail = prev; 5573 } 5574 q.mNext = null; 5575 5576 mQueueLength -= 1; 5577 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength); 5578 } 5579 5580 @Override dump(String prefix, PrintWriter writer)5581 void dump(String prefix, PrintWriter writer) { 5582 writer.print(prefix); 5583 writer.print(getClass().getName()); 5584 writer.print(": mQueueLength="); 5585 writer.println(mQueueLength); 5586 5587 super.dump(prefix, writer); 5588 } 5589 } 5590 5591 /** 5592 * Delivers pre-ime input events to a native activity. 5593 * Does not support pointer events. 5594 */ 5595 final class NativePreImeInputStage extends AsyncInputStage 5596 implements InputQueue.FinishedInputEventCallback { NativePreImeInputStage(InputStage next, String traceCounter)5597 public NativePreImeInputStage(InputStage next, String traceCounter) { 5598 super(next, traceCounter); 5599 } 5600 5601 @Override onProcess(QueuedInputEvent q)5602 protected int onProcess(QueuedInputEvent q) { 5603 if (mInputQueue != null && q.mEvent instanceof KeyEvent) { 5604 mInputQueue.sendInputEvent(q.mEvent, q, true, this); 5605 return DEFER; 5606 } 5607 return FORWARD; 5608 } 5609 5610 @Override onFinishedInputEvent(Object token, boolean handled)5611 public void onFinishedInputEvent(Object token, boolean handled) { 5612 QueuedInputEvent q = (QueuedInputEvent)token; 5613 if (handled) { 5614 finish(q, true); 5615 return; 5616 } 5617 forward(q); 5618 } 5619 } 5620 5621 /** 5622 * Delivers pre-ime input events to the view hierarchy. 5623 * Does not support pointer events. 5624 */ 5625 final class ViewPreImeInputStage extends InputStage { ViewPreImeInputStage(InputStage next)5626 public ViewPreImeInputStage(InputStage next) { 5627 super(next); 5628 } 5629 5630 @Override onProcess(QueuedInputEvent q)5631 protected int onProcess(QueuedInputEvent q) { 5632 if (q.mEvent instanceof KeyEvent) { 5633 return processKeyEvent(q); 5634 } 5635 return FORWARD; 5636 } 5637 processKeyEvent(QueuedInputEvent q)5638 private int processKeyEvent(QueuedInputEvent q) { 5639 final KeyEvent event = (KeyEvent)q.mEvent; 5640 if (mView.dispatchKeyEventPreIme(event)) { 5641 return FINISH_HANDLED; 5642 } 5643 return FORWARD; 5644 } 5645 } 5646 5647 /** 5648 * Delivers input events to the ime. 5649 * Does not support pointer events. 5650 */ 5651 final class ImeInputStage extends AsyncInputStage 5652 implements InputMethodManager.FinishedInputEventCallback { ImeInputStage(InputStage next, String traceCounter)5653 public ImeInputStage(InputStage next, String traceCounter) { 5654 super(next, traceCounter); 5655 } 5656 5657 @Override onProcess(QueuedInputEvent q)5658 protected int onProcess(QueuedInputEvent q) { 5659 final int result = mImeFocusController.onProcessImeInputStage( 5660 q, q.mEvent, mWindowAttributes, this); 5661 switch (result) { 5662 case InputMethodManager.DISPATCH_IN_PROGRESS: 5663 // callback will be invoked later 5664 return DEFER; 5665 case InputMethodManager.DISPATCH_NOT_HANDLED: 5666 // The IME could not handle it, so skip along to the next InputStage 5667 return FORWARD; 5668 case InputMethodManager.DISPATCH_HANDLED: 5669 return FINISH_HANDLED; 5670 default: 5671 throw new IllegalStateException("Unexpected result=" + result); 5672 } 5673 } 5674 5675 @Override onFinishedInputEvent(Object token, boolean handled)5676 public void onFinishedInputEvent(Object token, boolean handled) { 5677 QueuedInputEvent q = (QueuedInputEvent)token; 5678 if (handled) { 5679 finish(q, true); 5680 return; 5681 } 5682 forward(q); 5683 } 5684 } 5685 5686 /** 5687 * Performs early processing of post-ime input events. 5688 */ 5689 final class EarlyPostImeInputStage extends InputStage { EarlyPostImeInputStage(InputStage next)5690 public EarlyPostImeInputStage(InputStage next) { 5691 super(next); 5692 } 5693 5694 @Override onProcess(QueuedInputEvent q)5695 protected int onProcess(QueuedInputEvent q) { 5696 if (q.mEvent instanceof KeyEvent) { 5697 return processKeyEvent(q); 5698 } else if (q.mEvent instanceof MotionEvent) { 5699 return processMotionEvent(q); 5700 } 5701 return FORWARD; 5702 } 5703 processKeyEvent(QueuedInputEvent q)5704 private int processKeyEvent(QueuedInputEvent q) { 5705 final KeyEvent event = (KeyEvent)q.mEvent; 5706 5707 if (mAttachInfo.mTooltipHost != null) { 5708 mAttachInfo.mTooltipHost.handleTooltipKey(event); 5709 } 5710 5711 // If the key's purpose is to exit touch mode then we consume it 5712 // and consider it handled. 5713 if (checkForLeavingTouchModeAndConsume(event)) { 5714 return FINISH_HANDLED; 5715 } 5716 5717 // Make sure the fallback event policy sees all keys that will be 5718 // delivered to the view hierarchy. 5719 mFallbackEventHandler.preDispatchKeyEvent(event); 5720 return FORWARD; 5721 } 5722 processMotionEvent(QueuedInputEvent q)5723 private int processMotionEvent(QueuedInputEvent q) { 5724 final MotionEvent event = (MotionEvent) q.mEvent; 5725 5726 if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 5727 return processPointerEvent(q); 5728 } 5729 5730 // If the motion event is from an absolute position device, exit touch mode 5731 final int action = event.getActionMasked(); 5732 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) { 5733 if (event.isFromSource(InputDevice.SOURCE_CLASS_POSITION)) { 5734 ensureTouchMode(false); 5735 } 5736 } 5737 return FORWARD; 5738 } 5739 processPointerEvent(QueuedInputEvent q)5740 private int processPointerEvent(QueuedInputEvent q) { 5741 final MotionEvent event = (MotionEvent)q.mEvent; 5742 5743 // Translate the pointer event for compatibility, if needed. 5744 if (mTranslator != null) { 5745 mTranslator.translateEventInScreenToAppWindow(event); 5746 } 5747 5748 // Enter touch mode on down or scroll from any type of a device. 5749 final int action = event.getAction(); 5750 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) { 5751 ensureTouchMode(true); 5752 } 5753 5754 if (action == MotionEvent.ACTION_DOWN) { 5755 // Upon motion event within app window, close autofill ui. 5756 AutofillManager afm = getAutofillManager(); 5757 if (afm != null) { 5758 afm.requestHideFillUi(); 5759 } 5760 } 5761 5762 if (action == MotionEvent.ACTION_DOWN && mAttachInfo.mTooltipHost != null) { 5763 mAttachInfo.mTooltipHost.hideTooltip(); 5764 } 5765 5766 // Offset the scroll position. 5767 if (mCurScrollY != 0) { 5768 event.offsetLocation(0, mCurScrollY); 5769 } 5770 5771 // Remember the touch position for possible drag-initiation. 5772 if (event.isTouchEvent()) { 5773 mLastTouchPoint.x = event.getRawX(); 5774 mLastTouchPoint.y = event.getRawY(); 5775 mLastTouchSource = event.getSource(); 5776 } 5777 return FORWARD; 5778 } 5779 } 5780 5781 /** 5782 * Delivers post-ime input events to a native activity. 5783 */ 5784 final class NativePostImeInputStage extends AsyncInputStage 5785 implements InputQueue.FinishedInputEventCallback { NativePostImeInputStage(InputStage next, String traceCounter)5786 public NativePostImeInputStage(InputStage next, String traceCounter) { 5787 super(next, traceCounter); 5788 } 5789 5790 @Override onProcess(QueuedInputEvent q)5791 protected int onProcess(QueuedInputEvent q) { 5792 if (mInputQueue != null) { 5793 mInputQueue.sendInputEvent(q.mEvent, q, false, this); 5794 return DEFER; 5795 } 5796 return FORWARD; 5797 } 5798 5799 @Override onFinishedInputEvent(Object token, boolean handled)5800 public void onFinishedInputEvent(Object token, boolean handled) { 5801 QueuedInputEvent q = (QueuedInputEvent)token; 5802 if (handled) { 5803 finish(q, true); 5804 return; 5805 } 5806 forward(q); 5807 } 5808 } 5809 5810 /** 5811 * Delivers post-ime input events to the view hierarchy. 5812 */ 5813 final class ViewPostImeInputStage extends InputStage { ViewPostImeInputStage(InputStage next)5814 public ViewPostImeInputStage(InputStage next) { 5815 super(next); 5816 } 5817 5818 @Override onProcess(QueuedInputEvent q)5819 protected int onProcess(QueuedInputEvent q) { 5820 if (q.mEvent instanceof KeyEvent) { 5821 return processKeyEvent(q); 5822 } else { 5823 final int source = q.mEvent.getSource(); 5824 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 5825 return processPointerEvent(q); 5826 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { 5827 return processTrackballEvent(q); 5828 } else { 5829 return processGenericMotionEvent(q); 5830 } 5831 } 5832 } 5833 5834 @Override onDeliverToNext(QueuedInputEvent q)5835 protected void onDeliverToNext(QueuedInputEvent q) { 5836 if (mUnbufferedInputDispatch 5837 && q.mEvent instanceof MotionEvent 5838 && ((MotionEvent)q.mEvent).isTouchEvent() 5839 && isTerminalInputEvent(q.mEvent)) { 5840 mUnbufferedInputDispatch = false; 5841 scheduleConsumeBatchedInput(); 5842 } 5843 super.onDeliverToNext(q); 5844 } 5845 performFocusNavigation(KeyEvent event)5846 private boolean performFocusNavigation(KeyEvent event) { 5847 int direction = 0; 5848 switch (event.getKeyCode()) { 5849 case KeyEvent.KEYCODE_DPAD_LEFT: 5850 if (event.hasNoModifiers()) { 5851 direction = View.FOCUS_LEFT; 5852 } 5853 break; 5854 case KeyEvent.KEYCODE_DPAD_RIGHT: 5855 if (event.hasNoModifiers()) { 5856 direction = View.FOCUS_RIGHT; 5857 } 5858 break; 5859 case KeyEvent.KEYCODE_DPAD_UP: 5860 if (event.hasNoModifiers()) { 5861 direction = View.FOCUS_UP; 5862 } 5863 break; 5864 case KeyEvent.KEYCODE_DPAD_DOWN: 5865 if (event.hasNoModifiers()) { 5866 direction = View.FOCUS_DOWN; 5867 } 5868 break; 5869 case KeyEvent.KEYCODE_TAB: 5870 if (event.hasNoModifiers()) { 5871 direction = View.FOCUS_FORWARD; 5872 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) { 5873 direction = View.FOCUS_BACKWARD; 5874 } 5875 break; 5876 } 5877 if (direction != 0) { 5878 View focused = mView.findFocus(); 5879 if (focused != null) { 5880 View v = focused.focusSearch(direction); 5881 if (v != null && v != focused) { 5882 // do the math the get the interesting rect 5883 // of previous focused into the coord system of 5884 // newly focused view 5885 focused.getFocusedRect(mTempRect); 5886 if (mView instanceof ViewGroup) { 5887 ((ViewGroup) mView).offsetDescendantRectToMyCoords( 5888 focused, mTempRect); 5889 ((ViewGroup) mView).offsetRectIntoDescendantCoords( 5890 v, mTempRect); 5891 } 5892 if (v.requestFocus(direction, mTempRect)) { 5893 playSoundEffect(SoundEffectConstants 5894 .getContantForFocusDirection(direction)); 5895 return true; 5896 } 5897 } 5898 5899 // Give the focused view a last chance to handle the dpad key. 5900 if (mView.dispatchUnhandledMove(focused, direction)) { 5901 return true; 5902 } 5903 } else { 5904 if (mView.restoreDefaultFocus()) { 5905 return true; 5906 } 5907 } 5908 } 5909 return false; 5910 } 5911 performKeyboardGroupNavigation(int direction)5912 private boolean performKeyboardGroupNavigation(int direction) { 5913 final View focused = mView.findFocus(); 5914 if (focused == null && mView.restoreDefaultFocus()) { 5915 return true; 5916 } 5917 View cluster = focused == null ? keyboardNavigationClusterSearch(null, direction) 5918 : focused.keyboardNavigationClusterSearch(null, direction); 5919 5920 // Since requestFocus only takes "real" focus directions (and therefore also 5921 // restoreFocusInCluster), convert forward/backward focus into FOCUS_DOWN. 5922 int realDirection = direction; 5923 if (direction == View.FOCUS_FORWARD || direction == View.FOCUS_BACKWARD) { 5924 realDirection = View.FOCUS_DOWN; 5925 } 5926 5927 if (cluster != null && cluster.isRootNamespace()) { 5928 // the default cluster. Try to find a non-clustered view to focus. 5929 if (cluster.restoreFocusNotInCluster()) { 5930 playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction)); 5931 return true; 5932 } 5933 // otherwise skip to next actual cluster 5934 cluster = keyboardNavigationClusterSearch(null, direction); 5935 } 5936 5937 if (cluster != null && cluster.restoreFocusInCluster(realDirection)) { 5938 playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction)); 5939 return true; 5940 } 5941 5942 return false; 5943 } 5944 processKeyEvent(QueuedInputEvent q)5945 private int processKeyEvent(QueuedInputEvent q) { 5946 final KeyEvent event = (KeyEvent)q.mEvent; 5947 5948 if (mUnhandledKeyManager.preViewDispatch(event)) { 5949 return FINISH_HANDLED; 5950 } 5951 5952 // Deliver the key to the view hierarchy. 5953 if (mView.dispatchKeyEvent(event)) { 5954 return FINISH_HANDLED; 5955 } 5956 5957 if (shouldDropInputEvent(q)) { 5958 return FINISH_NOT_HANDLED; 5959 } 5960 5961 // This dispatch is for windows that don't have a Window.Callback. Otherwise, 5962 // the Window.Callback usually will have already called this (see 5963 // DecorView.superDispatchKeyEvent) leaving this call a no-op. 5964 if (mUnhandledKeyManager.dispatch(mView, event)) { 5965 return FINISH_HANDLED; 5966 } 5967 5968 int groupNavigationDirection = 0; 5969 5970 if (event.getAction() == KeyEvent.ACTION_DOWN 5971 && event.getKeyCode() == KeyEvent.KEYCODE_TAB) { 5972 if (KeyEvent.metaStateHasModifiers(event.getMetaState(), KeyEvent.META_META_ON)) { 5973 groupNavigationDirection = View.FOCUS_FORWARD; 5974 } else if (KeyEvent.metaStateHasModifiers(event.getMetaState(), 5975 KeyEvent.META_META_ON | KeyEvent.META_SHIFT_ON)) { 5976 groupNavigationDirection = View.FOCUS_BACKWARD; 5977 } 5978 } 5979 5980 // If a modifier is held, try to interpret the key as a shortcut. 5981 if (event.getAction() == KeyEvent.ACTION_DOWN 5982 && !KeyEvent.metaStateHasNoModifiers(event.getMetaState()) 5983 && event.getRepeatCount() == 0 5984 && !KeyEvent.isModifierKey(event.getKeyCode()) 5985 && groupNavigationDirection == 0) { 5986 if (mView.dispatchKeyShortcutEvent(event)) { 5987 return FINISH_HANDLED; 5988 } 5989 if (shouldDropInputEvent(q)) { 5990 return FINISH_NOT_HANDLED; 5991 } 5992 } 5993 5994 // Apply the fallback event policy. 5995 if (mFallbackEventHandler.dispatchKeyEvent(event)) { 5996 return FINISH_HANDLED; 5997 } 5998 if (shouldDropInputEvent(q)) { 5999 return FINISH_NOT_HANDLED; 6000 } 6001 6002 // Handle automatic focus changes. 6003 if (event.getAction() == KeyEvent.ACTION_DOWN) { 6004 if (groupNavigationDirection != 0) { 6005 if (performKeyboardGroupNavigation(groupNavigationDirection)) { 6006 return FINISH_HANDLED; 6007 } 6008 } else { 6009 if (performFocusNavigation(event)) { 6010 return FINISH_HANDLED; 6011 } 6012 } 6013 } 6014 return FORWARD; 6015 } 6016 processPointerEvent(QueuedInputEvent q)6017 private int processPointerEvent(QueuedInputEvent q) { 6018 final MotionEvent event = (MotionEvent)q.mEvent; 6019 6020 mAttachInfo.mUnbufferedDispatchRequested = false; 6021 mAttachInfo.mHandlingPointerEvent = true; 6022 boolean handled = mView.dispatchPointerEvent(event); 6023 maybeUpdatePointerIcon(event); 6024 maybeUpdateTooltip(event); 6025 mAttachInfo.mHandlingPointerEvent = false; 6026 if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) { 6027 mUnbufferedInputDispatch = true; 6028 if (mConsumeBatchedInputScheduled) { 6029 scheduleConsumeBatchedInputImmediately(); 6030 } 6031 } 6032 return handled ? FINISH_HANDLED : FORWARD; 6033 } 6034 maybeUpdatePointerIcon(MotionEvent event)6035 private void maybeUpdatePointerIcon(MotionEvent event) { 6036 if (event.getPointerCount() == 1 && event.isFromSource(InputDevice.SOURCE_MOUSE)) { 6037 if (event.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER 6038 || event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) { 6039 // Other apps or the window manager may change the icon type outside of 6040 // this app, therefore the icon type has to be reset on enter/exit event. 6041 mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED; 6042 } 6043 6044 if (event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT) { 6045 if (!updatePointerIcon(event) && 6046 event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) { 6047 mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED; 6048 } 6049 } 6050 } 6051 } 6052 processTrackballEvent(QueuedInputEvent q)6053 private int processTrackballEvent(QueuedInputEvent q) { 6054 final MotionEvent event = (MotionEvent)q.mEvent; 6055 6056 if (event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) { 6057 if (!hasPointerCapture() || mView.dispatchCapturedPointerEvent(event)) { 6058 return FINISH_HANDLED; 6059 } 6060 } 6061 6062 if (mView.dispatchTrackballEvent(event)) { 6063 return FINISH_HANDLED; 6064 } 6065 return FORWARD; 6066 } 6067 processGenericMotionEvent(QueuedInputEvent q)6068 private int processGenericMotionEvent(QueuedInputEvent q) { 6069 final MotionEvent event = (MotionEvent)q.mEvent; 6070 6071 if (event.isFromSource(InputDevice.SOURCE_TOUCHPAD)) { 6072 if (hasPointerCapture() && mView.dispatchCapturedPointerEvent(event)) { 6073 return FINISH_HANDLED; 6074 } 6075 } 6076 6077 // Deliver the event to the view. 6078 if (mView.dispatchGenericMotionEvent(event)) { 6079 return FINISH_HANDLED; 6080 } 6081 return FORWARD; 6082 } 6083 } 6084 resetPointerIcon(MotionEvent event)6085 private void resetPointerIcon(MotionEvent event) { 6086 mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED; 6087 updatePointerIcon(event); 6088 } 6089 updatePointerIcon(MotionEvent event)6090 private boolean updatePointerIcon(MotionEvent event) { 6091 final int pointerIndex = 0; 6092 final float x = event.getX(pointerIndex); 6093 final float y = event.getY(pointerIndex); 6094 if (mView == null) { 6095 // E.g. click outside a popup to dismiss it 6096 Slog.d(mTag, "updatePointerIcon called after view was removed"); 6097 return false; 6098 } 6099 if (x < 0 || x >= mView.getWidth() || y < 0 || y >= mView.getHeight()) { 6100 // E.g. when moving window divider with mouse 6101 Slog.d(mTag, "updatePointerIcon called with position out of bounds"); 6102 return false; 6103 } 6104 final PointerIcon pointerIcon = mView.onResolvePointerIcon(event, pointerIndex); 6105 final int pointerType = (pointerIcon != null) ? 6106 pointerIcon.getType() : PointerIcon.TYPE_DEFAULT; 6107 6108 if (mPointerIconType != pointerType) { 6109 mPointerIconType = pointerType; 6110 mCustomPointerIcon = null; 6111 if (mPointerIconType != PointerIcon.TYPE_CUSTOM) { 6112 InputManager.getInstance().setPointerIconType(pointerType); 6113 return true; 6114 } 6115 } 6116 if (mPointerIconType == PointerIcon.TYPE_CUSTOM && 6117 !pointerIcon.equals(mCustomPointerIcon)) { 6118 mCustomPointerIcon = pointerIcon; 6119 InputManager.getInstance().setCustomPointerIcon(mCustomPointerIcon); 6120 } 6121 return true; 6122 } 6123 maybeUpdateTooltip(MotionEvent event)6124 private void maybeUpdateTooltip(MotionEvent event) { 6125 if (event.getPointerCount() != 1) { 6126 return; 6127 } 6128 final int action = event.getActionMasked(); 6129 if (action != MotionEvent.ACTION_HOVER_ENTER 6130 && action != MotionEvent.ACTION_HOVER_MOVE 6131 && action != MotionEvent.ACTION_HOVER_EXIT) { 6132 return; 6133 } 6134 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 6135 if (manager.isEnabled() && manager.isTouchExplorationEnabled()) { 6136 return; 6137 } 6138 if (mView == null) { 6139 Slog.d(mTag, "maybeUpdateTooltip called after view was removed"); 6140 return; 6141 } 6142 mView.dispatchTooltipHoverEvent(event); 6143 } 6144 6145 /** 6146 * Performs synthesis of new input events from unhandled input events. 6147 */ 6148 final class SyntheticInputStage extends InputStage { 6149 private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler(); 6150 private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler(); 6151 private final SyntheticTouchNavigationHandler mTouchNavigation = 6152 new SyntheticTouchNavigationHandler(); 6153 private final SyntheticKeyboardHandler mKeyboard = new SyntheticKeyboardHandler(); 6154 SyntheticInputStage()6155 public SyntheticInputStage() { 6156 super(null); 6157 } 6158 6159 @Override onProcess(QueuedInputEvent q)6160 protected int onProcess(QueuedInputEvent q) { 6161 q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED; 6162 if (q.mEvent instanceof MotionEvent) { 6163 final MotionEvent event = (MotionEvent)q.mEvent; 6164 final int source = event.getSource(); 6165 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { 6166 mTrackball.process(event); 6167 return FINISH_HANDLED; 6168 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { 6169 mJoystick.process(event); 6170 return FINISH_HANDLED; 6171 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION) 6172 == InputDevice.SOURCE_TOUCH_NAVIGATION) { 6173 mTouchNavigation.process(event); 6174 return FINISH_HANDLED; 6175 } 6176 } else if ((q.mFlags & QueuedInputEvent.FLAG_UNHANDLED) != 0) { 6177 mKeyboard.process((KeyEvent)q.mEvent); 6178 return FINISH_HANDLED; 6179 } 6180 6181 return FORWARD; 6182 } 6183 6184 @Override onDeliverToNext(QueuedInputEvent q)6185 protected void onDeliverToNext(QueuedInputEvent q) { 6186 if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) { 6187 // Cancel related synthetic events if any prior stage has handled the event. 6188 if (q.mEvent instanceof MotionEvent) { 6189 final MotionEvent event = (MotionEvent)q.mEvent; 6190 final int source = event.getSource(); 6191 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { 6192 mTrackball.cancel(); 6193 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { 6194 mJoystick.cancel(); 6195 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION) 6196 == InputDevice.SOURCE_TOUCH_NAVIGATION) { 6197 mTouchNavigation.cancel(event); 6198 } 6199 } 6200 } 6201 super.onDeliverToNext(q); 6202 } 6203 6204 @Override onWindowFocusChanged(boolean hasWindowFocus)6205 protected void onWindowFocusChanged(boolean hasWindowFocus) { 6206 if (!hasWindowFocus) { 6207 mJoystick.cancel(); 6208 } 6209 } 6210 6211 @Override onDetachedFromWindow()6212 protected void onDetachedFromWindow() { 6213 mJoystick.cancel(); 6214 } 6215 } 6216 6217 /** 6218 * Creates dpad events from unhandled trackball movements. 6219 */ 6220 final class SyntheticTrackballHandler { 6221 private final TrackballAxis mX = new TrackballAxis(); 6222 private final TrackballAxis mY = new TrackballAxis(); 6223 private long mLastTime; 6224 process(MotionEvent event)6225 public void process(MotionEvent event) { 6226 // Translate the trackball event into DPAD keys and try to deliver those. 6227 long curTime = SystemClock.uptimeMillis(); 6228 if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) { 6229 // It has been too long since the last movement, 6230 // so restart at the beginning. 6231 mX.reset(0); 6232 mY.reset(0); 6233 mLastTime = curTime; 6234 } 6235 6236 final int action = event.getAction(); 6237 final int metaState = event.getMetaState(); 6238 switch (action) { 6239 case MotionEvent.ACTION_DOWN: 6240 mX.reset(2); 6241 mY.reset(2); 6242 enqueueInputEvent(new KeyEvent(curTime, curTime, 6243 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState, 6244 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, 6245 InputDevice.SOURCE_KEYBOARD)); 6246 break; 6247 case MotionEvent.ACTION_UP: 6248 mX.reset(2); 6249 mY.reset(2); 6250 enqueueInputEvent(new KeyEvent(curTime, curTime, 6251 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState, 6252 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, 6253 InputDevice.SOURCE_KEYBOARD)); 6254 break; 6255 } 6256 6257 if (DEBUG_TRACKBALL) Log.v(mTag, "TB X=" + mX.position + " step=" 6258 + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration 6259 + " move=" + event.getX() 6260 + " / Y=" + mY.position + " step=" 6261 + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration 6262 + " move=" + event.getY()); 6263 final float xOff = mX.collect(event.getX(), event.getEventTime(), "X"); 6264 final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y"); 6265 6266 // Generate DPAD events based on the trackball movement. 6267 // We pick the axis that has moved the most as the direction of 6268 // the DPAD. When we generate DPAD events for one axis, then the 6269 // other axis is reset -- we don't want to perform DPAD jumps due 6270 // to slight movements in the trackball when making major movements 6271 // along the other axis. 6272 int keycode = 0; 6273 int movement = 0; 6274 float accel = 1; 6275 if (xOff > yOff) { 6276 movement = mX.generate(); 6277 if (movement != 0) { 6278 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT 6279 : KeyEvent.KEYCODE_DPAD_LEFT; 6280 accel = mX.acceleration; 6281 mY.reset(2); 6282 } 6283 } else if (yOff > 0) { 6284 movement = mY.generate(); 6285 if (movement != 0) { 6286 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN 6287 : KeyEvent.KEYCODE_DPAD_UP; 6288 accel = mY.acceleration; 6289 mX.reset(2); 6290 } 6291 } 6292 6293 if (keycode != 0) { 6294 if (movement < 0) movement = -movement; 6295 int accelMovement = (int)(movement * accel); 6296 if (DEBUG_TRACKBALL) Log.v(mTag, "Move: movement=" + movement 6297 + " accelMovement=" + accelMovement 6298 + " accel=" + accel); 6299 if (accelMovement > movement) { 6300 if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: " 6301 + keycode); 6302 movement--; 6303 int repeatCount = accelMovement - movement; 6304 enqueueInputEvent(new KeyEvent(curTime, curTime, 6305 KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState, 6306 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, 6307 InputDevice.SOURCE_KEYBOARD)); 6308 } 6309 while (movement > 0) { 6310 if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: " 6311 + keycode); 6312 movement--; 6313 curTime = SystemClock.uptimeMillis(); 6314 enqueueInputEvent(new KeyEvent(curTime, curTime, 6315 KeyEvent.ACTION_DOWN, keycode, 0, metaState, 6316 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, 6317 InputDevice.SOURCE_KEYBOARD)); 6318 enqueueInputEvent(new KeyEvent(curTime, curTime, 6319 KeyEvent.ACTION_UP, keycode, 0, metaState, 6320 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, 6321 InputDevice.SOURCE_KEYBOARD)); 6322 } 6323 mLastTime = curTime; 6324 } 6325 } 6326 cancel()6327 public void cancel() { 6328 mLastTime = Integer.MIN_VALUE; 6329 6330 // If we reach this, we consumed a trackball event. 6331 // Because we will not translate the trackball event into a key event, 6332 // touch mode will not exit, so we exit touch mode here. 6333 if (mView != null && mAdded) { 6334 ensureTouchMode(false); 6335 } 6336 } 6337 } 6338 6339 /** 6340 * Maintains state information for a single trackball axis, generating 6341 * discrete (DPAD) movements based on raw trackball motion. 6342 */ 6343 static final class TrackballAxis { 6344 /** 6345 * The maximum amount of acceleration we will apply. 6346 */ 6347 static final float MAX_ACCELERATION = 20; 6348 6349 /** 6350 * The maximum amount of time (in milliseconds) between events in order 6351 * for us to consider the user to be doing fast trackball movements, 6352 * and thus apply an acceleration. 6353 */ 6354 static final long FAST_MOVE_TIME = 150; 6355 6356 /** 6357 * Scaling factor to the time (in milliseconds) between events to how 6358 * much to multiple/divide the current acceleration. When movement 6359 * is < FAST_MOVE_TIME this multiplies the acceleration; when > 6360 * FAST_MOVE_TIME it divides it. 6361 */ 6362 static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40); 6363 6364 static final float FIRST_MOVEMENT_THRESHOLD = 0.5f; 6365 static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f; 6366 static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f; 6367 6368 float position; 6369 float acceleration = 1; 6370 long lastMoveTime = 0; 6371 int step; 6372 int dir; 6373 int nonAccelMovement; 6374 reset(int _step)6375 void reset(int _step) { 6376 position = 0; 6377 acceleration = 1; 6378 lastMoveTime = 0; 6379 step = _step; 6380 dir = 0; 6381 } 6382 6383 /** 6384 * Add trackball movement into the state. If the direction of movement 6385 * has been reversed, the state is reset before adding the 6386 * movement (so that you don't have to compensate for any previously 6387 * collected movement before see the result of the movement in the 6388 * new direction). 6389 * 6390 * @return Returns the absolute value of the amount of movement 6391 * collected so far. 6392 */ collect(float off, long time, String axis)6393 float collect(float off, long time, String axis) { 6394 long normTime; 6395 if (off > 0) { 6396 normTime = (long)(off * FAST_MOVE_TIME); 6397 if (dir < 0) { 6398 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!"); 6399 position = 0; 6400 step = 0; 6401 acceleration = 1; 6402 lastMoveTime = 0; 6403 } 6404 dir = 1; 6405 } else if (off < 0) { 6406 normTime = (long)((-off) * FAST_MOVE_TIME); 6407 if (dir > 0) { 6408 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!"); 6409 position = 0; 6410 step = 0; 6411 acceleration = 1; 6412 lastMoveTime = 0; 6413 } 6414 dir = -1; 6415 } else { 6416 normTime = 0; 6417 } 6418 6419 // The number of milliseconds between each movement that is 6420 // considered "normal" and will not result in any acceleration 6421 // or deceleration, scaled by the offset we have here. 6422 if (normTime > 0) { 6423 long delta = time - lastMoveTime; 6424 lastMoveTime = time; 6425 float acc = acceleration; 6426 if (delta < normTime) { 6427 // The user is scrolling rapidly, so increase acceleration. 6428 float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR; 6429 if (scale > 1) acc *= scale; 6430 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off=" 6431 + off + " normTime=" + normTime + " delta=" + delta 6432 + " scale=" + scale + " acc=" + acc); 6433 acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION; 6434 } else { 6435 // The user is scrolling slowly, so decrease acceleration. 6436 float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR; 6437 if (scale > 1) acc /= scale; 6438 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off=" 6439 + off + " normTime=" + normTime + " delta=" + delta 6440 + " scale=" + scale + " acc=" + acc); 6441 acceleration = acc > 1 ? acc : 1; 6442 } 6443 } 6444 position += off; 6445 return Math.abs(position); 6446 } 6447 6448 /** 6449 * Generate the number of discrete movement events appropriate for 6450 * the currently collected trackball movement. 6451 * 6452 * @return Returns the number of discrete movements, either positive 6453 * or negative, or 0 if there is not enough trackball movement yet 6454 * for a discrete movement. 6455 */ generate()6456 int generate() { 6457 int movement = 0; 6458 nonAccelMovement = 0; 6459 do { 6460 final int dir = position >= 0 ? 1 : -1; 6461 switch (step) { 6462 // If we are going to execute the first step, then we want 6463 // to do this as soon as possible instead of waiting for 6464 // a full movement, in order to make things look responsive. 6465 case 0: 6466 if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) { 6467 return movement; 6468 } 6469 movement += dir; 6470 nonAccelMovement += dir; 6471 step = 1; 6472 break; 6473 // If we have generated the first movement, then we need 6474 // to wait for the second complete trackball motion before 6475 // generating the second discrete movement. 6476 case 1: 6477 if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) { 6478 return movement; 6479 } 6480 movement += dir; 6481 nonAccelMovement += dir; 6482 position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir; 6483 step = 2; 6484 break; 6485 // After the first two, we generate discrete movements 6486 // consistently with the trackball, applying an acceleration 6487 // if the trackball is moving quickly. This is a simple 6488 // acceleration on top of what we already compute based 6489 // on how quickly the wheel is being turned, to apply 6490 // a longer increasing acceleration to continuous movement 6491 // in one direction. 6492 default: 6493 if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) { 6494 return movement; 6495 } 6496 movement += dir; 6497 position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD; 6498 float acc = acceleration; 6499 acc *= 1.1f; 6500 acceleration = acc < MAX_ACCELERATION ? acc : acceleration; 6501 break; 6502 } 6503 } while (true); 6504 } 6505 } 6506 6507 /** 6508 * Creates dpad events from unhandled joystick movements. 6509 */ 6510 final class SyntheticJoystickHandler extends Handler { 6511 private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1; 6512 private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2; 6513 6514 private final JoystickAxesState mJoystickAxesState = new JoystickAxesState(); 6515 private final SparseArray<KeyEvent> mDeviceKeyEvents = new SparseArray<>(); 6516 6517 public SyntheticJoystickHandler() { 6518 super(true); 6519 } 6520 6521 @Override 6522 public void handleMessage(Message msg) { 6523 switch (msg.what) { 6524 case MSG_ENQUEUE_X_AXIS_KEY_REPEAT: 6525 case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: { 6526 if (mAttachInfo.mHasWindowFocus) { 6527 KeyEvent oldEvent = (KeyEvent) msg.obj; 6528 KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent, 6529 SystemClock.uptimeMillis(), oldEvent.getRepeatCount() + 1); 6530 enqueueInputEvent(e); 6531 Message m = obtainMessage(msg.what, e); 6532 m.setAsynchronous(true); 6533 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay()); 6534 } 6535 } break; 6536 } 6537 } 6538 6539 public void process(MotionEvent event) { 6540 switch(event.getActionMasked()) { 6541 case MotionEvent.ACTION_CANCEL: 6542 cancel(); 6543 break; 6544 case MotionEvent.ACTION_MOVE: 6545 update(event); 6546 break; 6547 default: 6548 Log.w(mTag, "Unexpected action: " + event.getActionMasked()); 6549 } 6550 } 6551 6552 private void cancel() { 6553 removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT); 6554 removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT); 6555 for (int i = 0; i < mDeviceKeyEvents.size(); i++) { 6556 final KeyEvent keyEvent = mDeviceKeyEvents.valueAt(i); 6557 if (keyEvent != null) { 6558 enqueueInputEvent(KeyEvent.changeTimeRepeat(keyEvent, 6559 SystemClock.uptimeMillis(), 0)); 6560 } 6561 } 6562 mDeviceKeyEvents.clear(); 6563 mJoystickAxesState.resetState(); 6564 } 6565 6566 private void update(MotionEvent event) { 6567 final int historySize = event.getHistorySize(); 6568 for (int h = 0; h < historySize; h++) { 6569 final long time = event.getHistoricalEventTime(h); 6570 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X, 6571 event.getHistoricalAxisValue(MotionEvent.AXIS_X, 0, h)); 6572 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y, 6573 event.getHistoricalAxisValue(MotionEvent.AXIS_Y, 0, h)); 6574 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X, 6575 event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_X, 0, h)); 6576 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y, 6577 event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_Y, 0, h)); 6578 } 6579 final long time = event.getEventTime(); 6580 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X, 6581 event.getAxisValue(MotionEvent.AXIS_X)); 6582 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y, 6583 event.getAxisValue(MotionEvent.AXIS_Y)); 6584 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X, 6585 event.getAxisValue(MotionEvent.AXIS_HAT_X)); 6586 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y, 6587 event.getAxisValue(MotionEvent.AXIS_HAT_Y)); 6588 } 6589 6590 final class JoystickAxesState { 6591 // State machine: from neutral state (no button press) can go into 6592 // button STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state, emitting an ACTION_DOWN event. 6593 // From STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state can go into neutral state, 6594 // emitting an ACTION_UP event. 6595 private static final int STATE_UP_OR_LEFT = -1; 6596 private static final int STATE_NEUTRAL = 0; 6597 private static final int STATE_DOWN_OR_RIGHT = 1; 6598 6599 final int[] mAxisStatesHat = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_HAT_X, AXIS_HAT_Y} 6600 final int[] mAxisStatesStick = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_X, AXIS_Y} 6601 6602 void resetState() { 6603 mAxisStatesHat[0] = STATE_NEUTRAL; 6604 mAxisStatesHat[1] = STATE_NEUTRAL; 6605 mAxisStatesStick[0] = STATE_NEUTRAL; 6606 mAxisStatesStick[1] = STATE_NEUTRAL; 6607 } 6608 6609 void updateStateForAxis(MotionEvent event, long time, int axis, float value) { 6610 // Emit KeyEvent if necessary 6611 // axis can be AXIS_X, AXIS_Y, AXIS_HAT_X, AXIS_HAT_Y 6612 final int axisStateIndex; 6613 final int repeatMessage; 6614 if (isXAxis(axis)) { 6615 axisStateIndex = 0; 6616 repeatMessage = MSG_ENQUEUE_X_AXIS_KEY_REPEAT; 6617 } else if (isYAxis(axis)) { 6618 axisStateIndex = 1; 6619 repeatMessage = MSG_ENQUEUE_Y_AXIS_KEY_REPEAT; 6620 } else { 6621 Log.e(mTag, "Unexpected axis " + axis + " in updateStateForAxis!"); 6622 return; 6623 } 6624 final int newState = joystickAxisValueToState(value); 6625 6626 final int currentState; 6627 if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) { 6628 currentState = mAxisStatesStick[axisStateIndex]; 6629 } else { 6630 currentState = mAxisStatesHat[axisStateIndex]; 6631 } 6632 6633 if (currentState == newState) { 6634 return; 6635 } 6636 6637 final int metaState = event.getMetaState(); 6638 final int deviceId = event.getDeviceId(); 6639 final int source = event.getSource(); 6640 6641 if (currentState == STATE_DOWN_OR_RIGHT || currentState == STATE_UP_OR_LEFT) { 6642 // send a button release event 6643 final int keyCode = joystickAxisAndStateToKeycode(axis, currentState); 6644 if (keyCode != KeyEvent.KEYCODE_UNKNOWN) { 6645 enqueueInputEvent(new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode, 6646 0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source)); 6647 // remove the corresponding pending UP event if focus lost/view detached 6648 mDeviceKeyEvents.put(deviceId, null); 6649 } 6650 removeMessages(repeatMessage); 6651 } 6652 6653 if (newState == STATE_DOWN_OR_RIGHT || newState == STATE_UP_OR_LEFT) { 6654 // send a button down event 6655 final int keyCode = joystickAxisAndStateToKeycode(axis, newState); 6656 if (keyCode != KeyEvent.KEYCODE_UNKNOWN) { 6657 KeyEvent keyEvent = new KeyEvent(time, time, KeyEvent.ACTION_DOWN, keyCode, 6658 0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source); 6659 enqueueInputEvent(keyEvent); 6660 Message m = obtainMessage(repeatMessage, keyEvent); 6661 m.setAsynchronous(true); 6662 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout()); 6663 // store the corresponding ACTION_UP event so that it can be sent 6664 // if focus is lost or root view is removed 6665 mDeviceKeyEvents.put(deviceId, 6666 new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode, 6667 0, metaState, deviceId, 0, 6668 KeyEvent.FLAG_FALLBACK | KeyEvent.FLAG_CANCELED, 6669 source)); 6670 } 6671 } 6672 if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) { 6673 mAxisStatesStick[axisStateIndex] = newState; 6674 } else { 6675 mAxisStatesHat[axisStateIndex] = newState; 6676 } 6677 } 6678 6679 private boolean isXAxis(int axis) { 6680 return axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_HAT_X; 6681 } 6682 private boolean isYAxis(int axis) { 6683 return axis == MotionEvent.AXIS_Y || axis == MotionEvent.AXIS_HAT_Y; 6684 } 6685 6686 private int joystickAxisAndStateToKeycode(int axis, int state) { 6687 if (isXAxis(axis) && state == STATE_UP_OR_LEFT) { 6688 return KeyEvent.KEYCODE_DPAD_LEFT; 6689 } 6690 if (isXAxis(axis) && state == STATE_DOWN_OR_RIGHT) { 6691 return KeyEvent.KEYCODE_DPAD_RIGHT; 6692 } 6693 if (isYAxis(axis) && state == STATE_UP_OR_LEFT) { 6694 return KeyEvent.KEYCODE_DPAD_UP; 6695 } 6696 if (isYAxis(axis) && state == STATE_DOWN_OR_RIGHT) { 6697 return KeyEvent.KEYCODE_DPAD_DOWN; 6698 } 6699 Log.e(mTag, "Unknown axis " + axis + " or direction " + state); 6700 return KeyEvent.KEYCODE_UNKNOWN; // should never happen 6701 } 6702 6703 private int joystickAxisValueToState(float value) { 6704 if (value >= 0.5f) { 6705 return STATE_DOWN_OR_RIGHT; 6706 } else if (value <= -0.5f) { 6707 return STATE_UP_OR_LEFT; 6708 } else { 6709 return STATE_NEUTRAL; 6710 } 6711 } 6712 } 6713 } 6714 6715 /** 6716 * Creates dpad events from unhandled touch navigation movements. 6717 */ 6718 final class SyntheticTouchNavigationHandler extends Handler { 6719 private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler"; 6720 private static final boolean LOCAL_DEBUG = false; 6721 6722 // Assumed nominal width and height in millimeters of a touch navigation pad, 6723 // if no resolution information is available from the input system. 6724 private static final float DEFAULT_WIDTH_MILLIMETERS = 48; 6725 private static final float DEFAULT_HEIGHT_MILLIMETERS = 48; 6726 6727 /* TODO: These constants should eventually be moved to ViewConfiguration. */ 6728 6729 // The nominal distance traveled to move by one unit. 6730 private static final int TICK_DISTANCE_MILLIMETERS = 12; 6731 6732 // Minimum and maximum fling velocity in ticks per second. 6733 // The minimum velocity should be set such that we perform enough ticks per 6734 // second that the fling appears to be fluid. For example, if we set the minimum 6735 // to 2 ticks per second, then there may be up to half a second delay between the next 6736 // to last and last ticks which is noticeably discrete and jerky. This value should 6737 // probably not be set to anything less than about 4. 6738 // If fling accuracy is a problem then consider tuning the tick distance instead. 6739 private static final float MIN_FLING_VELOCITY_TICKS_PER_SECOND = 6f; 6740 private static final float MAX_FLING_VELOCITY_TICKS_PER_SECOND = 20f; 6741 6742 // Fling velocity decay factor applied after each new key is emitted. 6743 // This parameter controls the deceleration and overall duration of the fling. 6744 // The fling stops automatically when its velocity drops below the minimum 6745 // fling velocity defined above. 6746 private static final float FLING_TICK_DECAY = 0.8f; 6747 6748 /* The input device that we are tracking. */ 6749 6750 private int mCurrentDeviceId = -1; 6751 private int mCurrentSource; 6752 private boolean mCurrentDeviceSupported; 6753 6754 /* Configuration for the current input device. */ 6755 6756 // The scaled tick distance. A movement of this amount should generally translate 6757 // into a single dpad event in a given direction. 6758 private float mConfigTickDistance; 6759 6760 // The minimum and maximum scaled fling velocity. 6761 private float mConfigMinFlingVelocity; 6762 private float mConfigMaxFlingVelocity; 6763 6764 /* Tracking state. */ 6765 6766 // The velocity tracker for detecting flings. 6767 private VelocityTracker mVelocityTracker; 6768 6769 // The active pointer id, or -1 if none. 6770 private int mActivePointerId = -1; 6771 6772 // Location where tracking started. 6773 private float mStartX; 6774 private float mStartY; 6775 6776 // Most recently observed position. 6777 private float mLastX; 6778 private float mLastY; 6779 6780 // Accumulated movement delta since the last direction key was sent. 6781 private float mAccumulatedX; 6782 private float mAccumulatedY; 6783 6784 // Set to true if any movement was delivered to the app. 6785 // Implies that tap slop was exceeded. 6786 private boolean mConsumedMovement; 6787 6788 // The most recently sent key down event. 6789 // The keycode remains set until the direction changes or a fling ends 6790 // so that repeated key events may be generated as required. 6791 private long mPendingKeyDownTime; 6792 private int mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN; 6793 private int mPendingKeyRepeatCount; 6794 private int mPendingKeyMetaState; 6795 6796 // The current fling velocity while a fling is in progress. 6797 private boolean mFlinging; 6798 private float mFlingVelocity; 6799 6800 public SyntheticTouchNavigationHandler() { 6801 super(true); 6802 } 6803 6804 public void process(MotionEvent event) { 6805 // Update the current device information. 6806 final long time = event.getEventTime(); 6807 final int deviceId = event.getDeviceId(); 6808 final int source = event.getSource(); 6809 if (mCurrentDeviceId != deviceId || mCurrentSource != source) { 6810 finishKeys(time); 6811 finishTracking(time); 6812 mCurrentDeviceId = deviceId; 6813 mCurrentSource = source; 6814 mCurrentDeviceSupported = false; 6815 InputDevice device = event.getDevice(); 6816 if (device != null) { 6817 // In order to support an input device, we must know certain 6818 // characteristics about it, such as its size and resolution. 6819 InputDevice.MotionRange xRange = device.getMotionRange(MotionEvent.AXIS_X); 6820 InputDevice.MotionRange yRange = device.getMotionRange(MotionEvent.AXIS_Y); 6821 if (xRange != null && yRange != null) { 6822 mCurrentDeviceSupported = true; 6823 6824 // Infer the resolution if it not actually known. 6825 float xRes = xRange.getResolution(); 6826 if (xRes <= 0) { 6827 xRes = xRange.getRange() / DEFAULT_WIDTH_MILLIMETERS; 6828 } 6829 float yRes = yRange.getResolution(); 6830 if (yRes <= 0) { 6831 yRes = yRange.getRange() / DEFAULT_HEIGHT_MILLIMETERS; 6832 } 6833 float nominalRes = (xRes + yRes) * 0.5f; 6834 6835 // Precompute all of the configuration thresholds we will need. 6836 mConfigTickDistance = TICK_DISTANCE_MILLIMETERS * nominalRes; 6837 mConfigMinFlingVelocity = 6838 MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance; 6839 mConfigMaxFlingVelocity = 6840 MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance; 6841 6842 if (LOCAL_DEBUG) { 6843 Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId 6844 + " (" + Integer.toHexString(mCurrentSource) + "): " 6845 + ", mConfigTickDistance=" + mConfigTickDistance 6846 + ", mConfigMinFlingVelocity=" + mConfigMinFlingVelocity 6847 + ", mConfigMaxFlingVelocity=" + mConfigMaxFlingVelocity); 6848 } 6849 } 6850 } 6851 } 6852 if (!mCurrentDeviceSupported) { 6853 return; 6854 } 6855 6856 // Handle the event. 6857 final int action = event.getActionMasked(); 6858 switch (action) { 6859 case MotionEvent.ACTION_DOWN: { 6860 boolean caughtFling = mFlinging; 6861 finishKeys(time); 6862 finishTracking(time); 6863 mActivePointerId = event.getPointerId(0); 6864 mVelocityTracker = VelocityTracker.obtain(); 6865 mVelocityTracker.addMovement(event); 6866 mStartX = event.getX(); 6867 mStartY = event.getY(); 6868 mLastX = mStartX; 6869 mLastY = mStartY; 6870 mAccumulatedX = 0; 6871 mAccumulatedY = 0; 6872 6873 // If we caught a fling, then pretend that the tap slop has already 6874 // been exceeded to suppress taps whose only purpose is to stop the fling. 6875 mConsumedMovement = caughtFling; 6876 break; 6877 } 6878 6879 case MotionEvent.ACTION_MOVE: 6880 case MotionEvent.ACTION_UP: { 6881 if (mActivePointerId < 0) { 6882 break; 6883 } 6884 final int index = event.findPointerIndex(mActivePointerId); 6885 if (index < 0) { 6886 finishKeys(time); 6887 finishTracking(time); 6888 break; 6889 } 6890 6891 mVelocityTracker.addMovement(event); 6892 final float x = event.getX(index); 6893 final float y = event.getY(index); 6894 mAccumulatedX += x - mLastX; 6895 mAccumulatedY += y - mLastY; 6896 mLastX = x; 6897 mLastY = y; 6898 6899 // Consume any accumulated movement so far. 6900 final int metaState = event.getMetaState(); 6901 consumeAccumulatedMovement(time, metaState); 6902 6903 // Detect taps and flings. 6904 if (action == MotionEvent.ACTION_UP) { 6905 if (mConsumedMovement && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) { 6906 // It might be a fling. 6907 mVelocityTracker.computeCurrentVelocity(1000, mConfigMaxFlingVelocity); 6908 final float vx = mVelocityTracker.getXVelocity(mActivePointerId); 6909 final float vy = mVelocityTracker.getYVelocity(mActivePointerId); 6910 if (!startFling(time, vx, vy)) { 6911 finishKeys(time); 6912 } 6913 } 6914 finishTracking(time); 6915 } 6916 break; 6917 } 6918 6919 case MotionEvent.ACTION_CANCEL: { 6920 finishKeys(time); 6921 finishTracking(time); 6922 break; 6923 } 6924 } 6925 } 6926 6927 public void cancel(MotionEvent event) { 6928 if (mCurrentDeviceId == event.getDeviceId() 6929 && mCurrentSource == event.getSource()) { 6930 final long time = event.getEventTime(); 6931 finishKeys(time); 6932 finishTracking(time); 6933 } 6934 } 6935 6936 private void finishKeys(long time) { 6937 cancelFling(); 6938 sendKeyUp(time); 6939 } 6940 6941 private void finishTracking(long time) { 6942 if (mActivePointerId >= 0) { 6943 mActivePointerId = -1; 6944 mVelocityTracker.recycle(); 6945 mVelocityTracker = null; 6946 } 6947 } 6948 6949 private void consumeAccumulatedMovement(long time, int metaState) { 6950 final float absX = Math.abs(mAccumulatedX); 6951 final float absY = Math.abs(mAccumulatedY); 6952 if (absX >= absY) { 6953 if (absX >= mConfigTickDistance) { 6954 mAccumulatedX = consumeAccumulatedMovement(time, metaState, mAccumulatedX, 6955 KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT); 6956 mAccumulatedY = 0; 6957 mConsumedMovement = true; 6958 } 6959 } else { 6960 if (absY >= mConfigTickDistance) { 6961 mAccumulatedY = consumeAccumulatedMovement(time, metaState, mAccumulatedY, 6962 KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN); 6963 mAccumulatedX = 0; 6964 mConsumedMovement = true; 6965 } 6966 } 6967 } 6968 6969 private float consumeAccumulatedMovement(long time, int metaState, 6970 float accumulator, int negativeKeyCode, int positiveKeyCode) { 6971 while (accumulator <= -mConfigTickDistance) { 6972 sendKeyDownOrRepeat(time, negativeKeyCode, metaState); 6973 accumulator += mConfigTickDistance; 6974 } 6975 while (accumulator >= mConfigTickDistance) { 6976 sendKeyDownOrRepeat(time, positiveKeyCode, metaState); 6977 accumulator -= mConfigTickDistance; 6978 } 6979 return accumulator; 6980 } 6981 6982 private void sendKeyDownOrRepeat(long time, int keyCode, int metaState) { 6983 if (mPendingKeyCode != keyCode) { 6984 sendKeyUp(time); 6985 mPendingKeyDownTime = time; 6986 mPendingKeyCode = keyCode; 6987 mPendingKeyRepeatCount = 0; 6988 } else { 6989 mPendingKeyRepeatCount += 1; 6990 } 6991 mPendingKeyMetaState = metaState; 6992 6993 // Note: Normally we would pass FLAG_LONG_PRESS when the repeat count is 1 6994 // but it doesn't quite make sense when simulating the events in this way. 6995 if (LOCAL_DEBUG) { 6996 Log.d(LOCAL_TAG, "Sending key down: keyCode=" + mPendingKeyCode 6997 + ", repeatCount=" + mPendingKeyRepeatCount 6998 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState)); 6999 } 7000 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time, 7001 KeyEvent.ACTION_DOWN, mPendingKeyCode, mPendingKeyRepeatCount, 7002 mPendingKeyMetaState, mCurrentDeviceId, 7003 KeyEvent.FLAG_FALLBACK, mCurrentSource)); 7004 } 7005 7006 private void sendKeyUp(long time) { 7007 if (mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) { 7008 if (LOCAL_DEBUG) { 7009 Log.d(LOCAL_TAG, "Sending key up: keyCode=" + mPendingKeyCode 7010 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState)); 7011 } 7012 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time, 7013 KeyEvent.ACTION_UP, mPendingKeyCode, 0, mPendingKeyMetaState, 7014 mCurrentDeviceId, 0, KeyEvent.FLAG_FALLBACK, 7015 mCurrentSource)); 7016 mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN; 7017 } 7018 } 7019 7020 private boolean startFling(long time, float vx, float vy) { 7021 if (LOCAL_DEBUG) { 7022 Log.d(LOCAL_TAG, "Considering fling: vx=" + vx + ", vy=" + vy 7023 + ", min=" + mConfigMinFlingVelocity); 7024 } 7025 7026 // Flings must be oriented in the same direction as the preceding movements. 7027 switch (mPendingKeyCode) { 7028 case KeyEvent.KEYCODE_DPAD_LEFT: 7029 if (-vx >= mConfigMinFlingVelocity 7030 && Math.abs(vy) < mConfigMinFlingVelocity) { 7031 mFlingVelocity = -vx; 7032 break; 7033 } 7034 return false; 7035 7036 case KeyEvent.KEYCODE_DPAD_RIGHT: 7037 if (vx >= mConfigMinFlingVelocity 7038 && Math.abs(vy) < mConfigMinFlingVelocity) { 7039 mFlingVelocity = vx; 7040 break; 7041 } 7042 return false; 7043 7044 case KeyEvent.KEYCODE_DPAD_UP: 7045 if (-vy >= mConfigMinFlingVelocity 7046 && Math.abs(vx) < mConfigMinFlingVelocity) { 7047 mFlingVelocity = -vy; 7048 break; 7049 } 7050 return false; 7051 7052 case KeyEvent.KEYCODE_DPAD_DOWN: 7053 if (vy >= mConfigMinFlingVelocity 7054 && Math.abs(vx) < mConfigMinFlingVelocity) { 7055 mFlingVelocity = vy; 7056 break; 7057 } 7058 return false; 7059 } 7060 7061 // Post the first fling event. 7062 mFlinging = postFling(time); 7063 return mFlinging; 7064 } 7065 7066 private boolean postFling(long time) { 7067 // The idea here is to estimate the time when the pointer would have 7068 // traveled one tick distance unit given the current fling velocity. 7069 // This effect creates continuity of motion. 7070 if (mFlingVelocity >= mConfigMinFlingVelocity) { 7071 long delay = (long)(mConfigTickDistance / mFlingVelocity * 1000); 7072 postAtTime(mFlingRunnable, time + delay); 7073 if (LOCAL_DEBUG) { 7074 Log.d(LOCAL_TAG, "Posted fling: velocity=" 7075 + mFlingVelocity + ", delay=" + delay 7076 + ", keyCode=" + mPendingKeyCode); 7077 } 7078 return true; 7079 } 7080 return false; 7081 } 7082 7083 private void cancelFling() { 7084 if (mFlinging) { 7085 removeCallbacks(mFlingRunnable); 7086 mFlinging = false; 7087 } 7088 } 7089 7090 private final Runnable mFlingRunnable = new Runnable() { 7091 @Override 7092 public void run() { 7093 final long time = SystemClock.uptimeMillis(); 7094 sendKeyDownOrRepeat(time, mPendingKeyCode, mPendingKeyMetaState); 7095 mFlingVelocity *= FLING_TICK_DECAY; 7096 if (!postFling(time)) { 7097 mFlinging = false; 7098 finishKeys(time); 7099 } 7100 } 7101 }; 7102 } 7103 7104 final class SyntheticKeyboardHandler { 7105 public void process(KeyEvent event) { 7106 if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) { 7107 return; 7108 } 7109 7110 final KeyCharacterMap kcm = event.getKeyCharacterMap(); 7111 final int keyCode = event.getKeyCode(); 7112 final int metaState = event.getMetaState(); 7113 7114 // Check for fallback actions specified by the key character map. 7115 KeyCharacterMap.FallbackAction fallbackAction = 7116 kcm.getFallbackAction(keyCode, metaState); 7117 if (fallbackAction != null) { 7118 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK; 7119 KeyEvent fallbackEvent = KeyEvent.obtain( 7120 event.getDownTime(), event.getEventTime(), 7121 event.getAction(), fallbackAction.keyCode, 7122 event.getRepeatCount(), fallbackAction.metaState, 7123 event.getDeviceId(), event.getScanCode(), 7124 flags, event.getSource(), null); 7125 fallbackAction.recycle(); 7126 enqueueInputEvent(fallbackEvent); 7127 } 7128 } 7129 } 7130 7131 /** 7132 * Returns true if the key is used for keyboard navigation. 7133 * @param keyEvent The key event. 7134 * @return True if the key is used for keyboard navigation. 7135 */ 7136 private static boolean isNavigationKey(KeyEvent keyEvent) { 7137 switch (keyEvent.getKeyCode()) { 7138 case KeyEvent.KEYCODE_DPAD_LEFT: 7139 case KeyEvent.KEYCODE_DPAD_RIGHT: 7140 case KeyEvent.KEYCODE_DPAD_UP: 7141 case KeyEvent.KEYCODE_DPAD_DOWN: 7142 case KeyEvent.KEYCODE_DPAD_CENTER: 7143 case KeyEvent.KEYCODE_PAGE_UP: 7144 case KeyEvent.KEYCODE_PAGE_DOWN: 7145 case KeyEvent.KEYCODE_MOVE_HOME: 7146 case KeyEvent.KEYCODE_MOVE_END: 7147 case KeyEvent.KEYCODE_TAB: 7148 case KeyEvent.KEYCODE_SPACE: 7149 case KeyEvent.KEYCODE_ENTER: 7150 return true; 7151 } 7152 return false; 7153 } 7154 7155 /** 7156 * Returns true if the key is used for typing. 7157 * @param keyEvent The key event. 7158 * @return True if the key is used for typing. 7159 */ 7160 private static boolean isTypingKey(KeyEvent keyEvent) { 7161 return keyEvent.getUnicodeChar() > 0; 7162 } 7163 7164 /** 7165 * See if the key event means we should leave touch mode (and leave touch mode if so). 7166 * @param event The key event. 7167 * @return Whether this key event should be consumed (meaning the act of 7168 * leaving touch mode alone is considered the event). 7169 */ 7170 private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) { 7171 // Only relevant in touch mode. 7172 if (!mAttachInfo.mInTouchMode) { 7173 return false; 7174 } 7175 7176 // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP. 7177 final int action = event.getAction(); 7178 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) { 7179 return false; 7180 } 7181 7182 // Don't leave touch mode if the IME told us not to. 7183 if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) { 7184 return false; 7185 } 7186 7187 // If the key can be used for keyboard navigation then leave touch mode 7188 // and select a focused view if needed (in ensureTouchMode). 7189 // When a new focused view is selected, we consume the navigation key because 7190 // navigation doesn't make much sense unless a view already has focus so 7191 // the key's purpose is to set focus. 7192 if (isNavigationKey(event)) { 7193 return ensureTouchMode(false); 7194 } 7195 7196 // If the key can be used for typing then leave touch mode 7197 // and select a focused view if needed (in ensureTouchMode). 7198 // Always allow the view to process the typing key. 7199 if (isTypingKey(event)) { 7200 ensureTouchMode(false); 7201 return false; 7202 } 7203 7204 return false; 7205 } 7206 7207 /* drag/drop */ 7208 @UnsupportedAppUsage 7209 void setLocalDragState(Object obj) { 7210 mLocalDragState = obj; 7211 } 7212 7213 private void handleDragEvent(DragEvent event) { 7214 // From the root, only drag start/end/location are dispatched. entered/exited 7215 // are determined and dispatched by the viewgroup hierarchy, who then report 7216 // that back here for ultimate reporting back to the framework. 7217 if (mView != null && mAdded) { 7218 final int what = event.mAction; 7219 7220 // Cache the drag description when the operation starts, then fill it in 7221 // on subsequent calls as a convenience 7222 if (what == DragEvent.ACTION_DRAG_STARTED) { 7223 mCurrentDragView = null; // Start the current-recipient tracking 7224 mDragDescription = event.mClipDescription; 7225 } else { 7226 if (what == DragEvent.ACTION_DRAG_ENDED) { 7227 mDragDescription = null; 7228 } 7229 event.mClipDescription = mDragDescription; 7230 } 7231 7232 if (what == DragEvent.ACTION_DRAG_EXITED) { 7233 // A direct EXITED event means that the window manager knows we've just crossed 7234 // a window boundary, so the current drag target within this one must have 7235 // just been exited. Send the EXITED notification to the current drag view, if any. 7236 if (View.sCascadedDragDrop) { 7237 mView.dispatchDragEnterExitInPreN(event); 7238 } 7239 setDragFocus(null, event); 7240 } else { 7241 // For events with a [screen] location, translate into window coordinates 7242 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) { 7243 mDragPoint.set(event.mX, event.mY); 7244 if (mTranslator != null) { 7245 mTranslator.translatePointInScreenToAppWindow(mDragPoint); 7246 } 7247 7248 if (mCurScrollY != 0) { 7249 mDragPoint.offset(0, mCurScrollY); 7250 } 7251 7252 event.mX = mDragPoint.x; 7253 event.mY = mDragPoint.y; 7254 } 7255 7256 // Remember who the current drag target is pre-dispatch 7257 final View prevDragView = mCurrentDragView; 7258 7259 if (what == DragEvent.ACTION_DROP && event.mClipData != null) { 7260 event.mClipData.prepareToEnterProcess(); 7261 } 7262 7263 // Now dispatch the drag/drop event 7264 boolean result = mView.dispatchDragEvent(event); 7265 7266 if (what == DragEvent.ACTION_DRAG_LOCATION && !event.mEventHandlerWasCalled) { 7267 // If the LOCATION event wasn't delivered to any handler, no view now has a drag 7268 // focus. 7269 setDragFocus(null, event); 7270 } 7271 7272 // If we changed apparent drag target, tell the OS about it 7273 if (prevDragView != mCurrentDragView) { 7274 try { 7275 if (prevDragView != null) { 7276 mWindowSession.dragRecipientExited(mWindow); 7277 } 7278 if (mCurrentDragView != null) { 7279 mWindowSession.dragRecipientEntered(mWindow); 7280 } 7281 } catch (RemoteException e) { 7282 Slog.e(mTag, "Unable to note drag target change"); 7283 } 7284 } 7285 7286 // Report the drop result when we're done 7287 if (what == DragEvent.ACTION_DROP) { 7288 try { 7289 Log.i(mTag, "Reporting drop result: " + result); 7290 mWindowSession.reportDropResult(mWindow, result); 7291 } catch (RemoteException e) { 7292 Log.e(mTag, "Unable to report drop result"); 7293 } 7294 } 7295 7296 // When the drag operation ends, reset drag-related state 7297 if (what == DragEvent.ACTION_DRAG_ENDED) { 7298 mCurrentDragView = null; 7299 setLocalDragState(null); 7300 mAttachInfo.mDragToken = null; 7301 if (mAttachInfo.mDragSurface != null) { 7302 mAttachInfo.mDragSurface.release(); 7303 mAttachInfo.mDragSurface = null; 7304 } 7305 } 7306 } 7307 } 7308 event.recycle(); 7309 } 7310 7311 /** 7312 * Notify that the window title changed 7313 */ 7314 public void onWindowTitleChanged() { 7315 mAttachInfo.mForceReportNewAttributes = true; 7316 } 7317 7318 public void handleDispatchWindowShown() { 7319 mAttachInfo.mTreeObserver.dispatchOnWindowShown(); 7320 } 7321 7322 public void handleRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) { 7323 Bundle data = new Bundle(); 7324 ArrayList<KeyboardShortcutGroup> list = new ArrayList<>(); 7325 if (mView != null) { 7326 mView.requestKeyboardShortcuts(list, deviceId); 7327 } 7328 data.putParcelableArrayList(WindowManager.PARCEL_KEY_SHORTCUTS_ARRAY, list); 7329 try { 7330 receiver.send(0, data); 7331 } catch (RemoteException e) { 7332 } 7333 } 7334 7335 @UnsupportedAppUsage 7336 public void getLastTouchPoint(Point outLocation) { 7337 outLocation.x = (int) mLastTouchPoint.x; 7338 outLocation.y = (int) mLastTouchPoint.y; 7339 } 7340 7341 public int getLastTouchSource() { 7342 return mLastTouchSource; 7343 } 7344 7345 public void setDragFocus(View newDragTarget, DragEvent event) { 7346 if (mCurrentDragView != newDragTarget && !View.sCascadedDragDrop) { 7347 // Send EXITED and ENTERED notifications to the old and new drag focus views. 7348 7349 final float tx = event.mX; 7350 final float ty = event.mY; 7351 final int action = event.mAction; 7352 final ClipData td = event.mClipData; 7353 // Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED. 7354 event.mX = 0; 7355 event.mY = 0; 7356 event.mClipData = null; 7357 7358 if (mCurrentDragView != null) { 7359 event.mAction = DragEvent.ACTION_DRAG_EXITED; 7360 mCurrentDragView.callDragEventHandler(event); 7361 } 7362 7363 if (newDragTarget != null) { 7364 event.mAction = DragEvent.ACTION_DRAG_ENTERED; 7365 newDragTarget.callDragEventHandler(event); 7366 } 7367 7368 event.mAction = action; 7369 event.mX = tx; 7370 event.mY = ty; 7371 event.mClipData = td; 7372 } 7373 7374 mCurrentDragView = newDragTarget; 7375 } 7376 7377 private AudioManager getAudioManager() { 7378 if (mView == null) { 7379 throw new IllegalStateException("getAudioManager called when there is no mView"); 7380 } 7381 if (mAudioManager == null) { 7382 mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE); 7383 } 7384 return mAudioManager; 7385 } 7386 7387 private @Nullable AutofillManager getAutofillManager() { 7388 if (mView instanceof ViewGroup) { 7389 ViewGroup decorView = (ViewGroup) mView; 7390 if (decorView.getChildCount() > 0) { 7391 // We cannot use decorView's Context for querying AutofillManager: DecorView's 7392 // context is based on Application Context, it would allocate a different 7393 // AutofillManager instance. 7394 return decorView.getChildAt(0).getContext() 7395 .getSystemService(AutofillManager.class); 7396 } 7397 } 7398 return null; 7399 } 7400 isAutofillUiShowing()7401 private boolean isAutofillUiShowing() { 7402 AutofillManager afm = getAutofillManager(); 7403 if (afm == null) { 7404 return false; 7405 } 7406 return afm.isAutofillUiShowing(); 7407 } 7408 getAccessibilityInteractionController()7409 public AccessibilityInteractionController getAccessibilityInteractionController() { 7410 if (mView == null) { 7411 throw new IllegalStateException("getAccessibilityInteractionController" 7412 + " called when there is no mView"); 7413 } 7414 if (mAccessibilityInteractionController == null) { 7415 mAccessibilityInteractionController = new AccessibilityInteractionController(this); 7416 } 7417 return mAccessibilityInteractionController; 7418 } 7419 relayoutWindow(WindowManager.LayoutParams params, int viewVisibility, boolean insetsPending)7420 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility, 7421 boolean insetsPending) throws RemoteException { 7422 7423 float appScale = mAttachInfo.mApplicationScale; 7424 boolean restore = false; 7425 if (params != null && mTranslator != null) { 7426 restore = true; 7427 params.backup(); 7428 mTranslator.translateWindowLayout(params); 7429 } 7430 7431 if (params != null) { 7432 if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params); 7433 7434 if (mOrigWindowType != params.type) { 7435 // For compatibility with old apps, don't crash here. 7436 if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 7437 Slog.w(mTag, "Window type can not be changed after " 7438 + "the window is added; ignoring change of " + mView); 7439 params.type = mOrigWindowType; 7440 } 7441 } 7442 } 7443 7444 long frameNumber = -1; 7445 if (mSurface.isValid()) { 7446 frameNumber = mSurface.getNextFrameNumber(); 7447 } 7448 7449 int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params, 7450 (int) (mView.getMeasuredWidth() * appScale + 0.5f), 7451 (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility, 7452 insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber, 7453 mTmpFrame, mTmpRect, mTmpRect, mTmpRect, mPendingBackDropFrame, 7454 mPendingDisplayCutout, mPendingMergedConfiguration, mSurfaceControl, mTempInsets, 7455 mTempControls, mSurfaceSize, mBlastSurfaceControl); 7456 if (mSurfaceControl.isValid()) { 7457 if (!useBLAST()) { 7458 mSurface.copyFrom(mSurfaceControl); 7459 } else { 7460 final Surface blastSurface = getOrCreateBLASTSurface(mSurfaceSize.x, 7461 mSurfaceSize.y); 7462 // If blastSurface == null that means it hasn't changed since the last time we 7463 // called. In this situation, avoid calling transferFrom as we would then 7464 // inc the generation ID and cause EGL resources to be recreated. 7465 if (blastSurface != null) { 7466 mSurface.transferFrom(blastSurface); 7467 } 7468 } 7469 } else { 7470 destroySurface(); 7471 } 7472 7473 mPendingAlwaysConsumeSystemBars = 7474 (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS) != 0; 7475 7476 if (restore) { 7477 params.restore(); 7478 } 7479 7480 if (mTranslator != null) { 7481 mTranslator.translateRectInScreenToAppWinFrame(mTmpFrame); 7482 } 7483 setFrame(mTmpFrame); 7484 mInsetsController.onStateChanged(mTempInsets); 7485 mInsetsController.onControlsChanged(mTempControls); 7486 return relayoutResult; 7487 } 7488 setFrame(Rect frame)7489 private void setFrame(Rect frame) { 7490 mWinFrame.set(frame); 7491 mInsetsController.onFrameChanged(frame); 7492 } 7493 7494 /** 7495 * {@inheritDoc} 7496 */ 7497 @Override playSoundEffect(int effectId)7498 public void playSoundEffect(int effectId) { 7499 checkThread(); 7500 7501 try { 7502 final AudioManager audioManager = getAudioManager(); 7503 7504 switch (effectId) { 7505 case SoundEffectConstants.CLICK: 7506 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK); 7507 return; 7508 case SoundEffectConstants.NAVIGATION_DOWN: 7509 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN); 7510 return; 7511 case SoundEffectConstants.NAVIGATION_LEFT: 7512 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT); 7513 return; 7514 case SoundEffectConstants.NAVIGATION_RIGHT: 7515 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT); 7516 return; 7517 case SoundEffectConstants.NAVIGATION_UP: 7518 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP); 7519 return; 7520 default: 7521 throw new IllegalArgumentException("unknown effect id " + effectId + 7522 " not defined in " + SoundEffectConstants.class.getCanonicalName()); 7523 } 7524 } catch (IllegalStateException e) { 7525 // Exception thrown by getAudioManager() when mView is null 7526 Log.e(mTag, "FATAL EXCEPTION when attempting to play sound effect: " + e); 7527 e.printStackTrace(); 7528 } 7529 } 7530 7531 /** 7532 * {@inheritDoc} 7533 */ 7534 @Override performHapticFeedback(int effectId, boolean always)7535 public boolean performHapticFeedback(int effectId, boolean always) { 7536 try { 7537 return mWindowSession.performHapticFeedback(effectId, always); 7538 } catch (RemoteException e) { 7539 return false; 7540 } 7541 } 7542 7543 /** 7544 * {@inheritDoc} 7545 */ 7546 @Override focusSearch(View focused, int direction)7547 public View focusSearch(View focused, int direction) { 7548 checkThread(); 7549 if (!(mView instanceof ViewGroup)) { 7550 return null; 7551 } 7552 return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction); 7553 } 7554 7555 /** 7556 * {@inheritDoc} 7557 */ 7558 @Override keyboardNavigationClusterSearch(View currentCluster, @FocusDirection int direction)7559 public View keyboardNavigationClusterSearch(View currentCluster, 7560 @FocusDirection int direction) { 7561 checkThread(); 7562 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( 7563 mView, currentCluster, direction); 7564 } 7565 debug()7566 public void debug() { 7567 mView.debug(); 7568 } 7569 dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args)7570 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 7571 String innerPrefix = prefix + " "; 7572 writer.print(prefix); writer.println("ViewRoot:"); 7573 writer.print(innerPrefix); writer.print("mAdded="); writer.print(mAdded); 7574 writer.print(" mRemoved="); writer.println(mRemoved); 7575 writer.print(innerPrefix); writer.print("mConsumeBatchedInputScheduled="); 7576 writer.println(mConsumeBatchedInputScheduled); 7577 writer.print(innerPrefix); writer.print("mConsumeBatchedInputImmediatelyScheduled="); 7578 writer.println(mConsumeBatchedInputImmediatelyScheduled); 7579 writer.print(innerPrefix); writer.print("mPendingInputEventCount="); 7580 writer.println(mPendingInputEventCount); 7581 writer.print(innerPrefix); writer.print("mProcessInputEventsScheduled="); 7582 writer.println(mProcessInputEventsScheduled); 7583 writer.print(innerPrefix); writer.print("mTraversalScheduled="); 7584 writer.print(mTraversalScheduled); 7585 writer.print(innerPrefix); writer.print("mIsAmbientMode="); 7586 writer.print(mIsAmbientMode); 7587 writer.print(innerPrefix); writer.print("mUnbufferedInputSource="); 7588 writer.print(Integer.toHexString(mUnbufferedInputSource)); 7589 7590 if (mTraversalScheduled) { 7591 writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")"); 7592 } else { 7593 writer.println(); 7594 } 7595 mFirstInputStage.dump(innerPrefix, writer); 7596 7597 mChoreographer.dump(prefix, writer); 7598 7599 mInsetsController.dump(prefix, writer); 7600 7601 writer.print(prefix); writer.println("View Hierarchy:"); 7602 dumpViewHierarchy(innerPrefix, writer, mView); 7603 } 7604 dumpViewHierarchy(String prefix, PrintWriter writer, View view)7605 private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) { 7606 writer.print(prefix); 7607 if (view == null) { 7608 writer.println("null"); 7609 return; 7610 } 7611 writer.println(view.toString()); 7612 if (!(view instanceof ViewGroup)) { 7613 return; 7614 } 7615 ViewGroup grp = (ViewGroup)view; 7616 final int N = grp.getChildCount(); 7617 if (N <= 0) { 7618 return; 7619 } 7620 prefix = prefix + " "; 7621 for (int i=0; i<N; i++) { 7622 dumpViewHierarchy(prefix, writer, grp.getChildAt(i)); 7623 } 7624 } 7625 7626 static final class GfxInfo { 7627 public int viewCount; 7628 public long renderNodeMemoryUsage; 7629 public long renderNodeMemoryAllocated; 7630 add(GfxInfo other)7631 void add(GfxInfo other) { 7632 viewCount += other.viewCount; 7633 renderNodeMemoryUsage += other.renderNodeMemoryUsage; 7634 renderNodeMemoryAllocated += other.renderNodeMemoryAllocated; 7635 } 7636 } 7637 getGfxInfo()7638 GfxInfo getGfxInfo() { 7639 GfxInfo info = new GfxInfo(); 7640 if (mView != null) { 7641 appendGfxInfo(mView, info); 7642 } 7643 return info; 7644 } 7645 computeRenderNodeUsage(RenderNode node, GfxInfo info)7646 private static void computeRenderNodeUsage(RenderNode node, GfxInfo info) { 7647 if (node == null) return; 7648 info.renderNodeMemoryUsage += node.computeApproximateMemoryUsage(); 7649 info.renderNodeMemoryAllocated += node.computeApproximateMemoryAllocated(); 7650 } 7651 appendGfxInfo(View view, GfxInfo info)7652 private static void appendGfxInfo(View view, GfxInfo info) { 7653 info.viewCount++; 7654 computeRenderNodeUsage(view.mRenderNode, info); 7655 computeRenderNodeUsage(view.mBackgroundRenderNode, info); 7656 if (view instanceof ViewGroup) { 7657 ViewGroup group = (ViewGroup) view; 7658 7659 int count = group.getChildCount(); 7660 for (int i = 0; i < count; i++) { 7661 appendGfxInfo(group.getChildAt(i), info); 7662 } 7663 } 7664 } 7665 7666 /** 7667 * @param immediate True, do now if not in traversal. False, put on queue and do later. 7668 * @return True, request has been queued. False, request has been completed. 7669 */ die(boolean immediate)7670 boolean die(boolean immediate) { 7671 // Make sure we do execute immediately if we are in the middle of a traversal or the damage 7672 // done by dispatchDetachedFromWindow will cause havoc on return. 7673 if (immediate && !mIsInTraversal) { 7674 doDie(); 7675 return false; 7676 } 7677 7678 if (!mIsDrawing) { 7679 destroyHardwareRenderer(); 7680 } else { 7681 Log.e(mTag, "Attempting to destroy the window while drawing!\n" + 7682 " window=" + this + ", title=" + mWindowAttributes.getTitle()); 7683 } 7684 mHandler.sendEmptyMessage(MSG_DIE); 7685 return true; 7686 } 7687 doDie()7688 void doDie() { 7689 checkThread(); 7690 if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface); 7691 synchronized (this) { 7692 if (mRemoved) { 7693 return; 7694 } 7695 mRemoved = true; 7696 if (mAdded) { 7697 dispatchDetachedFromWindow(); 7698 } 7699 7700 if (mAdded && !mFirst) { 7701 destroyHardwareRenderer(); 7702 7703 if (mView != null) { 7704 int viewVisibility = mView.getVisibility(); 7705 boolean viewVisibilityChanged = mViewVisibility != viewVisibility; 7706 if (mWindowAttributesChanged || viewVisibilityChanged) { 7707 // If layout params have been changed, first give them 7708 // to the window manager to make sure it has the correct 7709 // animation info. 7710 try { 7711 if ((relayoutWindow(mWindowAttributes, viewVisibility, false) 7712 & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { 7713 mWindowSession.finishDrawing( 7714 mWindow, null /* postDrawTransaction */); 7715 } 7716 } catch (RemoteException e) { 7717 } 7718 } 7719 7720 destroySurface(); 7721 } 7722 } 7723 7724 mAdded = false; 7725 } 7726 WindowManagerGlobal.getInstance().doRemoveView(this); 7727 } 7728 requestUpdateConfiguration(Configuration config)7729 public void requestUpdateConfiguration(Configuration config) { 7730 Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config); 7731 mHandler.sendMessage(msg); 7732 } 7733 loadSystemProperties()7734 public void loadSystemProperties() { 7735 mHandler.post(new Runnable() { 7736 @Override 7737 public void run() { 7738 // Profiling 7739 mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false); 7740 profileRendering(mAttachInfo.mHasWindowFocus); 7741 7742 // Hardware rendering 7743 if (mAttachInfo.mThreadedRenderer != null) { 7744 if (mAttachInfo.mThreadedRenderer.loadSystemProperties()) { 7745 invalidate(); 7746 } 7747 } 7748 7749 // Layout debugging 7750 boolean layout = DisplayProperties.debug_layout().orElse(false); 7751 if (layout != mAttachInfo.mDebugLayout) { 7752 mAttachInfo.mDebugLayout = layout; 7753 if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) { 7754 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200); 7755 } 7756 } 7757 } 7758 }); 7759 } 7760 destroyHardwareRenderer()7761 private void destroyHardwareRenderer() { 7762 ThreadedRenderer hardwareRenderer = mAttachInfo.mThreadedRenderer; 7763 7764 if (hardwareRenderer != null) { 7765 if (mView != null) { 7766 hardwareRenderer.destroyHardwareResources(mView); 7767 } 7768 hardwareRenderer.destroy(); 7769 hardwareRenderer.setRequested(false); 7770 7771 mAttachInfo.mThreadedRenderer = null; 7772 mAttachInfo.mHardwareAccelerated = false; 7773 } 7774 } 7775 7776 @UnsupportedAppUsage dispatchResized(Rect frame, Rect contentInsets, Rect visibleInsets, Rect stableInsets, boolean reportDraw, MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, DisplayCutout.ParcelableWrapper displayCutout)7777 private void dispatchResized(Rect frame, Rect contentInsets, 7778 Rect visibleInsets, Rect stableInsets, boolean reportDraw, 7779 MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout, 7780 boolean alwaysConsumeSystemBars, int displayId, 7781 DisplayCutout.ParcelableWrapper displayCutout) { 7782 if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString() 7783 + " contentInsets=" + contentInsets.toShortString() 7784 + " visibleInsets=" + visibleInsets.toShortString() 7785 + " reportDraw=" + reportDraw 7786 + " backDropFrame=" + backDropFrame); 7787 7788 // Tell all listeners that we are resizing the window so that the chrome can get 7789 // updated as fast as possible on a separate thread, 7790 if (mDragResizing && mUseMTRenderer) { 7791 boolean fullscreen = frame.equals(backDropFrame); 7792 synchronized (mWindowCallbacks) { 7793 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { 7794 mWindowCallbacks.get(i).onWindowSizeIsChanging(backDropFrame, fullscreen, 7795 visibleInsets, stableInsets); 7796 } 7797 } 7798 } 7799 7800 Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED); 7801 if (mTranslator != null) { 7802 mTranslator.translateRectInScreenToAppWindow(frame); 7803 mTranslator.translateRectInScreenToAppWindow(contentInsets); 7804 mTranslator.translateRectInScreenToAppWindow(visibleInsets); 7805 } 7806 SomeArgs args = SomeArgs.obtain(); 7807 final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid()); 7808 args.arg1 = sameProcessCall ? new Rect(frame) : frame; 7809 args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets; 7810 args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets; 7811 args.arg4 = sameProcessCall && mergedConfiguration != null 7812 ? new MergedConfiguration(mergedConfiguration) : mergedConfiguration; 7813 args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets; 7814 args.arg8 = sameProcessCall ? new Rect(backDropFrame) : backDropFrame; 7815 args.arg9 = displayCutout.get(); // DisplayCutout is immutable. 7816 args.argi1 = forceLayout ? 1 : 0; 7817 args.argi2 = alwaysConsumeSystemBars ? 1 : 0; 7818 args.argi3 = displayId; 7819 msg.obj = args; 7820 mHandler.sendMessage(msg); 7821 } 7822 dispatchInsetsChanged(InsetsState insetsState)7823 private void dispatchInsetsChanged(InsetsState insetsState) { 7824 if (Binder.getCallingPid() == android.os.Process.myPid()) { 7825 insetsState = new InsetsState(insetsState, true /* copySource */); 7826 } 7827 mHandler.obtainMessage(MSG_INSETS_CHANGED, insetsState).sendToTarget(); 7828 } 7829 dispatchInsetsControlChanged(InsetsState insetsState, InsetsSourceControl[] activeControls)7830 private void dispatchInsetsControlChanged(InsetsState insetsState, 7831 InsetsSourceControl[] activeControls) { 7832 if (Binder.getCallingPid() == android.os.Process.myPid()) { 7833 insetsState = new InsetsState(insetsState, true /* copySource */); 7834 if (activeControls != null) { 7835 for (int i = activeControls.length - 1; i >= 0; i--) { 7836 activeControls[i] = new InsetsSourceControl(activeControls[i]); 7837 } 7838 } 7839 } 7840 SomeArgs args = SomeArgs.obtain(); 7841 args.arg1 = insetsState; 7842 args.arg2 = activeControls; 7843 mHandler.obtainMessage(MSG_INSETS_CONTROL_CHANGED, args).sendToTarget(); 7844 } 7845 showInsets(@nsetsType int types, boolean fromIme)7846 private void showInsets(@InsetsType int types, boolean fromIme) { 7847 mHandler.obtainMessage(MSG_SHOW_INSETS, types, fromIme ? 1 : 0).sendToTarget(); 7848 } 7849 hideInsets(@nsetsType int types, boolean fromIme)7850 private void hideInsets(@InsetsType int types, boolean fromIme) { 7851 mHandler.obtainMessage(MSG_HIDE_INSETS, types, fromIme ? 1 : 0).sendToTarget(); 7852 } 7853 dispatchMoved(int newX, int newY)7854 public void dispatchMoved(int newX, int newY) { 7855 if (DEBUG_LAYOUT) Log.v(mTag, "Window moved " + this + ": newX=" + newX + " newY=" + newY); 7856 if (mTranslator != null) { 7857 PointF point = new PointF(newX, newY); 7858 mTranslator.translatePointInScreenToAppWindow(point); 7859 newX = (int) (point.x + 0.5); 7860 newY = (int) (point.y + 0.5); 7861 } 7862 Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY); 7863 mHandler.sendMessage(msg); 7864 } 7865 7866 /** 7867 * Represents a pending input event that is waiting in a queue. 7868 * 7869 * Input events are processed in serial order by the timestamp specified by 7870 * {@link InputEvent#getEventTimeNano()}. In general, the input dispatcher delivers 7871 * one input event to the application at a time and waits for the application 7872 * to finish handling it before delivering the next one. 7873 * 7874 * However, because the application or IME can synthesize and inject multiple 7875 * key events at a time without going through the input dispatcher, we end up 7876 * needing a queue on the application's side. 7877 */ 7878 private static final class QueuedInputEvent { 7879 public static final int FLAG_DELIVER_POST_IME = 1 << 0; 7880 public static final int FLAG_DEFERRED = 1 << 1; 7881 public static final int FLAG_FINISHED = 1 << 2; 7882 public static final int FLAG_FINISHED_HANDLED = 1 << 3; 7883 public static final int FLAG_RESYNTHESIZED = 1 << 4; 7884 public static final int FLAG_UNHANDLED = 1 << 5; 7885 public static final int FLAG_MODIFIED_FOR_COMPATIBILITY = 1 << 6; 7886 7887 public QueuedInputEvent mNext; 7888 7889 public InputEvent mEvent; 7890 public InputEventReceiver mReceiver; 7891 public int mFlags; 7892 shouldSkipIme()7893 public boolean shouldSkipIme() { 7894 if ((mFlags & FLAG_DELIVER_POST_IME) != 0) { 7895 return true; 7896 } 7897 return mEvent instanceof MotionEvent 7898 && (mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER) 7899 || mEvent.isFromSource(InputDevice.SOURCE_ROTARY_ENCODER)); 7900 } 7901 shouldSendToSynthesizer()7902 public boolean shouldSendToSynthesizer() { 7903 if ((mFlags & FLAG_UNHANDLED) != 0) { 7904 return true; 7905 } 7906 7907 return false; 7908 } 7909 7910 @Override toString()7911 public String toString() { 7912 StringBuilder sb = new StringBuilder("QueuedInputEvent{flags="); 7913 boolean hasPrevious = false; 7914 hasPrevious = flagToString("DELIVER_POST_IME", FLAG_DELIVER_POST_IME, hasPrevious, sb); 7915 hasPrevious = flagToString("DEFERRED", FLAG_DEFERRED, hasPrevious, sb); 7916 hasPrevious = flagToString("FINISHED", FLAG_FINISHED, hasPrevious, sb); 7917 hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb); 7918 hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb); 7919 hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb); 7920 if (!hasPrevious) { 7921 sb.append("0"); 7922 } 7923 sb.append(", hasNextQueuedEvent=" + (mEvent != null ? "true" : "false")); 7924 sb.append(", hasInputEventReceiver=" + (mReceiver != null ? "true" : "false")); 7925 sb.append(", mEvent=" + mEvent + "}"); 7926 return sb.toString(); 7927 } 7928 flagToString(String name, int flag, boolean hasPrevious, StringBuilder sb)7929 private boolean flagToString(String name, int flag, 7930 boolean hasPrevious, StringBuilder sb) { 7931 if ((mFlags & flag) != 0) { 7932 if (hasPrevious) { 7933 sb.append("|"); 7934 } 7935 sb.append(name); 7936 return true; 7937 } 7938 return hasPrevious; 7939 } 7940 } 7941 obtainQueuedInputEvent(InputEvent event, InputEventReceiver receiver, int flags)7942 private QueuedInputEvent obtainQueuedInputEvent(InputEvent event, 7943 InputEventReceiver receiver, int flags) { 7944 QueuedInputEvent q = mQueuedInputEventPool; 7945 if (q != null) { 7946 mQueuedInputEventPoolSize -= 1; 7947 mQueuedInputEventPool = q.mNext; 7948 q.mNext = null; 7949 } else { 7950 q = new QueuedInputEvent(); 7951 } 7952 7953 q.mEvent = event; 7954 q.mReceiver = receiver; 7955 q.mFlags = flags; 7956 return q; 7957 } 7958 recycleQueuedInputEvent(QueuedInputEvent q)7959 private void recycleQueuedInputEvent(QueuedInputEvent q) { 7960 q.mEvent = null; 7961 q.mReceiver = null; 7962 7963 if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) { 7964 mQueuedInputEventPoolSize += 1; 7965 q.mNext = mQueuedInputEventPool; 7966 mQueuedInputEventPool = q; 7967 } 7968 } 7969 7970 @UnsupportedAppUsage enqueueInputEvent(InputEvent event)7971 void enqueueInputEvent(InputEvent event) { 7972 enqueueInputEvent(event, null, 0, false); 7973 } 7974 7975 @UnsupportedAppUsage enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately)7976 void enqueueInputEvent(InputEvent event, 7977 InputEventReceiver receiver, int flags, boolean processImmediately) { 7978 QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags); 7979 7980 // Always enqueue the input event in order, regardless of its time stamp. 7981 // We do this because the application or the IME may inject key events 7982 // in response to touch events and we want to ensure that the injected keys 7983 // are processed in the order they were received and we cannot trust that 7984 // the time stamp of injected events are monotonic. 7985 QueuedInputEvent last = mPendingInputEventTail; 7986 if (last == null) { 7987 mPendingInputEventHead = q; 7988 mPendingInputEventTail = q; 7989 } else { 7990 last.mNext = q; 7991 mPendingInputEventTail = q; 7992 } 7993 mPendingInputEventCount += 1; 7994 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName, 7995 mPendingInputEventCount); 7996 7997 if (processImmediately) { 7998 doProcessInputEvents(); 7999 } else { 8000 scheduleProcessInputEvents(); 8001 } 8002 } 8003 scheduleProcessInputEvents()8004 private void scheduleProcessInputEvents() { 8005 if (!mProcessInputEventsScheduled) { 8006 mProcessInputEventsScheduled = true; 8007 Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS); 8008 msg.setAsynchronous(true); 8009 mHandler.sendMessage(msg); 8010 } 8011 } 8012 doProcessInputEvents()8013 void doProcessInputEvents() { 8014 // Deliver all pending input events in the queue. 8015 while (mPendingInputEventHead != null) { 8016 QueuedInputEvent q = mPendingInputEventHead; 8017 mPendingInputEventHead = q.mNext; 8018 if (mPendingInputEventHead == null) { 8019 mPendingInputEventTail = null; 8020 } 8021 q.mNext = null; 8022 8023 mPendingInputEventCount -= 1; 8024 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName, 8025 mPendingInputEventCount); 8026 8027 long eventTime = q.mEvent.getEventTimeNano(); 8028 long oldestEventTime = eventTime; 8029 if (q.mEvent instanceof MotionEvent) { 8030 MotionEvent me = (MotionEvent)q.mEvent; 8031 if (me.getHistorySize() > 0) { 8032 oldestEventTime = me.getHistoricalEventTimeNano(0); 8033 } 8034 } 8035 mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime); 8036 8037 deliverInputEvent(q); 8038 } 8039 8040 // We are done processing all input events that we can process right now 8041 // so we can clear the pending flag immediately. 8042 if (mProcessInputEventsScheduled) { 8043 mProcessInputEventsScheduled = false; 8044 mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS); 8045 } 8046 } 8047 deliverInputEvent(QueuedInputEvent q)8048 private void deliverInputEvent(QueuedInputEvent q) { 8049 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent", 8050 q.mEvent.getId()); 8051 8052 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 8053 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent src=0x" 8054 + Integer.toHexString(q.mEvent.getSource()) + " eventTimeNano=" 8055 + q.mEvent.getEventTimeNano() + " id=0x" 8056 + Integer.toHexString(q.mEvent.getId())); 8057 } 8058 try { 8059 if (mInputEventConsistencyVerifier != null) { 8060 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "verifyEventConsistency"); 8061 try { 8062 mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0); 8063 } finally { 8064 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 8065 } 8066 } 8067 8068 InputStage stage; 8069 if (q.shouldSendToSynthesizer()) { 8070 stage = mSyntheticInputStage; 8071 } else { 8072 stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage; 8073 } 8074 8075 if (q.mEvent instanceof KeyEvent) { 8076 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "preDispatchToUnhandledKeyManager"); 8077 try { 8078 mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent); 8079 } finally { 8080 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 8081 } 8082 } 8083 8084 if (stage != null) { 8085 handleWindowFocusChanged(); 8086 stage.deliver(q); 8087 } else { 8088 finishInputEvent(q); 8089 } 8090 } finally { 8091 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 8092 } 8093 } 8094 finishInputEvent(QueuedInputEvent q)8095 private void finishInputEvent(QueuedInputEvent q) { 8096 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent", 8097 q.mEvent.getId()); 8098 8099 if (q.mReceiver != null) { 8100 boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0; 8101 boolean modified = (q.mFlags & QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY) != 0; 8102 if (modified) { 8103 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventBeforeFinish"); 8104 InputEvent processedEvent; 8105 try { 8106 processedEvent = 8107 mInputCompatProcessor.processInputEventBeforeFinish(q.mEvent); 8108 } finally { 8109 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 8110 } 8111 if (processedEvent != null) { 8112 q.mReceiver.finishInputEvent(processedEvent, handled); 8113 } 8114 } else { 8115 q.mReceiver.finishInputEvent(q.mEvent, handled); 8116 } 8117 } else { 8118 q.mEvent.recycleIfNeededAfterDispatch(); 8119 } 8120 8121 recycleQueuedInputEvent(q); 8122 } 8123 isTerminalInputEvent(InputEvent event)8124 static boolean isTerminalInputEvent(InputEvent event) { 8125 if (event instanceof KeyEvent) { 8126 final KeyEvent keyEvent = (KeyEvent)event; 8127 return keyEvent.getAction() == KeyEvent.ACTION_UP; 8128 } else { 8129 final MotionEvent motionEvent = (MotionEvent)event; 8130 final int action = motionEvent.getAction(); 8131 return action == MotionEvent.ACTION_UP 8132 || action == MotionEvent.ACTION_CANCEL 8133 || action == MotionEvent.ACTION_HOVER_EXIT; 8134 } 8135 } 8136 scheduleConsumeBatchedInput()8137 void scheduleConsumeBatchedInput() { 8138 // If anything is currently scheduled to consume batched input then there's no point in 8139 // scheduling it again. 8140 if (!mConsumeBatchedInputScheduled && !mConsumeBatchedInputImmediatelyScheduled) { 8141 mConsumeBatchedInputScheduled = true; 8142 mChoreographer.postCallback(Choreographer.CALLBACK_INPUT, 8143 mConsumedBatchedInputRunnable, null); 8144 } 8145 } 8146 unscheduleConsumeBatchedInput()8147 void unscheduleConsumeBatchedInput() { 8148 if (mConsumeBatchedInputScheduled) { 8149 mConsumeBatchedInputScheduled = false; 8150 mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT, 8151 mConsumedBatchedInputRunnable, null); 8152 } 8153 } 8154 scheduleConsumeBatchedInputImmediately()8155 void scheduleConsumeBatchedInputImmediately() { 8156 if (!mConsumeBatchedInputImmediatelyScheduled) { 8157 unscheduleConsumeBatchedInput(); 8158 mConsumeBatchedInputImmediatelyScheduled = true; 8159 mHandler.post(mConsumeBatchedInputImmediatelyRunnable); 8160 } 8161 } 8162 doConsumeBatchedInput(long frameTimeNanos)8163 boolean doConsumeBatchedInput(long frameTimeNanos) { 8164 final boolean consumedBatches; 8165 if (mInputEventReceiver != null) { 8166 consumedBatches = mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos); 8167 } else { 8168 consumedBatches = false; 8169 } 8170 doProcessInputEvents(); 8171 return consumedBatches; 8172 } 8173 8174 final class TraversalRunnable implements Runnable { 8175 @Override run()8176 public void run() { 8177 doTraversal(); 8178 } 8179 } 8180 final TraversalRunnable mTraversalRunnable = new TraversalRunnable(); 8181 8182 final class WindowInputEventReceiver extends InputEventReceiver { WindowInputEventReceiver(InputChannel inputChannel, Looper looper)8183 public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) { 8184 super(inputChannel, looper); 8185 } 8186 8187 @Override onInputEvent(InputEvent event)8188 public void onInputEvent(InputEvent event) { 8189 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventForCompatibility"); 8190 List<InputEvent> processedEvents; 8191 try { 8192 processedEvents = 8193 mInputCompatProcessor.processInputEventForCompatibility(event); 8194 } finally { 8195 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 8196 } 8197 if (processedEvents != null) { 8198 if (processedEvents.isEmpty()) { 8199 // InputEvent consumed by mInputCompatProcessor 8200 finishInputEvent(event, true); 8201 } else { 8202 for (int i = 0; i < processedEvents.size(); i++) { 8203 enqueueInputEvent( 8204 processedEvents.get(i), this, 8205 QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY, true); 8206 } 8207 } 8208 } else { 8209 enqueueInputEvent(event, this, 0, true); 8210 } 8211 } 8212 8213 @Override onBatchedInputEventPending(int source)8214 public void onBatchedInputEventPending(int source) { 8215 // mStopped: There will be no more choreographer callbacks if we are stopped, 8216 // so we must consume all input immediately to prevent ANR 8217 final boolean unbuffered = mUnbufferedInputDispatch 8218 || (source & mUnbufferedInputSource) != SOURCE_CLASS_NONE 8219 || mStopped; 8220 if (unbuffered) { 8221 if (mConsumeBatchedInputScheduled) { 8222 unscheduleConsumeBatchedInput(); 8223 } 8224 // Consume event immediately if unbuffered input dispatch has been requested. 8225 consumeBatchedInputEvents(-1); 8226 return; 8227 } 8228 scheduleConsumeBatchedInput(); 8229 } 8230 8231 @Override onFocusEvent(boolean hasFocus, boolean inTouchMode)8232 public void onFocusEvent(boolean hasFocus, boolean inTouchMode) { 8233 windowFocusChanged(hasFocus, inTouchMode); 8234 } 8235 8236 @Override dispose()8237 public void dispose() { 8238 unscheduleConsumeBatchedInput(); 8239 super.dispose(); 8240 } 8241 } 8242 WindowInputEventReceiver mInputEventReceiver; 8243 8244 final class ConsumeBatchedInputRunnable implements Runnable { 8245 @Override run()8246 public void run() { 8247 mConsumeBatchedInputScheduled = false; 8248 if (doConsumeBatchedInput(mChoreographer.getFrameTimeNanos())) { 8249 // If we consumed a batch here, we want to go ahead and schedule the 8250 // consumption of batched input events on the next frame. Otherwise, we would 8251 // wait until we have more input events pending and might get starved by other 8252 // things occurring in the process. 8253 scheduleConsumeBatchedInput(); 8254 } 8255 } 8256 } 8257 final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable = 8258 new ConsumeBatchedInputRunnable(); 8259 boolean mConsumeBatchedInputScheduled; 8260 8261 final class ConsumeBatchedInputImmediatelyRunnable implements Runnable { 8262 @Override run()8263 public void run() { 8264 mConsumeBatchedInputImmediatelyScheduled = false; 8265 doConsumeBatchedInput(-1); 8266 } 8267 } 8268 final ConsumeBatchedInputImmediatelyRunnable mConsumeBatchedInputImmediatelyRunnable = 8269 new ConsumeBatchedInputImmediatelyRunnable(); 8270 boolean mConsumeBatchedInputImmediatelyScheduled; 8271 8272 final class InvalidateOnAnimationRunnable implements Runnable { 8273 private boolean mPosted; 8274 private final ArrayList<View> mViews = new ArrayList<View>(); 8275 private final ArrayList<AttachInfo.InvalidateInfo> mViewRects = 8276 new ArrayList<AttachInfo.InvalidateInfo>(); 8277 private View[] mTempViews; 8278 private AttachInfo.InvalidateInfo[] mTempViewRects; 8279 addView(View view)8280 public void addView(View view) { 8281 synchronized (this) { 8282 mViews.add(view); 8283 postIfNeededLocked(); 8284 } 8285 } 8286 addViewRect(AttachInfo.InvalidateInfo info)8287 public void addViewRect(AttachInfo.InvalidateInfo info) { 8288 synchronized (this) { 8289 mViewRects.add(info); 8290 postIfNeededLocked(); 8291 } 8292 } 8293 removeView(View view)8294 public void removeView(View view) { 8295 synchronized (this) { 8296 mViews.remove(view); 8297 8298 for (int i = mViewRects.size(); i-- > 0; ) { 8299 AttachInfo.InvalidateInfo info = mViewRects.get(i); 8300 if (info.target == view) { 8301 mViewRects.remove(i); 8302 info.recycle(); 8303 } 8304 } 8305 8306 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) { 8307 mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null); 8308 mPosted = false; 8309 } 8310 } 8311 } 8312 8313 @Override run()8314 public void run() { 8315 final int viewCount; 8316 final int viewRectCount; 8317 synchronized (this) { 8318 mPosted = false; 8319 8320 viewCount = mViews.size(); 8321 if (viewCount != 0) { 8322 mTempViews = mViews.toArray(mTempViews != null 8323 ? mTempViews : new View[viewCount]); 8324 mViews.clear(); 8325 } 8326 8327 viewRectCount = mViewRects.size(); 8328 if (viewRectCount != 0) { 8329 mTempViewRects = mViewRects.toArray(mTempViewRects != null 8330 ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]); 8331 mViewRects.clear(); 8332 } 8333 } 8334 8335 for (int i = 0; i < viewCount; i++) { 8336 mTempViews[i].invalidate(); 8337 mTempViews[i] = null; 8338 } 8339 8340 for (int i = 0; i < viewRectCount; i++) { 8341 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i]; 8342 info.target.invalidate(info.left, info.top, info.right, info.bottom); 8343 info.recycle(); 8344 } 8345 } 8346 postIfNeededLocked()8347 private void postIfNeededLocked() { 8348 if (!mPosted) { 8349 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null); 8350 mPosted = true; 8351 } 8352 } 8353 } 8354 final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable = 8355 new InvalidateOnAnimationRunnable(); 8356 dispatchInvalidateDelayed(View view, long delayMilliseconds)8357 public void dispatchInvalidateDelayed(View view, long delayMilliseconds) { 8358 Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view); 8359 mHandler.sendMessageDelayed(msg, delayMilliseconds); 8360 } 8361 dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info, long delayMilliseconds)8362 public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info, 8363 long delayMilliseconds) { 8364 final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info); 8365 mHandler.sendMessageDelayed(msg, delayMilliseconds); 8366 } 8367 dispatchInvalidateOnAnimation(View view)8368 public void dispatchInvalidateOnAnimation(View view) { 8369 mInvalidateOnAnimationRunnable.addView(view); 8370 } 8371 dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info)8372 public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) { 8373 mInvalidateOnAnimationRunnable.addViewRect(info); 8374 } 8375 8376 @UnsupportedAppUsage cancelInvalidate(View view)8377 public void cancelInvalidate(View view) { 8378 mHandler.removeMessages(MSG_INVALIDATE, view); 8379 // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning 8380 // them to the pool 8381 mHandler.removeMessages(MSG_INVALIDATE_RECT, view); 8382 mInvalidateOnAnimationRunnable.removeView(view); 8383 } 8384 8385 @UnsupportedAppUsage dispatchInputEvent(InputEvent event)8386 public void dispatchInputEvent(InputEvent event) { 8387 dispatchInputEvent(event, null); 8388 } 8389 8390 @UnsupportedAppUsage dispatchInputEvent(InputEvent event, InputEventReceiver receiver)8391 public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) { 8392 SomeArgs args = SomeArgs.obtain(); 8393 args.arg1 = event; 8394 args.arg2 = receiver; 8395 Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args); 8396 msg.setAsynchronous(true); 8397 mHandler.sendMessage(msg); 8398 } 8399 synthesizeInputEvent(InputEvent event)8400 public void synthesizeInputEvent(InputEvent event) { 8401 Message msg = mHandler.obtainMessage(MSG_SYNTHESIZE_INPUT_EVENT, event); 8402 msg.setAsynchronous(true); 8403 mHandler.sendMessage(msg); 8404 } 8405 8406 @UnsupportedAppUsage dispatchKeyFromIme(KeyEvent event)8407 public void dispatchKeyFromIme(KeyEvent event) { 8408 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event); 8409 msg.setAsynchronous(true); 8410 mHandler.sendMessage(msg); 8411 } 8412 dispatchKeyFromAutofill(KeyEvent event)8413 public void dispatchKeyFromAutofill(KeyEvent event) { 8414 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_AUTOFILL, event); 8415 msg.setAsynchronous(true); 8416 mHandler.sendMessage(msg); 8417 } 8418 8419 /** 8420 * Reinject unhandled {@link InputEvent}s in order to synthesize fallbacks events. 8421 * 8422 * Note that it is the responsibility of the caller of this API to recycle the InputEvent it 8423 * passes in. 8424 */ 8425 @UnsupportedAppUsage dispatchUnhandledInputEvent(InputEvent event)8426 public void dispatchUnhandledInputEvent(InputEvent event) { 8427 if (event instanceof MotionEvent) { 8428 event = MotionEvent.obtain((MotionEvent) event); 8429 } 8430 synthesizeInputEvent(event); 8431 } 8432 dispatchAppVisibility(boolean visible)8433 public void dispatchAppVisibility(boolean visible) { 8434 Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY); 8435 msg.arg1 = visible ? 1 : 0; 8436 mHandler.sendMessage(msg); 8437 } 8438 dispatchGetNewSurface()8439 public void dispatchGetNewSurface() { 8440 Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE); 8441 mHandler.sendMessage(msg); 8442 } 8443 8444 /** 8445 * Dispatch the offset changed. 8446 * 8447 * @param offset the offset of this view in the parent window. 8448 */ dispatchLocationInParentDisplayChanged(Point offset)8449 public void dispatchLocationInParentDisplayChanged(Point offset) { 8450 Message msg = 8451 mHandler.obtainMessage(MSG_LOCATION_IN_PARENT_DISPLAY_CHANGED, offset.x, offset.y); 8452 mHandler.sendMessage(msg); 8453 } 8454 windowFocusChanged(boolean hasFocus, boolean inTouchMode)8455 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) { 8456 synchronized (this) { 8457 mWindowFocusChanged = true; 8458 mUpcomingWindowFocus = hasFocus; 8459 mUpcomingInTouchMode = inTouchMode; 8460 } 8461 Message msg = Message.obtain(); 8462 msg.what = MSG_WINDOW_FOCUS_CHANGED; 8463 mHandler.sendMessage(msg); 8464 } 8465 dispatchWindowShown()8466 public void dispatchWindowShown() { 8467 mHandler.sendEmptyMessage(MSG_DISPATCH_WINDOW_SHOWN); 8468 } 8469 dispatchCloseSystemDialogs(String reason)8470 public void dispatchCloseSystemDialogs(String reason) { 8471 Message msg = Message.obtain(); 8472 msg.what = MSG_CLOSE_SYSTEM_DIALOGS; 8473 msg.obj = reason; 8474 mHandler.sendMessage(msg); 8475 } 8476 dispatchDragEvent(DragEvent event)8477 public void dispatchDragEvent(DragEvent event) { 8478 final int what; 8479 if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) { 8480 what = MSG_DISPATCH_DRAG_LOCATION_EVENT; 8481 mHandler.removeMessages(what); 8482 } else { 8483 what = MSG_DISPATCH_DRAG_EVENT; 8484 } 8485 Message msg = mHandler.obtainMessage(what, event); 8486 mHandler.sendMessage(msg); 8487 } 8488 updatePointerIcon(float x, float y)8489 public void updatePointerIcon(float x, float y) { 8490 final int what = MSG_UPDATE_POINTER_ICON; 8491 mHandler.removeMessages(what); 8492 final long now = SystemClock.uptimeMillis(); 8493 final MotionEvent event = MotionEvent.obtain( 8494 0, now, MotionEvent.ACTION_HOVER_MOVE, x, y, 0); 8495 Message msg = mHandler.obtainMessage(what, event); 8496 mHandler.sendMessage(msg); 8497 } 8498 8499 // TODO(118118435): Remove this after migration dispatchSystemUiVisibilityChanged(int seq, int globalVisibility, int localValue, int localChanges)8500 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility, 8501 int localValue, int localChanges) { 8502 SystemUiVisibilityInfo args = new SystemUiVisibilityInfo(); 8503 args.seq = seq; 8504 args.globalVisibility = globalVisibility; 8505 args.localValue = localValue; 8506 args.localChanges = localChanges; 8507 mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args)); 8508 } 8509 dispatchCheckFocus()8510 public void dispatchCheckFocus() { 8511 if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) { 8512 // This will result in a call to checkFocus() below. 8513 mHandler.sendEmptyMessage(MSG_CHECK_FOCUS); 8514 } 8515 } 8516 dispatchRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId)8517 public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) { 8518 mHandler.obtainMessage( 8519 MSG_REQUEST_KEYBOARD_SHORTCUTS, deviceId, 0, receiver).sendToTarget(); 8520 } 8521 dispatchPointerCaptureChanged(boolean on)8522 public void dispatchPointerCaptureChanged(boolean on) { 8523 final int what = MSG_POINTER_CAPTURE_CHANGED; 8524 mHandler.removeMessages(what); 8525 Message msg = mHandler.obtainMessage(what); 8526 msg.arg1 = on ? 1 : 0; 8527 mHandler.sendMessage(msg); 8528 } 8529 8530 /** 8531 * Post a callback to send a 8532 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event. 8533 * This event is send at most once every 8534 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 8535 */ postSendWindowContentChangedCallback(View source, int changeType)8536 private void postSendWindowContentChangedCallback(View source, int changeType) { 8537 if (mSendWindowContentChangedAccessibilityEvent == null) { 8538 mSendWindowContentChangedAccessibilityEvent = 8539 new SendWindowContentChangedAccessibilityEvent(); 8540 } 8541 mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType); 8542 } 8543 8544 /** 8545 * Remove a posted callback to send a 8546 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event. 8547 */ removeSendWindowContentChangedCallback()8548 private void removeSendWindowContentChangedCallback() { 8549 if (mSendWindowContentChangedAccessibilityEvent != null) { 8550 mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent); 8551 } 8552 } 8553 8554 @Override showContextMenuForChild(View originalView)8555 public boolean showContextMenuForChild(View originalView) { 8556 return false; 8557 } 8558 8559 @Override showContextMenuForChild(View originalView, float x, float y)8560 public boolean showContextMenuForChild(View originalView, float x, float y) { 8561 return false; 8562 } 8563 8564 @Override startActionModeForChild(View originalView, ActionMode.Callback callback)8565 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) { 8566 return null; 8567 } 8568 8569 @Override startActionModeForChild( View originalView, ActionMode.Callback callback, int type)8570 public ActionMode startActionModeForChild( 8571 View originalView, ActionMode.Callback callback, int type) { 8572 return null; 8573 } 8574 8575 @Override createContextMenu(ContextMenu menu)8576 public void createContextMenu(ContextMenu menu) { 8577 } 8578 8579 @Override childDrawableStateChanged(View child)8580 public void childDrawableStateChanged(View child) { 8581 } 8582 8583 @Override requestSendAccessibilityEvent(View child, AccessibilityEvent event)8584 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) { 8585 if (mView == null || mStopped || mPausedForTransition) { 8586 return false; 8587 } 8588 8589 // Immediately flush pending content changed event (if any) to preserve event order 8590 if (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED 8591 && mSendWindowContentChangedAccessibilityEvent != null 8592 && mSendWindowContentChangedAccessibilityEvent.mSource != null) { 8593 mSendWindowContentChangedAccessibilityEvent.removeCallbacksAndRun(); 8594 } 8595 8596 // Intercept accessibility focus events fired by virtual nodes to keep 8597 // track of accessibility focus position in such nodes. 8598 final int eventType = event.getEventType(); 8599 final View source = getSourceForAccessibilityEvent(event); 8600 switch (eventType) { 8601 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: { 8602 if (source != null) { 8603 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider(); 8604 if (provider != null) { 8605 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId( 8606 event.getSourceNodeId()); 8607 final AccessibilityNodeInfo node; 8608 node = provider.createAccessibilityNodeInfo(virtualNodeId); 8609 setAccessibilityFocus(source, node); 8610 } 8611 } 8612 } break; 8613 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: { 8614 if (source != null && source.getAccessibilityNodeProvider() != null) { 8615 setAccessibilityFocus(null, null); 8616 } 8617 } break; 8618 8619 8620 case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: { 8621 handleWindowContentChangedEvent(event); 8622 } break; 8623 } 8624 mAccessibilityManager.sendAccessibilityEvent(event); 8625 return true; 8626 } 8627 getSourceForAccessibilityEvent(AccessibilityEvent event)8628 private View getSourceForAccessibilityEvent(AccessibilityEvent event) { 8629 final long sourceNodeId = event.getSourceNodeId(); 8630 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId( 8631 sourceNodeId); 8632 return AccessibilityNodeIdManager.getInstance().findView(accessibilityViewId); 8633 } 8634 8635 /** 8636 * Updates the focused virtual view, when necessary, in response to a 8637 * content changed event. 8638 * <p> 8639 * This is necessary to get updated bounds after a position change. 8640 * 8641 * @param event an accessibility event of type 8642 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} 8643 */ handleWindowContentChangedEvent(AccessibilityEvent event)8644 private void handleWindowContentChangedEvent(AccessibilityEvent event) { 8645 final View focusedHost = mAccessibilityFocusedHost; 8646 if (focusedHost == null || mAccessibilityFocusedVirtualView == null) { 8647 // No virtual view focused, nothing to do here. 8648 return; 8649 } 8650 8651 final AccessibilityNodeProvider provider = focusedHost.getAccessibilityNodeProvider(); 8652 if (provider == null) { 8653 // Error state: virtual view with no provider. Clear focus. 8654 mAccessibilityFocusedHost = null; 8655 mAccessibilityFocusedVirtualView = null; 8656 focusedHost.clearAccessibilityFocusNoCallbacks(0); 8657 return; 8658 } 8659 8660 // We only care about change types that may affect the bounds of the 8661 // focused virtual view. 8662 final int changes = event.getContentChangeTypes(); 8663 if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) == 0 8664 && changes != AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) { 8665 return; 8666 } 8667 8668 final long eventSourceNodeId = event.getSourceNodeId(); 8669 final int changedViewId = AccessibilityNodeInfo.getAccessibilityViewId(eventSourceNodeId); 8670 8671 // Search up the tree for subtree containment. 8672 boolean hostInSubtree = false; 8673 View root = mAccessibilityFocusedHost; 8674 while (root != null && !hostInSubtree) { 8675 if (changedViewId == root.getAccessibilityViewId()) { 8676 hostInSubtree = true; 8677 } else { 8678 final ViewParent parent = root.getParent(); 8679 if (parent instanceof View) { 8680 root = (View) parent; 8681 } else { 8682 root = null; 8683 } 8684 } 8685 } 8686 8687 // We care only about changes in subtrees containing the host view. 8688 if (!hostInSubtree) { 8689 return; 8690 } 8691 8692 final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId(); 8693 int focusedChildId = AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId); 8694 8695 // Refresh the node for the focused virtual view. 8696 final Rect oldBounds = mTempRect; 8697 mAccessibilityFocusedVirtualView.getBoundsInScreen(oldBounds); 8698 mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo(focusedChildId); 8699 if (mAccessibilityFocusedVirtualView == null) { 8700 // Error state: The node no longer exists. Clear focus. 8701 mAccessibilityFocusedHost = null; 8702 focusedHost.clearAccessibilityFocusNoCallbacks(0); 8703 8704 // This will probably fail, but try to keep the provider's internal 8705 // state consistent by clearing focus. 8706 provider.performAction(focusedChildId, 8707 AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(), null); 8708 invalidateRectOnScreen(oldBounds); 8709 } else { 8710 // The node was refreshed, invalidate bounds if necessary. 8711 final Rect newBounds = mAccessibilityFocusedVirtualView.getBoundsInScreen(); 8712 if (!oldBounds.equals(newBounds)) { 8713 oldBounds.union(newBounds); 8714 invalidateRectOnScreen(oldBounds); 8715 } 8716 } 8717 } 8718 8719 @Override notifySubtreeAccessibilityStateChanged(View child, View source, int changeType)8720 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) { 8721 postSendWindowContentChangedCallback(Preconditions.checkNotNull(source), changeType); 8722 } 8723 8724 @Override canResolveLayoutDirection()8725 public boolean canResolveLayoutDirection() { 8726 return true; 8727 } 8728 8729 @Override isLayoutDirectionResolved()8730 public boolean isLayoutDirectionResolved() { 8731 return true; 8732 } 8733 8734 @Override getLayoutDirection()8735 public int getLayoutDirection() { 8736 return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT; 8737 } 8738 8739 @Override canResolveTextDirection()8740 public boolean canResolveTextDirection() { 8741 return true; 8742 } 8743 8744 @Override isTextDirectionResolved()8745 public boolean isTextDirectionResolved() { 8746 return true; 8747 } 8748 8749 @Override getTextDirection()8750 public int getTextDirection() { 8751 return View.TEXT_DIRECTION_RESOLVED_DEFAULT; 8752 } 8753 8754 @Override canResolveTextAlignment()8755 public boolean canResolveTextAlignment() { 8756 return true; 8757 } 8758 8759 @Override isTextAlignmentResolved()8760 public boolean isTextAlignmentResolved() { 8761 return true; 8762 } 8763 8764 @Override getTextAlignment()8765 public int getTextAlignment() { 8766 return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT; 8767 } 8768 getCommonPredecessor(View first, View second)8769 private View getCommonPredecessor(View first, View second) { 8770 if (mTempHashSet == null) { 8771 mTempHashSet = new HashSet<View>(); 8772 } 8773 HashSet<View> seen = mTempHashSet; 8774 seen.clear(); 8775 View firstCurrent = first; 8776 while (firstCurrent != null) { 8777 seen.add(firstCurrent); 8778 ViewParent firstCurrentParent = firstCurrent.mParent; 8779 if (firstCurrentParent instanceof View) { 8780 firstCurrent = (View) firstCurrentParent; 8781 } else { 8782 firstCurrent = null; 8783 } 8784 } 8785 View secondCurrent = second; 8786 while (secondCurrent != null) { 8787 if (seen.contains(secondCurrent)) { 8788 seen.clear(); 8789 return secondCurrent; 8790 } 8791 ViewParent secondCurrentParent = secondCurrent.mParent; 8792 if (secondCurrentParent instanceof View) { 8793 secondCurrent = (View) secondCurrentParent; 8794 } else { 8795 secondCurrent = null; 8796 } 8797 } 8798 seen.clear(); 8799 return null; 8800 } 8801 checkThread()8802 void checkThread() { 8803 if (mThread != Thread.currentThread()) { 8804 throw new CalledFromWrongThreadException( 8805 "Only the original thread that created a view hierarchy can touch its views."); 8806 } 8807 } 8808 8809 @Override requestDisallowInterceptTouchEvent(boolean disallowIntercept)8810 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { 8811 // ViewAncestor never intercepts touch event, so this can be a no-op 8812 } 8813 8814 @Override requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate)8815 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) { 8816 if (rectangle == null) { 8817 return scrollToRectOrFocus(null, immediate); 8818 } 8819 rectangle.offset(child.getLeft() - child.getScrollX(), 8820 child.getTop() - child.getScrollY()); 8821 final boolean scrolled = scrollToRectOrFocus(rectangle, immediate); 8822 mTempRect.set(rectangle); 8823 mTempRect.offset(0, -mCurScrollY); 8824 mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 8825 try { 8826 mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect); 8827 } catch (RemoteException re) { 8828 /* ignore */ 8829 } 8830 return scrolled; 8831 } 8832 8833 @Override childHasTransientStateChanged(View child, boolean hasTransientState)8834 public void childHasTransientStateChanged(View child, boolean hasTransientState) { 8835 // Do nothing. 8836 } 8837 8838 @Override onStartNestedScroll(View child, View target, int nestedScrollAxes)8839 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) { 8840 return false; 8841 } 8842 8843 @Override onStopNestedScroll(View target)8844 public void onStopNestedScroll(View target) { 8845 } 8846 8847 @Override onNestedScrollAccepted(View child, View target, int nestedScrollAxes)8848 public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) { 8849 } 8850 8851 @Override onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed)8852 public void onNestedScroll(View target, int dxConsumed, int dyConsumed, 8853 int dxUnconsumed, int dyUnconsumed) { 8854 } 8855 8856 @Override onNestedPreScroll(View target, int dx, int dy, int[] consumed)8857 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) { 8858 } 8859 8860 @Override onNestedFling(View target, float velocityX, float velocityY, boolean consumed)8861 public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) { 8862 return false; 8863 } 8864 8865 @Override onNestedPreFling(View target, float velocityX, float velocityY)8866 public boolean onNestedPreFling(View target, float velocityX, float velocityY) { 8867 return false; 8868 } 8869 8870 @Override onNestedPrePerformAccessibilityAction(View target, int action, Bundle args)8871 public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) { 8872 return false; 8873 } 8874 8875 /** 8876 * Adds a scroll capture callback to this window. 8877 * 8878 * @param callback the callback to add 8879 */ addScrollCaptureCallback(ScrollCaptureCallback callback)8880 public void addScrollCaptureCallback(ScrollCaptureCallback callback) { 8881 if (mRootScrollCaptureCallbacks == null) { 8882 mRootScrollCaptureCallbacks = new HashSet<>(); 8883 } 8884 mRootScrollCaptureCallbacks.add(callback); 8885 } 8886 8887 /** 8888 * Removes a scroll capture callback from this window. 8889 * 8890 * @param callback the callback to remove 8891 */ removeScrollCaptureCallback(ScrollCaptureCallback callback)8892 public void removeScrollCaptureCallback(ScrollCaptureCallback callback) { 8893 if (mRootScrollCaptureCallbacks != null) { 8894 mRootScrollCaptureCallbacks.remove(callback); 8895 if (mRootScrollCaptureCallbacks.isEmpty()) { 8896 mRootScrollCaptureCallbacks = null; 8897 } 8898 } 8899 } 8900 8901 /** 8902 * Dispatches a scroll capture request to the view hierarchy on the ui thread. 8903 * 8904 * @param controller the controller to receive replies 8905 */ dispatchScrollCaptureRequest(@onNull IScrollCaptureController controller)8906 public void dispatchScrollCaptureRequest(@NonNull IScrollCaptureController controller) { 8907 mHandler.obtainMessage(MSG_REQUEST_SCROLL_CAPTURE, controller).sendToTarget(); 8908 } 8909 8910 /** 8911 * Collect and include any ScrollCaptureCallback instances registered with the window. 8912 * 8913 * @see #addScrollCaptureCallback(ScrollCaptureCallback) 8914 * @param targets the search queue for targets 8915 */ collectRootScrollCaptureTargets(Queue<ScrollCaptureTarget> targets)8916 private void collectRootScrollCaptureTargets(Queue<ScrollCaptureTarget> targets) { 8917 for (ScrollCaptureCallback cb : mRootScrollCaptureCallbacks) { 8918 // Add to the list for consideration 8919 Point offset = new Point(mView.getLeft(), mView.getTop()); 8920 Rect rect = new Rect(0, 0, mView.getWidth(), mView.getHeight()); 8921 targets.add(new ScrollCaptureTarget(mView, rect, offset, cb)); 8922 } 8923 } 8924 8925 /** 8926 * Handles an inbound request for scroll capture from the system. If a client is not already 8927 * active, a search will be dispatched through the view tree to locate scrolling content. 8928 * <p> 8929 * Either {@link IScrollCaptureController#onClientConnected(IScrollCaptureClient, Rect, 8930 * Point)} or {@link IScrollCaptureController#onClientUnavailable()} will be returned 8931 * depending on the results of the search. 8932 * 8933 * @param controller the interface to the system controller 8934 * @see ScrollCaptureTargetResolver 8935 */ handleScrollCaptureRequest(@onNull IScrollCaptureController controller)8936 private void handleScrollCaptureRequest(@NonNull IScrollCaptureController controller) { 8937 LinkedList<ScrollCaptureTarget> targetList = new LinkedList<>(); 8938 8939 // Window (root) level callbacks 8940 collectRootScrollCaptureTargets(targetList); 8941 8942 // Search through View-tree 8943 View rootView = getView(); 8944 Point point = new Point(); 8945 Rect rect = new Rect(0, 0, rootView.getWidth(), rootView.getHeight()); 8946 getChildVisibleRect(rootView, rect, point); 8947 rootView.dispatchScrollCaptureSearch(rect, point, targetList); 8948 8949 // No-op path. Scroll capture not offered for this window. 8950 if (targetList.isEmpty()) { 8951 dispatchScrollCaptureSearchResult(controller, null); 8952 return; 8953 } 8954 8955 // Request scrollBounds from each of the targets. 8956 // Continues with the consumer once all responses are consumed, or the timeout expires. 8957 ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(targetList); 8958 resolver.start(mHandler, 1000, 8959 (selected) -> dispatchScrollCaptureSearchResult(controller, selected)); 8960 } 8961 8962 /** Called by {@link #handleScrollCaptureRequest} when a result is returned */ dispatchScrollCaptureSearchResult( @onNull IScrollCaptureController controller, @Nullable ScrollCaptureTarget selectedTarget)8963 private void dispatchScrollCaptureSearchResult( 8964 @NonNull IScrollCaptureController controller, 8965 @Nullable ScrollCaptureTarget selectedTarget) { 8966 8967 // If timeout or no eligible targets found. 8968 if (selectedTarget == null) { 8969 try { 8970 if (DEBUG_SCROLL_CAPTURE) { 8971 Log.d(TAG, "scrollCaptureSearch returned no targets available."); 8972 } 8973 controller.onClientUnavailable(); 8974 } catch (RemoteException e) { 8975 if (DEBUG_SCROLL_CAPTURE) { 8976 Log.w(TAG, "Failed to notify controller of scroll capture search result.", e); 8977 } 8978 } 8979 return; 8980 } 8981 8982 // Create a client instance and return it to the caller 8983 mScrollCaptureClient = new ScrollCaptureClient(selectedTarget, controller); 8984 try { 8985 if (DEBUG_SCROLL_CAPTURE) { 8986 Log.d(TAG, "scrollCaptureSearch returning client: " + getScrollCaptureClient()); 8987 } 8988 controller.onClientConnected( 8989 mScrollCaptureClient, 8990 selectedTarget.getScrollBounds(), 8991 selectedTarget.getPositionInWindow()); 8992 } catch (RemoteException e) { 8993 if (DEBUG_SCROLL_CAPTURE) { 8994 Log.w(TAG, "Failed to notify controller of scroll capture search result.", e); 8995 } 8996 mScrollCaptureClient.disconnect(); 8997 mScrollCaptureClient = null; 8998 } 8999 } 9000 reportNextDraw()9001 private void reportNextDraw() { 9002 if (mReportNextDraw == false) { 9003 drawPending(); 9004 } 9005 mReportNextDraw = true; 9006 } 9007 9008 /** 9009 * Force the window to report its next draw. 9010 * <p> 9011 * This method is only supposed to be used to speed up the interaction from SystemUI and window 9012 * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE 9013 * unless you fully understand this interaction. 9014 * @hide 9015 */ setReportNextDraw()9016 public void setReportNextDraw() { 9017 reportNextDraw(); 9018 invalidate(); 9019 } 9020 changeCanvasOpacity(boolean opaque)9021 void changeCanvasOpacity(boolean opaque) { 9022 Log.d(mTag, "changeCanvasOpacity: opaque=" + opaque); 9023 opaque = opaque & ((mView.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0); 9024 if (mAttachInfo.mThreadedRenderer != null) { 9025 mAttachInfo.mThreadedRenderer.setOpaque(opaque); 9026 } 9027 } 9028 9029 /** 9030 * Dispatches a KeyEvent to all registered key fallback handlers. 9031 * 9032 * @param event 9033 * @return {@code true} if the event was handled, {@code false} otherwise. 9034 */ dispatchUnhandledKeyEvent(KeyEvent event)9035 public boolean dispatchUnhandledKeyEvent(KeyEvent event) { 9036 return mUnhandledKeyManager.dispatch(mView, event); 9037 } 9038 9039 class TakenSurfaceHolder extends BaseSurfaceHolder { 9040 @Override onAllowLockCanvas()9041 public boolean onAllowLockCanvas() { 9042 return mDrawingAllowed; 9043 } 9044 9045 @Override onRelayoutContainer()9046 public void onRelayoutContainer() { 9047 // Not currently interesting -- from changing between fixed and layout size. 9048 } 9049 9050 @Override setFormat(int format)9051 public void setFormat(int format) { 9052 ((RootViewSurfaceTaker)mView).setSurfaceFormat(format); 9053 } 9054 9055 @Override setType(int type)9056 public void setType(int type) { 9057 ((RootViewSurfaceTaker)mView).setSurfaceType(type); 9058 } 9059 9060 @Override onUpdateSurface()9061 public void onUpdateSurface() { 9062 // We take care of format and type changes on our own. 9063 throw new IllegalStateException("Shouldn't be here"); 9064 } 9065 9066 @Override isCreating()9067 public boolean isCreating() { 9068 return mIsCreating; 9069 } 9070 9071 @Override setFixedSize(int width, int height)9072 public void setFixedSize(int width, int height) { 9073 throw new UnsupportedOperationException( 9074 "Currently only support sizing from layout"); 9075 } 9076 9077 @Override setKeepScreenOn(boolean screenOn)9078 public void setKeepScreenOn(boolean screenOn) { 9079 ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn); 9080 } 9081 } 9082 9083 static class W extends IWindow.Stub { 9084 private final WeakReference<ViewRootImpl> mViewAncestor; 9085 private final IWindowSession mWindowSession; 9086 W(ViewRootImpl viewAncestor)9087 W(ViewRootImpl viewAncestor) { 9088 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor); 9089 mWindowSession = viewAncestor.mWindowSession; 9090 } 9091 9092 @Override resized(Rect frame, Rect contentInsets, Rect visibleInsets, Rect stableInsets, boolean reportDraw, MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, DisplayCutout.ParcelableWrapper displayCutout)9093 public void resized(Rect frame, Rect contentInsets, 9094 Rect visibleInsets, Rect stableInsets, boolean reportDraw, 9095 MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout, 9096 boolean alwaysConsumeSystemBars, int displayId, 9097 DisplayCutout.ParcelableWrapper displayCutout) { 9098 final ViewRootImpl viewAncestor = mViewAncestor.get(); 9099 if (viewAncestor != null) { 9100 viewAncestor.dispatchResized(frame, contentInsets, 9101 visibleInsets, stableInsets, reportDraw, mergedConfiguration, 9102 backDropFrame, forceLayout, alwaysConsumeSystemBars, displayId, 9103 displayCutout); 9104 } 9105 } 9106 9107 @Override locationInParentDisplayChanged(Point offset)9108 public void locationInParentDisplayChanged(Point offset) { 9109 final ViewRootImpl viewAncestor = mViewAncestor.get(); 9110 if (viewAncestor != null) { 9111 viewAncestor.dispatchLocationInParentDisplayChanged(offset); 9112 } 9113 } 9114 9115 @Override insetsChanged(InsetsState insetsState)9116 public void insetsChanged(InsetsState insetsState) { 9117 final ViewRootImpl viewAncestor = mViewAncestor.get(); 9118 if (viewAncestor != null) { 9119 viewAncestor.dispatchInsetsChanged(insetsState); 9120 } 9121 } 9122 9123 @Override insetsControlChanged(InsetsState insetsState, InsetsSourceControl[] activeControls)9124 public void insetsControlChanged(InsetsState insetsState, 9125 InsetsSourceControl[] activeControls) { 9126 final ViewRootImpl viewAncestor = mViewAncestor.get(); 9127 if (viewAncestor != null) { 9128 viewAncestor.dispatchInsetsControlChanged(insetsState, activeControls); 9129 } 9130 } 9131 9132 @Override showInsets(@nsetsType int types, boolean fromIme)9133 public void showInsets(@InsetsType int types, boolean fromIme) { 9134 final ViewRootImpl viewAncestor = mViewAncestor.get(); 9135 if (viewAncestor != null) { 9136 viewAncestor.showInsets(types, fromIme); 9137 } 9138 } 9139 9140 @Override hideInsets(@nsetsType int types, boolean fromIme)9141 public void hideInsets(@InsetsType int types, boolean fromIme) { 9142 final ViewRootImpl viewAncestor = mViewAncestor.get(); 9143 if (viewAncestor != null) { 9144 viewAncestor.hideInsets(types, fromIme); 9145 } 9146 } 9147 9148 @Override moved(int newX, int newY)9149 public void moved(int newX, int newY) { 9150 final ViewRootImpl viewAncestor = mViewAncestor.get(); 9151 if (viewAncestor != null) { 9152 viewAncestor.dispatchMoved(newX, newY); 9153 } 9154 } 9155 9156 @Override dispatchAppVisibility(boolean visible)9157 public void dispatchAppVisibility(boolean visible) { 9158 final ViewRootImpl viewAncestor = mViewAncestor.get(); 9159 if (viewAncestor != null) { 9160 viewAncestor.dispatchAppVisibility(visible); 9161 } 9162 } 9163 9164 @Override dispatchGetNewSurface()9165 public void dispatchGetNewSurface() { 9166 final ViewRootImpl viewAncestor = mViewAncestor.get(); 9167 if (viewAncestor != null) { 9168 viewAncestor.dispatchGetNewSurface(); 9169 } 9170 } 9171 9172 @Override windowFocusChanged(boolean hasFocus, boolean inTouchMode)9173 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) { 9174 final ViewRootImpl viewAncestor = mViewAncestor.get(); 9175 if (viewAncestor != null) { 9176 viewAncestor.windowFocusChanged(hasFocus, inTouchMode); 9177 } 9178 } 9179 checkCallingPermission(String permission)9180 private static int checkCallingPermission(String permission) { 9181 try { 9182 return ActivityManager.getService().checkPermission( 9183 permission, Binder.getCallingPid(), Binder.getCallingUid()); 9184 } catch (RemoteException e) { 9185 return PackageManager.PERMISSION_DENIED; 9186 } 9187 } 9188 9189 @Override executeCommand(String command, String parameters, ParcelFileDescriptor out)9190 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) { 9191 final ViewRootImpl viewAncestor = mViewAncestor.get(); 9192 if (viewAncestor != null) { 9193 final View view = viewAncestor.mView; 9194 if (view != null) { 9195 if (checkCallingPermission(Manifest.permission.DUMP) != 9196 PackageManager.PERMISSION_GRANTED) { 9197 throw new SecurityException("Insufficient permissions to invoke" 9198 + " executeCommand() from pid=" + Binder.getCallingPid() 9199 + ", uid=" + Binder.getCallingUid()); 9200 } 9201 9202 OutputStream clientStream = null; 9203 try { 9204 clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out); 9205 ViewDebug.dispatchCommand(view, command, parameters, clientStream); 9206 } catch (IOException e) { 9207 e.printStackTrace(); 9208 } finally { 9209 if (clientStream != null) { 9210 try { 9211 clientStream.close(); 9212 } catch (IOException e) { 9213 e.printStackTrace(); 9214 } 9215 } 9216 } 9217 } 9218 } 9219 } 9220 9221 @Override closeSystemDialogs(String reason)9222 public void closeSystemDialogs(String reason) { 9223 final ViewRootImpl viewAncestor = mViewAncestor.get(); 9224 if (viewAncestor != null) { 9225 viewAncestor.dispatchCloseSystemDialogs(reason); 9226 } 9227 } 9228 9229 @Override dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, float zoom, boolean sync)9230 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, 9231 float zoom, boolean sync) { 9232 if (sync) { 9233 try { 9234 mWindowSession.wallpaperOffsetsComplete(asBinder()); 9235 } catch (RemoteException e) { 9236 } 9237 } 9238 } 9239 9240 @Override dispatchWallpaperCommand(String action, int x, int y, int z, Bundle extras, boolean sync)9241 public void dispatchWallpaperCommand(String action, int x, int y, 9242 int z, Bundle extras, boolean sync) { 9243 if (sync) { 9244 try { 9245 mWindowSession.wallpaperCommandComplete(asBinder(), null); 9246 } catch (RemoteException e) { 9247 } 9248 } 9249 } 9250 9251 /* Drag/drop */ 9252 @Override dispatchDragEvent(DragEvent event)9253 public void dispatchDragEvent(DragEvent event) { 9254 final ViewRootImpl viewAncestor = mViewAncestor.get(); 9255 if (viewAncestor != null) { 9256 viewAncestor.dispatchDragEvent(event); 9257 } 9258 } 9259 9260 @Override updatePointerIcon(float x, float y)9261 public void updatePointerIcon(float x, float y) { 9262 final ViewRootImpl viewAncestor = mViewAncestor.get(); 9263 if (viewAncestor != null) { 9264 viewAncestor.updatePointerIcon(x, y); 9265 } 9266 } 9267 9268 @Override dispatchSystemUiVisibilityChanged(int seq, int globalVisibility, int localValue, int localChanges)9269 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility, 9270 int localValue, int localChanges) { 9271 final ViewRootImpl viewAncestor = mViewAncestor.get(); 9272 if (viewAncestor != null) { 9273 viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility, 9274 localValue, localChanges); 9275 } 9276 } 9277 9278 @Override dispatchWindowShown()9279 public void dispatchWindowShown() { 9280 final ViewRootImpl viewAncestor = mViewAncestor.get(); 9281 if (viewAncestor != null) { 9282 viewAncestor.dispatchWindowShown(); 9283 } 9284 } 9285 9286 @Override requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId)9287 public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) { 9288 ViewRootImpl viewAncestor = mViewAncestor.get(); 9289 if (viewAncestor != null) { 9290 viewAncestor.dispatchRequestKeyboardShortcuts(receiver, deviceId); 9291 } 9292 } 9293 9294 @Override dispatchPointerCaptureChanged(boolean hasCapture)9295 public void dispatchPointerCaptureChanged(boolean hasCapture) { 9296 final ViewRootImpl viewAncestor = mViewAncestor.get(); 9297 if (viewAncestor != null) { 9298 viewAncestor.dispatchPointerCaptureChanged(hasCapture); 9299 } 9300 } 9301 9302 @Override requestScrollCapture(IScrollCaptureController controller)9303 public void requestScrollCapture(IScrollCaptureController controller) { 9304 final ViewRootImpl viewAncestor = mViewAncestor.get(); 9305 if (viewAncestor != null) { 9306 viewAncestor.dispatchScrollCaptureRequest(controller); 9307 } 9308 } 9309 } 9310 9311 public static final class CalledFromWrongThreadException extends AndroidRuntimeException { 9312 @UnsupportedAppUsage CalledFromWrongThreadException(String msg)9313 public CalledFromWrongThreadException(String msg) { 9314 super(msg); 9315 } 9316 } 9317 getRunQueue()9318 static HandlerActionQueue getRunQueue() { 9319 HandlerActionQueue rq = sRunQueues.get(); 9320 if (rq != null) { 9321 return rq; 9322 } 9323 rq = new HandlerActionQueue(); 9324 sRunQueues.set(rq); 9325 return rq; 9326 } 9327 9328 /** 9329 * Start a drag resizing which will inform all listeners that a window resize is taking place. 9330 */ startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets, Rect stableInsets, int resizeMode)9331 private void startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets, 9332 Rect stableInsets, int resizeMode) { 9333 if (!mDragResizing) { 9334 mDragResizing = true; 9335 if (mUseMTRenderer) { 9336 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { 9337 mWindowCallbacks.get(i).onWindowDragResizeStart( 9338 initialBounds, fullscreen, systemInsets, stableInsets, resizeMode); 9339 } 9340 } 9341 mFullRedrawNeeded = true; 9342 } 9343 } 9344 9345 /** 9346 * End a drag resize which will inform all listeners that a window resize has ended. 9347 */ endDragResizing()9348 private void endDragResizing() { 9349 if (mDragResizing) { 9350 mDragResizing = false; 9351 if (mUseMTRenderer) { 9352 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { 9353 mWindowCallbacks.get(i).onWindowDragResizeEnd(); 9354 } 9355 } 9356 mFullRedrawNeeded = true; 9357 } 9358 } 9359 updateContentDrawBounds()9360 private boolean updateContentDrawBounds() { 9361 boolean updated = false; 9362 if (mUseMTRenderer) { 9363 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { 9364 updated |= 9365 mWindowCallbacks.get(i).onContentDrawn(mWindowAttributes.surfaceInsets.left, 9366 mWindowAttributes.surfaceInsets.top, mWidth, mHeight); 9367 } 9368 } 9369 return updated | (mDragResizing && mReportNextDraw); 9370 } 9371 requestDrawWindow()9372 private void requestDrawWindow() { 9373 if (!mUseMTRenderer) { 9374 return; 9375 } 9376 mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size()); 9377 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { 9378 mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw); 9379 } 9380 } 9381 9382 /** 9383 * Tells this instance that its corresponding activity has just relaunched. In this case, we 9384 * need to force a relayout of the window to make sure we get the correct bounds from window 9385 * manager. 9386 */ reportActivityRelaunched()9387 public void reportActivityRelaunched() { 9388 mActivityRelaunched = true; 9389 } 9390 getSurfaceControl()9391 public SurfaceControl getSurfaceControl() { 9392 return mSurfaceControl; 9393 } 9394 9395 /** 9396 * @return Returns a token used to identify the windows input channel. 9397 */ getInputToken()9398 public IBinder getInputToken() { 9399 if (mInputEventReceiver == null) { 9400 return null; 9401 } 9402 return mInputEventReceiver.getToken(); 9403 } 9404 9405 @NonNull getWindowToken()9406 public IBinder getWindowToken() { 9407 return mAttachInfo.mWindowToken; 9408 } 9409 9410 /** 9411 * Class for managing the accessibility interaction connection 9412 * based on the global accessibility state. 9413 */ 9414 final class AccessibilityInteractionConnectionManager 9415 implements AccessibilityStateChangeListener { 9416 @Override onAccessibilityStateChanged(boolean enabled)9417 public void onAccessibilityStateChanged(boolean enabled) { 9418 if (enabled) { 9419 ensureConnection(); 9420 if (mAttachInfo.mHasWindowFocus && (mView != null)) { 9421 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 9422 View focusedView = mView.findFocus(); 9423 if (focusedView != null && focusedView != mView) { 9424 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 9425 } 9426 } 9427 if (mAttachInfo.mLeashedParentToken != null) { 9428 mAccessibilityManager.associateEmbeddedHierarchy( 9429 mAttachInfo.mLeashedParentToken, mLeashToken); 9430 } 9431 } else { 9432 ensureNoConnection(); 9433 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget(); 9434 } 9435 } 9436 ensureConnection()9437 public void ensureConnection() { 9438 final boolean registered = mAttachInfo.mAccessibilityWindowId 9439 != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 9440 if (!registered) { 9441 mAttachInfo.mAccessibilityWindowId = 9442 mAccessibilityManager.addAccessibilityInteractionConnection(mWindow, 9443 mLeashToken, 9444 mContext.getPackageName(), 9445 new AccessibilityInteractionConnection(ViewRootImpl.this)); 9446 } 9447 } 9448 ensureNoConnection()9449 public void ensureNoConnection() { 9450 final boolean registered = mAttachInfo.mAccessibilityWindowId 9451 != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 9452 if (registered) { 9453 mAttachInfo.mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 9454 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow); 9455 } 9456 } 9457 } 9458 9459 final class HighContrastTextManager implements HighTextContrastChangeListener { HighContrastTextManager()9460 HighContrastTextManager() { 9461 ThreadedRenderer.setHighContrastText(mAccessibilityManager.isHighTextContrastEnabled()); 9462 } 9463 @Override onHighTextContrastStateChanged(boolean enabled)9464 public void onHighTextContrastStateChanged(boolean enabled) { 9465 ThreadedRenderer.setHighContrastText(enabled); 9466 9467 // Destroy Displaylists so they can be recreated with high contrast recordings 9468 destroyHardwareResources(); 9469 9470 // Schedule redraw, which will rerecord + redraw all text 9471 invalidate(); 9472 } 9473 } 9474 9475 /** 9476 * This class is an interface this ViewAncestor provides to the 9477 * AccessibilityManagerService to the latter can interact with 9478 * the view hierarchy in this ViewAncestor. 9479 */ 9480 static final class AccessibilityInteractionConnection 9481 extends IAccessibilityInteractionConnection.Stub { 9482 private final WeakReference<ViewRootImpl> mViewRootImpl; 9483 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl)9484 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) { 9485 mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl); 9486 } 9487 9488 @Override findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, Bundle args)9489 public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, 9490 Region interactiveRegion, int interactionId, 9491 IAccessibilityInteractionConnectionCallback callback, int flags, 9492 int interrogatingPid, long interrogatingTid, MagnificationSpec spec, Bundle args) { 9493 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 9494 if (viewRootImpl != null && viewRootImpl.mView != null) { 9495 viewRootImpl.getAccessibilityInteractionController() 9496 .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId, 9497 interactiveRegion, interactionId, callback, flags, interrogatingPid, 9498 interrogatingTid, spec, args); 9499 } else { 9500 // We cannot make the call and notify the caller so it does not wait. 9501 try { 9502 callback.setFindAccessibilityNodeInfosResult(null, interactionId); 9503 } catch (RemoteException re) { 9504 /* best effort - ignore */ 9505 } 9506 } 9507 } 9508 9509 @Override performAccessibilityAction(long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid)9510 public void performAccessibilityAction(long accessibilityNodeId, int action, 9511 Bundle arguments, int interactionId, 9512 IAccessibilityInteractionConnectionCallback callback, int flags, 9513 int interrogatingPid, long interrogatingTid) { 9514 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 9515 if (viewRootImpl != null && viewRootImpl.mView != null) { 9516 viewRootImpl.getAccessibilityInteractionController() 9517 .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments, 9518 interactionId, callback, flags, interrogatingPid, interrogatingTid); 9519 } else { 9520 // We cannot make the call and notify the caller so it does not wait. 9521 try { 9522 callback.setPerformAccessibilityActionResult(false, interactionId); 9523 } catch (RemoteException re) { 9524 /* best effort - ignore */ 9525 } 9526 } 9527 } 9528 9529 @Override findAccessibilityNodeInfosByViewId(long accessibilityNodeId, String viewId, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec)9530 public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId, 9531 String viewId, Region interactiveRegion, int interactionId, 9532 IAccessibilityInteractionConnectionCallback callback, int flags, 9533 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { 9534 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 9535 if (viewRootImpl != null && viewRootImpl.mView != null) { 9536 viewRootImpl.getAccessibilityInteractionController() 9537 .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId, 9538 viewId, interactiveRegion, interactionId, callback, flags, 9539 interrogatingPid, interrogatingTid, spec); 9540 } else { 9541 // We cannot make the call and notify the caller so it does not wait. 9542 try { 9543 callback.setFindAccessibilityNodeInfoResult(null, interactionId); 9544 } catch (RemoteException re) { 9545 /* best effort - ignore */ 9546 } 9547 } 9548 } 9549 9550 @Override findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec)9551 public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, 9552 Region interactiveRegion, int interactionId, 9553 IAccessibilityInteractionConnectionCallback callback, int flags, 9554 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { 9555 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 9556 if (viewRootImpl != null && viewRootImpl.mView != null) { 9557 viewRootImpl.getAccessibilityInteractionController() 9558 .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text, 9559 interactiveRegion, interactionId, callback, flags, interrogatingPid, 9560 interrogatingTid, spec); 9561 } else { 9562 // We cannot make the call and notify the caller so it does not wait. 9563 try { 9564 callback.setFindAccessibilityNodeInfosResult(null, interactionId); 9565 } catch (RemoteException re) { 9566 /* best effort - ignore */ 9567 } 9568 } 9569 } 9570 9571 @Override findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec)9572 public void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion, 9573 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, 9574 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { 9575 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 9576 if (viewRootImpl != null && viewRootImpl.mView != null) { 9577 viewRootImpl.getAccessibilityInteractionController() 9578 .findFocusClientThread(accessibilityNodeId, focusType, interactiveRegion, 9579 interactionId, callback, flags, interrogatingPid, interrogatingTid, 9580 spec); 9581 } else { 9582 // We cannot make the call and notify the caller so it does not wait. 9583 try { 9584 callback.setFindAccessibilityNodeInfoResult(null, interactionId); 9585 } catch (RemoteException re) { 9586 /* best effort - ignore */ 9587 } 9588 } 9589 } 9590 9591 @Override focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec)9592 public void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion, 9593 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, 9594 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { 9595 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 9596 if (viewRootImpl != null && viewRootImpl.mView != null) { 9597 viewRootImpl.getAccessibilityInteractionController() 9598 .focusSearchClientThread(accessibilityNodeId, direction, interactiveRegion, 9599 interactionId, callback, flags, interrogatingPid, interrogatingTid, 9600 spec); 9601 } else { 9602 // We cannot make the call and notify the caller so it does not wait. 9603 try { 9604 callback.setFindAccessibilityNodeInfoResult(null, interactionId); 9605 } catch (RemoteException re) { 9606 /* best effort - ignore */ 9607 } 9608 } 9609 } 9610 9611 @Override clearAccessibilityFocus()9612 public void clearAccessibilityFocus() { 9613 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 9614 if (viewRootImpl != null && viewRootImpl.mView != null) { 9615 viewRootImpl.getAccessibilityInteractionController() 9616 .clearAccessibilityFocusClientThread(); 9617 } 9618 } 9619 9620 @Override notifyOutsideTouch()9621 public void notifyOutsideTouch() { 9622 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 9623 if (viewRootImpl != null && viewRootImpl.mView != null) { 9624 viewRootImpl.getAccessibilityInteractionController() 9625 .notifyOutsideTouchClientThread(); 9626 } 9627 } 9628 } 9629 9630 /** 9631 * Gets an accessibility embedded connection interface for this ViewRootImpl. 9632 * @hide 9633 */ getAccessibilityEmbeddedConnection()9634 public IAccessibilityEmbeddedConnection getAccessibilityEmbeddedConnection() { 9635 if (mAccessibilityEmbeddedConnection == null) { 9636 mAccessibilityEmbeddedConnection = new AccessibilityEmbeddedConnection( 9637 ViewRootImpl.this); 9638 } 9639 return mAccessibilityEmbeddedConnection; 9640 } 9641 9642 private class SendWindowContentChangedAccessibilityEvent implements Runnable { 9643 private int mChangeTypes = 0; 9644 9645 public View mSource; 9646 public long mLastEventTimeMillis; 9647 /** 9648 * Override for {@link AccessibilityEvent#originStackTrace} to provide the stack trace 9649 * of the original {@link #runOrPost} call instead of one for sending the delayed event 9650 * from a looper. 9651 */ 9652 public StackTraceElement[] mOrigin; 9653 9654 @Override run()9655 public void run() { 9656 // Protect against re-entrant code and attempt to do the right thing in the case that 9657 // we're multithreaded. 9658 View source = mSource; 9659 mSource = null; 9660 if (source == null) { 9661 Log.e(TAG, "Accessibility content change has no source"); 9662 return; 9663 } 9664 // The accessibility may be turned off while we were waiting so check again. 9665 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 9666 mLastEventTimeMillis = SystemClock.uptimeMillis(); 9667 AccessibilityEvent event = AccessibilityEvent.obtain(); 9668 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 9669 event.setContentChangeTypes(mChangeTypes); 9670 if (AccessibilityEvent.DEBUG_ORIGIN) event.originStackTrace = mOrigin; 9671 source.sendAccessibilityEventUnchecked(event); 9672 } else { 9673 mLastEventTimeMillis = 0; 9674 } 9675 // In any case reset to initial state. 9676 source.resetSubtreeAccessibilityStateChanged(); 9677 mChangeTypes = 0; 9678 if (AccessibilityEvent.DEBUG_ORIGIN) mOrigin = null; 9679 } 9680 runOrPost(View source, int changeType)9681 public void runOrPost(View source, int changeType) { 9682 if (mHandler.getLooper() != Looper.myLooper()) { 9683 CalledFromWrongThreadException e = new CalledFromWrongThreadException("Only the " 9684 + "original thread that created a view hierarchy can touch its views."); 9685 // TODO: Throw the exception 9686 Log.e(TAG, "Accessibility content change on non-UI thread. Future Android " 9687 + "versions will throw an exception.", e); 9688 // Attempt to recover. This code does not eliminate the thread safety issue, but 9689 // it should force any issues to happen near the above log. 9690 mHandler.removeCallbacks(this); 9691 if (mSource != null) { 9692 // Dispatch whatever was pending. It's still possible that the runnable started 9693 // just before we removed the callbacks, and bad things will happen, but at 9694 // least they should happen very close to the logged error. 9695 run(); 9696 } 9697 } 9698 if (mSource != null) { 9699 // If there is no common predecessor, then mSource points to 9700 // a removed view, hence in this case always prefer the source. 9701 View predecessor = getCommonPredecessor(mSource, source); 9702 if (predecessor != null) { 9703 predecessor = predecessor.getSelfOrParentImportantForA11y(); 9704 } 9705 mSource = (predecessor != null) ? predecessor : source; 9706 mChangeTypes |= changeType; 9707 return; 9708 } 9709 mSource = source; 9710 mChangeTypes = changeType; 9711 if (AccessibilityEvent.DEBUG_ORIGIN) { 9712 mOrigin = Thread.currentThread().getStackTrace(); 9713 } 9714 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis; 9715 final long minEventIntevalMillis = 9716 ViewConfiguration.getSendRecurringAccessibilityEventsInterval(); 9717 if (timeSinceLastMillis >= minEventIntevalMillis) { 9718 removeCallbacksAndRun(); 9719 } else { 9720 mHandler.postDelayed(this, minEventIntevalMillis - timeSinceLastMillis); 9721 } 9722 } 9723 removeCallbacksAndRun()9724 public void removeCallbacksAndRun() { 9725 mHandler.removeCallbacks(this); 9726 run(); 9727 } 9728 } 9729 9730 private static class UnhandledKeyManager { 9731 // This is used to ensure that unhandled events are only dispatched once. We attempt 9732 // to dispatch more than once in order to achieve a certain order. Specifically, if we 9733 // are in an Activity or Dialog (and have a Window.Callback), the unhandled events should 9734 // be dispatched after the view hierarchy, but before the Callback. However, if we aren't 9735 // in an activity, we still want unhandled keys to be dispatched. 9736 private boolean mDispatched = true; 9737 9738 // Keeps track of which Views have unhandled key focus for which keys. This doesn't 9739 // include modifiers. 9740 private final SparseArray<WeakReference<View>> mCapturedKeys = new SparseArray<>(); 9741 9742 // The current receiver. This value is transient and used between the pre-dispatch and 9743 // pre-view phase to ensure that other input-stages don't interfere with tracking. 9744 private WeakReference<View> mCurrentReceiver = null; 9745 dispatch(View root, KeyEvent event)9746 boolean dispatch(View root, KeyEvent event) { 9747 if (mDispatched) { 9748 return false; 9749 } 9750 View consumer; 9751 try { 9752 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "UnhandledKeyEvent dispatch"); 9753 mDispatched = true; 9754 9755 consumer = root.dispatchUnhandledKeyEvent(event); 9756 9757 // If an unhandled listener handles one, then keep track of it so that the 9758 // consuming view is first to receive its repeats and release as well. 9759 if (event.getAction() == KeyEvent.ACTION_DOWN) { 9760 int keycode = event.getKeyCode(); 9761 if (consumer != null && !KeyEvent.isModifierKey(keycode)) { 9762 mCapturedKeys.put(keycode, new WeakReference<>(consumer)); 9763 } 9764 } 9765 } finally { 9766 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 9767 } 9768 return consumer != null; 9769 } 9770 9771 /** 9772 * Called before the event gets dispatched to anything 9773 */ preDispatch(KeyEvent event)9774 void preDispatch(KeyEvent event) { 9775 // Always clean-up 'up' events since it's possible for earlier dispatch stages to 9776 // consume them without consuming the corresponding 'down' event. 9777 mCurrentReceiver = null; 9778 if (event.getAction() == KeyEvent.ACTION_UP) { 9779 int idx = mCapturedKeys.indexOfKey(event.getKeyCode()); 9780 if (idx >= 0) { 9781 mCurrentReceiver = mCapturedKeys.valueAt(idx); 9782 mCapturedKeys.removeAt(idx); 9783 } 9784 } 9785 } 9786 9787 /** 9788 * Called before the event gets dispatched to the view hierarchy 9789 * @return {@code true} if an unhandled handler has focus and consumed the event 9790 */ preViewDispatch(KeyEvent event)9791 boolean preViewDispatch(KeyEvent event) { 9792 mDispatched = false; 9793 if (mCurrentReceiver == null) { 9794 mCurrentReceiver = mCapturedKeys.get(event.getKeyCode()); 9795 } 9796 if (mCurrentReceiver != null) { 9797 View target = mCurrentReceiver.get(); 9798 if (event.getAction() == KeyEvent.ACTION_UP) { 9799 mCurrentReceiver = null; 9800 } 9801 if (target != null && target.isAttachedToWindow()) { 9802 target.onUnhandledKeyEvent(event); 9803 } 9804 // consume anyways so that we don't feed uncaptured key events to other views 9805 return true; 9806 } 9807 return false; 9808 } 9809 } 9810 setUseBLASTSyncTransaction()9811 void setUseBLASTSyncTransaction() { 9812 mNextDrawUseBLASTSyncTransaction = true; 9813 } 9814 finishBLASTSync(boolean apply)9815 private void finishBLASTSync(boolean apply) { 9816 mSendNextFrameToWm = false; 9817 if (mNextReportConsumeBLAST) { 9818 mNextReportConsumeBLAST = false; 9819 9820 if (apply) { 9821 mRtBLASTSyncTransaction.apply(); 9822 } else { 9823 mSurfaceChangedTransaction.merge(mRtBLASTSyncTransaction); 9824 } 9825 } 9826 } 9827 getBLASTSyncTransaction()9828 SurfaceControl.Transaction getBLASTSyncTransaction() { 9829 return mRtBLASTSyncTransaction; 9830 } 9831 9832 /** 9833 * @hide 9834 */ getRenderSurfaceControl()9835 public SurfaceControl getRenderSurfaceControl() { 9836 if (useBLAST()) { 9837 return mBlastSurfaceControl; 9838 } else { 9839 return mSurfaceControl; 9840 } 9841 } 9842 9843 @Override onDescendantUnbufferedRequested()9844 public void onDescendantUnbufferedRequested() { 9845 mUnbufferedInputSource = mView.mUnbufferedInputSource; 9846 } 9847 9848 /** 9849 * Force disabling use of the BLAST adapter regardless of the system 9850 * flag. Needs to be called before addView. 9851 */ forceDisableBLAST()9852 void forceDisableBLAST() { 9853 mForceDisableBLAST = true; 9854 } 9855 useBLAST()9856 boolean useBLAST() { 9857 return mUseBLASTAdapter && !mForceDisableBLAST; 9858 } 9859 9860 /** 9861 * Returns true if we are about to or currently processing a draw directed 9862 * in to a BLAST transaction. 9863 */ isDrawingToBLASTTransaction()9864 boolean isDrawingToBLASTTransaction() { 9865 return mNextReportConsumeBLAST; 9866 } 9867 } 9868