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