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