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