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