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.adpf.Flags.adpfViewrootimplActionDownBoost; 20 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; 22 import static android.content.pm.ActivityInfo.OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS; 23 import static android.graphics.HardwareRenderer.SYNC_CONTEXT_IS_STOPPED; 24 import static android.graphics.HardwareRenderer.SYNC_LOST_SURFACE_REWARD_IF_FOUND; 25 import static android.os.IInputConstants.INVALID_INPUT_EVENT_ID; 26 import static android.os.Trace.TRACE_TAG_VIEW; 27 import static android.util.SequenceUtils.getInitSeq; 28 import static android.util.SequenceUtils.isIncomingSeqStale; 29 import static android.view.Display.DEFAULT_DISPLAY; 30 import static android.view.Display.INVALID_DISPLAY; 31 import static android.view.DragEvent.ACTION_DRAG_LOCATION; 32 import static android.view.InputDevice.SOURCE_CLASS_NONE; 33 import static android.view.InsetsSource.ID_IME; 34 import static android.view.Surface.FRAME_RATE_CATEGORY_DEFAULT; 35 import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH; 36 import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH_HINT; 37 import static android.view.Surface.FRAME_RATE_CATEGORY_LOW; 38 import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL; 39 import static android.view.Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE; 40 import static android.view.Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; 41 import static android.view.Surface.FRAME_RATE_COMPATIBILITY_AT_LEAST; 42 import static android.view.View.FRAME_RATE_CATEGORY_REASON_BOOST; 43 import static android.view.View.FRAME_RATE_CATEGORY_REASON_CONFLICTED; 44 import static android.view.View.FRAME_RATE_CATEGORY_REASON_INTERMITTENT; 45 import static android.view.View.FRAME_RATE_CATEGORY_REASON_INVALID; 46 import static android.view.View.FRAME_RATE_CATEGORY_REASON_LARGE; 47 import static android.view.View.FRAME_RATE_CATEGORY_REASON_REQUESTED; 48 import static android.view.View.FRAME_RATE_CATEGORY_REASON_SMALL; 49 import static android.view.View.FRAME_RATE_CATEGORY_REASON_TOUCH; 50 import static android.view.View.FRAME_RATE_CATEGORY_REASON_UNKNOWN; 51 import static android.view.View.FRAME_RATE_CATEGORY_REASON_VELOCITY; 52 import static android.view.View.MAX_FRAME_RATE; 53 import static android.view.View.PFLAG_DRAW_ANIMATION; 54 import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN; 55 import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; 56 import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; 57 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 58 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; 59 import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; 60 import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; 61 import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE; 62 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; 63 import static android.view.ViewRootImplProto.ADDED; 64 import static android.view.ViewRootImplProto.APP_VISIBLE; 65 import static android.view.ViewRootImplProto.CUR_SCROLL_Y; 66 import static android.view.ViewRootImplProto.DISPLAY_ID; 67 import static android.view.ViewRootImplProto.HEIGHT; 68 import static android.view.ViewRootImplProto.IS_ANIMATING; 69 import static android.view.ViewRootImplProto.IS_DRAWING; 70 import static android.view.ViewRootImplProto.LAST_WINDOW_INSETS; 71 import static android.view.ViewRootImplProto.REMOVED; 72 import static android.view.ViewRootImplProto.SCROLL_Y; 73 import static android.view.ViewRootImplProto.SOFT_INPUT_MODE; 74 import static android.view.ViewRootImplProto.VIEW; 75 import static android.view.ViewRootImplProto.VISIBLE_RECT; 76 import static android.view.ViewRootImplProto.WIDTH; 77 import static android.view.ViewRootImplProto.WINDOW_ATTRIBUTES; 78 import static android.view.ViewRootImplProto.WIN_FRAME; 79 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; 80 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS; 81 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; 82 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; 83 import static android.view.WindowInsetsController.Appearance; 84 import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT; 85 import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; 86 import static android.view.WindowLayout.UNSPECIFIED_LENGTH; 87 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; 88 import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; 89 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 90 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; 91 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; 92 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; 93 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; 94 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; 95 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APP_PROGRESS_GENERATION_ALLOWED; 96 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EDGE_TO_EDGE_ENFORCED; 97 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FIT_INSETS_CONTROLLED; 98 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY; 99 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME; 100 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT; 101 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE; 102 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE; 103 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; 104 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; 105 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; 106 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; 107 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; 108 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; 109 import static android.view.WindowManager.LayoutParams.TYPE_TOAST; 110 import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY; 111 import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS; 112 import static android.view.WindowManagerGlobal.RELAYOUT_RES_CANCEL_AND_REDRAW; 113 import static android.view.WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS; 114 import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED; 115 import static android.view.accessibility.Flags.forceInvertColor; 116 import static android.view.accessibility.Flags.reduceWindowContentChangedEventThrottle; 117 import static android.view.flags.Flags.addSchandleToVriSurface; 118 import static android.view.flags.Flags.disableDrawWakeLock; 119 import static android.view.flags.Flags.sensitiveContentAppProtection; 120 import static android.view.flags.Flags.sensitiveContentPrematureProtectionRemovedFix; 121 import static android.view.flags.Flags.toolkitFrameRateDebug; 122 import static android.view.flags.Flags.toolkitFrameRateFunctionEnablingReadOnly; 123 import static android.view.flags.Flags.toolkitFrameRateTouchBoost25q1; 124 import static android.view.flags.Flags.toolkitFrameRateTypingReadOnly; 125 import static android.view.flags.Flags.toolkitFrameRateVelocityMappingReadOnly; 126 import static android.view.flags.Flags.toolkitFrameRateViewEnablingReadOnly; 127 import static android.view.flags.Flags.toolkitInitialTouchBoost; 128 import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision; 129 import static android.view.flags.Flags.toolkitSetFrameRateReadOnly; 130 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER; 131 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER; 132 import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION; 133 134 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; 135 import static com.android.text.flags.Flags.disableHandwritingInitiatorForIme; 136 import static com.android.window.flags.Flags.enableBufferTransformHintFromDisplay; 137 import static com.android.window.flags.Flags.enableWindowContextResourcesUpdateOnConfigChange; 138 import static com.android.window.flags.Flags.predictiveBackSwipeEdgeNoneApi; 139 import static com.android.window.flags.Flags.reduceChangedExclusionRectsMsgs; 140 import static com.android.window.flags.Flags.setScPropertiesInClient; 141 import static com.android.window.flags.Flags.fixViewRootCallTrace; 142 143 import android.Manifest; 144 import android.accessibilityservice.AccessibilityService; 145 import android.animation.AnimationHandler; 146 import android.animation.LayoutTransition; 147 import android.annotation.AnyThread; 148 import android.annotation.CallbackExecutor; 149 import android.annotation.FlaggedApi; 150 import android.annotation.NonNull; 151 import android.annotation.Nullable; 152 import android.annotation.Size; 153 import android.annotation.UiContext; 154 import android.app.ActivityManager; 155 import android.app.ActivityThread; 156 import android.app.ResourcesManager; 157 import android.app.UiModeManager; 158 import android.app.WindowConfiguration; 159 import android.app.compat.CompatChanges; 160 import android.app.servertransaction.WindowStateTransactionItem; 161 import android.compat.annotation.ChangeId; 162 import android.compat.annotation.EnabledSince; 163 import android.compat.annotation.UnsupportedAppUsage; 164 import android.content.ClipData; 165 import android.content.ClipDescription; 166 import android.content.Context; 167 import android.content.pm.ActivityInfo; 168 import android.content.pm.PackageManager; 169 import android.content.res.CompatibilityInfo; 170 import android.content.res.Configuration; 171 import android.content.res.Resources; 172 import android.content.res.TypedArray; 173 import android.database.ContentObserver; 174 import android.graphics.BLASTBufferQueue; 175 import android.graphics.Canvas; 176 import android.graphics.Color; 177 import android.graphics.ForceDarkType; 178 import android.graphics.FrameInfo; 179 import android.graphics.HardwareRenderer; 180 import android.graphics.HardwareRenderer.FrameDrawingCallback; 181 import android.graphics.HardwareRendererObserver; 182 import android.graphics.Matrix; 183 import android.graphics.Paint; 184 import android.graphics.PixelFormat; 185 import android.graphics.Point; 186 import android.graphics.PointF; 187 import android.graphics.PorterDuff; 188 import android.graphics.RecordingCanvas; 189 import android.graphics.Rect; 190 import android.graphics.RectF; 191 import android.graphics.Region; 192 import android.graphics.RenderNode; 193 import android.graphics.drawable.ColorDrawable; 194 import android.graphics.drawable.Drawable; 195 import android.graphics.drawable.GradientDrawable; 196 import android.hardware.SyncFence; 197 import android.hardware.display.DisplayManager.DisplayListener; 198 import android.hardware.display.DisplayManagerGlobal; 199 import android.hardware.input.InputManagerGlobal; 200 import android.hardware.input.InputSettings; 201 import android.media.AudioManager; 202 import android.net.Uri; 203 import android.os.Binder; 204 import android.os.Build; 205 import android.os.Bundle; 206 import android.os.Debug; 207 import android.os.Handler; 208 import android.os.IBinder; 209 import android.os.Looper; 210 import android.os.Message; 211 import android.os.ParcelFileDescriptor; 212 import android.os.Process; 213 import android.os.RemoteException; 214 import android.os.ServiceManager; 215 import android.os.StrictMode; 216 import android.os.SystemClock; 217 import android.os.SystemProperties; 218 import android.os.Trace; 219 import android.os.UserHandle; 220 import android.os.Vibrator; 221 import android.provider.Settings; 222 import android.sysprop.DisplayProperties; 223 import android.sysprop.ViewProperties; 224 import android.text.TextUtils; 225 import android.util.AndroidRuntimeException; 226 import android.util.DisplayMetrics; 227 import android.util.EventLog; 228 import android.util.IndentingPrintWriter; 229 import android.util.Log; 230 import android.util.LongArray; 231 import android.util.MergedConfiguration; 232 import android.util.Slog; 233 import android.util.SparseArray; 234 import android.util.TimeUtils; 235 import android.util.TypedValue; 236 import android.util.proto.ProtoOutputStream; 237 import android.view.InputDevice.InputSourceClass; 238 import android.view.Surface.OutOfResourcesException; 239 import android.view.SurfaceControl.Transaction; 240 import android.view.SurfaceControl.TransactionStats; 241 import android.view.View.AttachInfo; 242 import android.view.View.FocusDirection; 243 import android.view.View.MeasureSpec; 244 import android.view.Window.OnContentApplyWindowInsetsListener; 245 import android.view.WindowInsets.Type; 246 import android.view.WindowInsets.Type.InsetsType; 247 import android.view.WindowManager.LayoutParams.SoftInputModeFlags; 248 import android.view.accessibility.AccessibilityEvent; 249 import android.view.accessibility.AccessibilityInteractionClient; 250 import android.view.accessibility.AccessibilityManager; 251 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener; 252 import android.view.accessibility.AccessibilityManager.HighContrastTextStateChangeListener; 253 import android.view.accessibility.AccessibilityNodeIdManager; 254 import android.view.accessibility.AccessibilityNodeInfo; 255 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 256 import android.view.accessibility.AccessibilityNodeProvider; 257 import android.view.accessibility.AccessibilityWindowAttributes; 258 import android.view.accessibility.AccessibilityWindowInfo; 259 import android.view.accessibility.IAccessibilityEmbeddedConnection; 260 import android.view.accessibility.IAccessibilityInteractionConnection; 261 import android.view.accessibility.IAccessibilityInteractionConnectionCallback; 262 import android.view.accessibility.IWindowSurfaceInfoCallback; 263 import android.view.animation.AccelerateDecelerateInterpolator; 264 import android.view.animation.Interpolator; 265 import android.view.autofill.AutofillManager; 266 import android.view.contentcapture.ContentCaptureManager; 267 import android.view.contentcapture.ContentCaptureSession; 268 import android.view.flags.Flags; 269 import android.view.inputmethod.ImeTracker; 270 import android.view.inputmethod.InputMethodManager; 271 import android.widget.Scroller; 272 import android.window.ActivityWindowInfo; 273 import android.window.BackEvent; 274 import android.window.ClientWindowFrames; 275 import android.window.CompatOnBackInvokedCallback; 276 import android.window.InputTransferToken; 277 import android.window.OnBackAnimationCallback; 278 import android.window.OnBackInvokedCallback; 279 import android.window.OnBackInvokedDispatcher; 280 import android.window.ScreenCapture; 281 import android.window.SurfaceSyncGroup; 282 import android.window.WindowOnBackInvokedDispatcher; 283 import android.window.WindowTokenClient; 284 import android.window.WindowTokenClientController; 285 286 import com.android.internal.R; 287 import com.android.internal.annotations.GuardedBy; 288 import com.android.internal.annotations.VisibleForTesting; 289 import com.android.internal.graphics.drawable.BackgroundBlurDrawable; 290 import com.android.internal.inputmethod.ImeTracing; 291 import com.android.internal.inputmethod.InputMethodDebug; 292 import com.android.internal.os.IResultReceiver; 293 import com.android.internal.os.SomeArgs; 294 import com.android.internal.policy.DecorView; 295 import com.android.internal.policy.PhoneFallbackEventHandler; 296 import com.android.internal.protolog.ProtoLog; 297 import com.android.internal.util.ContrastColorUtil; 298 import com.android.internal.util.FastPrintWriter; 299 import com.android.internal.view.BaseSurfaceHolder; 300 import com.android.internal.view.RootViewSurfaceTaker; 301 import com.android.internal.view.SurfaceCallbackHelper; 302 import com.android.modules.expresslog.Counter; 303 import com.android.os.coregraphics.HwuiStatsLog; 304 305 import libcore.io.IoUtils; 306 307 import java.io.FileOutputStream; 308 import java.io.IOException; 309 import java.io.OutputStream; 310 import java.io.PrintWriter; 311 import java.io.StringWriter; 312 import java.lang.ref.WeakReference; 313 import java.util.ArrayDeque; 314 import java.util.ArrayList; 315 import java.util.HashSet; 316 import java.util.List; 317 import java.util.Objects; 318 import java.util.OptionalInt; 319 import java.util.Queue; 320 import java.util.concurrent.CountDownLatch; 321 import java.util.concurrent.Executor; 322 import java.util.concurrent.atomic.AtomicBoolean; 323 import java.util.function.Consumer; 324 import java.util.function.Predicate; 325 /** 326 * The top of a view hierarchy, implementing the needed protocol between View 327 * and the WindowManager. This is for the most part an internal implementation 328 * detail of {@link WindowManagerGlobal}. 329 * 330 * {@hide} 331 */ 332 @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"}) 333 public final class ViewRootImpl implements ViewParent, 334 View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks, 335 AttachedSurfaceControl { 336 private static final String TAG = "ViewRootImpl"; 337 private static final boolean DBG = false; 338 private static final boolean LOCAL_LOGV = false; 339 /** @noinspection PointlessBooleanExpression*/ 340 private static final boolean DEBUG_DRAW = false || LOCAL_LOGV; 341 private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV; 342 private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV; 343 private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV; 344 private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV; 345 private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV; 346 private static final boolean DEBUG_IMF = false || LOCAL_LOGV; 347 private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV; 348 private static final boolean DEBUG_FPS = false; 349 private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV; 350 private static final boolean DEBUG_KEEP_SCREEN_ON = false || LOCAL_LOGV; 351 private static final boolean DEBUG_CONTENT_CAPTURE = false || LOCAL_LOGV; 352 private static final boolean DEBUG_SCROLL_CAPTURE = false || LOCAL_LOGV; 353 private static final boolean DEBUG_TOUCH_NAVIGATION = false || LOCAL_LOGV; 354 private static final boolean DEBUG_BLAST = false || LOCAL_LOGV; 355 private static final boolean DEBUG_SENSITIVE_CONTENT = false || LOCAL_LOGV; 356 private static final int LOGTAG_INPUT_FOCUS = 62001; 357 private static final int LOGTAG_VIEWROOT_DRAW_EVENT = 60004; 358 359 /** 360 * This change disables the {@code DRAW_WAKE_LOCK}, an internal wakelock acquired per-frame 361 * duration display DOZE. It was added to allow animation during AOD. This wakelock consumes 362 * battery severely if the animation is too heavy, so, it will be removed. 363 */ 364 @ChangeId 365 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) 366 private static final long DISABLE_DRAW_WAKE_LOCK = 349153669L; 367 368 /** 369 * Set to false if we do not want to use the multi threaded renderer even though 370 * threaded renderer (aka hardware renderering) is used. Note that by disabling 371 * this, WindowCallbacks will not fire. 372 */ 373 private static final boolean MT_RENDERER_AVAILABLE = true; 374 375 /** 376 * Whether or not to report end-to-end input latency. Can be disabled temporarily as a 377 * risk mitigation against potential jank caused by acquiring a weak reference 378 * per frame. 379 */ 380 private static final boolean ENABLE_INPUT_LATENCY_TRACKING = true; 381 382 /** 383 * Whether the client (system UI) is handling the transient gesture and the corresponding 384 * animation. 385 * @hide 386 */ 387 public static final boolean CLIENT_TRANSIENT = 388 SystemProperties.getBoolean("persist.wm.debug.client_transient", false); 389 390 /** 391 * Set this system property to true to force the view hierarchy to render 392 * at 60 Hz. This can be used to measure the potential framerate. 393 */ 394 private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering"; 395 396 /** 397 * Maximum time we allow the user to roll the trackball enough to generate 398 * a key event, before resetting the counters. 399 */ 400 static final int MAX_TRACKBALL_DELAY = 250; 401 402 /** 403 * Initial value for {@link #mContentCaptureEnabled}. 404 */ 405 private static final int CONTENT_CAPTURE_ENABLED_NOT_CHECKED = 0; 406 407 /** 408 * Value for {@link #mContentCaptureEnabled} when it was checked and set to {@code true}. 409 */ 410 private static final int CONTENT_CAPTURE_ENABLED_TRUE = 1; 411 412 /** 413 * Value for {@link #mContentCaptureEnabled} when it was checked and set to {@code false}. 414 */ 415 private static final int CONTENT_CAPTURE_ENABLED_FALSE = 2; 416 417 /** 418 * Maximum time to wait for {@link View#dispatchScrollCaptureSearch} to complete. 419 */ 420 private static final int SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS = 2500; 421 422 private static final int UNSET_SYNC_ID = -1; 423 424 private static final int INFREQUENT_UPDATE_INTERVAL_MILLIS = 100; 425 private static final int INFREQUENT_UPDATE_COUNTS = 2; 426 427 /** 428 * The {@link #intermittentUpdateState()} value when the ViewRootImpl isn't intermittent. 429 */ 430 public static final int INTERMITTENT_STATE_NOT_INTERMITTENT = 1; 431 432 /** 433 * The {@link #intermittentUpdateState()} value when the ViewRootImpl is transitioning either 434 * to or from intermittent to not intermittent. This indicates that the frame rate shouldn't 435 * change. 436 */ 437 public static final int INTERMITTENT_STATE_IN_TRANSITION = -1; 438 439 /** 440 * The {@link #intermittentUpdateState()} value when the ViewRootImpl is intermittent. 441 */ 442 public static final int INTERMITTENT_STATE_INTERMITTENT = 0; 443 444 /** 445 * Minimum time to wait before reporting changes to keep clear areas. 446 */ 447 private static final int KEEP_CLEAR_AREA_REPORT_RATE_MILLIS = 100; 448 449 private static final long NANOS_PER_SEC = 1000000000; 450 451 // If the ViewRootImpl has been idle for more than 750ms, clear the preferred 452 // frame rate category and frame rate. 453 private static final int IDLE_TIME_MILLIS = 750; 454 455 private static final long NANOS_PER_MILLI = 1_000_000; 456 457 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 458 static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>(); 459 460 static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<>(); 461 static boolean sFirstDrawComplete = false; 462 463 private ArrayList<OnBufferTransformHintChangedListener> mTransformHintListeners = 464 new ArrayList<>(); 465 private @SurfaceControl.BufferTransform 466 int mPreviousTransformHint = SurfaceControl.BUFFER_TRANSFORM_IDENTITY; 467 /** 468 * The top level {@link OnBackInvokedDispatcher}. 469 */ 470 private final WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher; 471 /** 472 * Compatibility {@link OnBackInvokedCallback} that dispatches KEYCODE_BACK events 473 * to view root for apps using legacy back behavior. 474 */ 475 private CompatOnBackInvokedCallback mCompatOnBackInvokedCallback; 476 477 @Nullable 478 private ContentObserver mForceInvertObserver; 479 480 /** 481 * Callback for notifying about global configuration changes. 482 */ 483 public interface ConfigChangedCallback { 484 485 /** Notifies about global config change. */ onConfigurationChanged(Configuration globalConfig)486 void onConfigurationChanged(Configuration globalConfig); 487 } 488 489 private static final ArrayList<ConfigChangedCallback> sConfigCallbacks = new ArrayList<>(); 490 491 /** 492 * Callback for notifying activities. 493 */ 494 public interface ActivityConfigCallback { 495 /** 496 * Notifies about override config change and/or move to different display. 497 * @param overrideConfig New override config to apply to activity. 498 * @param newDisplayId New display id, {@link Display#INVALID_DISPLAY} if not changed. 499 */ onConfigurationChanged(@onNull Configuration overrideConfig, int newDisplayId)500 default void onConfigurationChanged(@NonNull Configuration overrideConfig, 501 int newDisplayId) { 502 // Must override one of the #onConfigurationChanged. 503 throw new IllegalStateException("Not implemented"); 504 } 505 506 /** 507 * Notifies about override config change and/or move to different display. 508 * @param overrideConfig New override config to apply to activity. 509 * @param newDisplayId New display id, {@link Display#INVALID_DISPLAY} if not changed. 510 * @param activityWindowInfo New ActivityWindowInfo to apply to activity. 511 */ onConfigurationChanged(@onNull Configuration overrideConfig, int newDisplayId, @Nullable ActivityWindowInfo activityWindowInfo)512 default void onConfigurationChanged(@NonNull Configuration overrideConfig, 513 int newDisplayId, @Nullable ActivityWindowInfo activityWindowInfo) { 514 onConfigurationChanged(overrideConfig, newDisplayId); 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 * Used when configuration change first updates the config of corresponding activity. 527 * In that case we receive a call back from {@link ActivityThread} and this flag is used to 528 * preserve the initial value. 529 * 530 * @see #performConfigurationChange 531 */ 532 private boolean mForceNextConfigUpdate; 533 534 /** lazily-initialized in getAudioManager() */ 535 private boolean mFastScrollSoundEffectsEnabled = false; 536 537 /** 538 * Signals that compatibility booleans have been initialized according to 539 * target SDK versions. 540 */ 541 private static boolean sCompatibilityDone = false; 542 543 /** 544 * Always assign focus if a focusable View is available. 545 */ 546 private static boolean sAlwaysAssignFocus; 547 548 /** 549 * whether we pre-initialized the Buffer Allocator 550 */ 551 private static boolean sPreInitializedBufferAllocator = false; 552 553 /** 554 * This list must only be modified by the main thread. 555 */ 556 final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList<>(); 557 @UnsupportedAppUsage 558 @UiContext 559 public final Context mContext; 560 561 @UnsupportedAppUsage 562 final IWindowSession mWindowSession; 563 @NonNull Display mDisplay; 564 final String mBasePackageName; 565 566 // If we would like to keep a particular eye on the corresponding package. 567 final boolean mExtraDisplayListenerLogging; 568 569 final int[] mTmpLocation = new int[2]; 570 571 final TypedValue mTmpValue = new TypedValue(); 572 573 final Thread mThread; 574 575 final WindowLeaked mLocation; 576 577 public final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams(); 578 579 final W mWindow; 580 581 final IBinder mLeashToken; 582 583 final int mTargetSdkVersion; 584 585 @UnsupportedAppUsage 586 View mView; 587 588 View mAccessibilityFocusedHost; 589 // Accessibility-focused virtual view. The bounds and sourceNodeId of 590 // mAccessibilityFocusedVirtualView is up-to-date while other fields may be stale. 591 AccessibilityNodeInfo mAccessibilityFocusedVirtualView; 592 593 // True if the window currently has pointer capture enabled. 594 boolean mPointerCapture; 595 596 int mViewVisibility; 597 boolean mAppVisible = true; 598 // For recents to freeform transition we need to keep drawing after the app receives information 599 // that it became invisible. This will ignore that information and depend on the decor view 600 // visibility to control drawing. The decor view visibility will get adjusted when the app get 601 // stopped and that's when the app will stop drawing further frames. 602 private boolean mForceDecorViewVisibility = false; 603 // Used for tracking app visibility updates separately in case we get double change. This will 604 // make sure that we always call relayout for the corresponding window. 605 private boolean mAppVisibilityChanged; 606 int mOrigWindowType = -1; 607 608 // Set to true if the owner of this window is in the stopped state, 609 // so the window should no longer be active. 610 @UnsupportedAppUsage 611 boolean mStopped = false; 612 613 // Set to true if the owner of this window is in ambient mode, 614 // which means it won't receive input events. 615 boolean mIsAmbientMode = false; 616 617 // Set to true to stop input during an Activity Transition. 618 boolean mPausedForTransition = false; 619 620 SurfaceHolder.Callback2 mSurfaceHolderCallback; 621 BaseSurfaceHolder mSurfaceHolder; 622 boolean mIsCreating; 623 boolean mDrawingAllowed; 624 625 final Region mTransparentRegion; 626 final Region mPreviousTransparentRegion; 627 628 Region mTouchableRegion; 629 Region mPreviousTouchableRegion; 630 631 private int mMeasuredWidth; 632 private int mMeasuredHeight; 633 634 // This indicates that we've already known the window size but without measuring the views. 635 // If this is true, we must measure the views before laying out them. 636 private boolean mViewMeasureDeferred; 637 638 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 639 int mWidth; 640 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 641 int mHeight; 642 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 643 private Rect mDirty; 644 public boolean mIsAnimating; 645 646 private boolean mUseMTRenderer; 647 private boolean mPendingDragResizing; 648 private boolean mDragResizing; 649 private boolean mInvalidateRootRequested; 650 private int mCanvasOffsetX; 651 private int mCanvasOffsetY; 652 CompatibilityInfo.Translator mTranslator; 653 654 @UnsupportedAppUsage 655 final View.AttachInfo mAttachInfo; 656 final SystemUiVisibilityInfo mCompatibleVisibilityInfo; 657 int mDispatchedSystemUiVisibility; 658 int mDispatchedSystemBarAppearance; 659 InputQueue.Callback mInputQueueCallback; 660 InputQueue mInputQueue; 661 @UnsupportedAppUsage 662 FallbackEventHandler mFallbackEventHandler; 663 final Choreographer mChoreographer; 664 protected final ViewFrameInfo mViewFrameInfo = new ViewFrameInfo(); 665 private final InputEventAssigner mInputEventAssigner = new InputEventAssigner(); 666 667 // Whether to draw this surface as DISPLAY_DECORATION. 668 boolean mDisplayDecorationCached = false; 669 670 // Is the stylus pointer icon enabled 671 private final boolean mIsStylusPointerIconEnabled; 672 673 // VRR check for number of infrequent updates 674 private int mInfrequentUpdateCount = 0; 675 // VRR time of last update 676 private long mLastUpdateTimeMillis = 0; 677 // VRR interval since the previous 678 private int mMinusOneFrameIntervalMillis = 0; 679 // VRR interval between the previous and the frame before 680 private int mMinusTwoFrameIntervalMillis = 0; 681 // VRR has the invalidation idle message been posted? 682 private boolean mInvalidationIdleMessagePosted = false; 683 // VRR: List of all Views that are animating with the threaded render 684 private ArrayList<View> mThreadedRendererViews = new ArrayList(); 685 686 /** 687 * Update the Choreographer's FrameInfo object with the timing information for the current 688 * ViewRootImpl instance. Erase the data in the current ViewFrameInfo to prepare for the next 689 * frame. 690 * @return the updated FrameInfo object 691 */ getUpdatedFrameInfo()692 protected @NonNull FrameInfo getUpdatedFrameInfo() { 693 // Since Choreographer is a thread-local singleton while we can have multiple 694 // ViewRootImpl's, populate the frame information from the current viewRootImpl before 695 // starting the draw 696 FrameInfo frameInfo = mChoreographer.mFrameInfo; 697 mViewFrameInfo.populateFrameInfo(frameInfo); 698 mViewFrameInfo.reset(); 699 mInputEventAssigner.notifyFrameProcessed(); 700 return frameInfo; 701 } 702 703 // used in relayout to get SurfaceControl size 704 // for BLAST adapter surface setup 705 private final Point mSurfaceSize = new Point(); 706 private final Point mLastSurfaceSize = new Point(); 707 708 private final Rect mVisRect = new Rect(); // used to retrieve visible rect of focused view. 709 private final Rect mTempRect = new Rect(); 710 711 private final WindowLayout mWindowLayout; 712 713 // This is used to reduce the race between window focus changes being dispatched from 714 // the window manager and input events coming through the input system. 715 @GuardedBy("this") 716 boolean mWindowFocusChanged; 717 @GuardedBy("this") 718 boolean mUpcomingWindowFocus; 719 @GuardedBy("this") 720 boolean mUpcomingInTouchMode; 721 /** 722 * Compatibility {@link OnBackInvokedCallback} for windowless window, to forward the back 723 * key event host app. 724 */ 725 private Predicate<KeyEvent> mWindowlessBackKeyCallback; 726 727 public boolean mTraversalScheduled; 728 int mTraversalBarrier; 729 boolean mWillDrawSoon; 730 /** Set to true while in performTraversals for detecting when die(true) is called from internal 731 * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */ 732 boolean mIsInTraversal; 733 boolean mApplyInsetsRequested; 734 boolean mLayoutRequested; 735 boolean mFirst; 736 737 @Nullable 738 int mContentCaptureEnabled = CONTENT_CAPTURE_ENABLED_NOT_CHECKED; 739 boolean mPerformContentCapture; 740 741 boolean mReportNextDraw; 742 /** Set only while mReportNextDraw=true, indicating the last reason that was triggered */ 743 String mLastReportNextDrawReason; 744 /** The reaason the last call to performDraw() returned false */ 745 String mLastPerformDrawSkippedReason; 746 /** The reason the last call to performTraversals() returned without drawing */ 747 String mLastPerformTraversalsSkipDrawReason; 748 /** The state of the WMS requested sync, if one is in progress. Can be one of the states 749 * below. */ 750 int mWmsRequestSyncGroupState; 751 752 // The possible states of the WMS requested sync, see createSyncIfNeeded() 753 private static final int WMS_SYNC_NONE = 0; 754 private static final int WMS_SYNC_PENDING = 1; 755 private static final int WMS_SYNC_RETURNED = 2; 756 private static final int WMS_SYNC_MERGED = 3; 757 758 /** 759 * Set whether the requested SurfaceSyncGroup should sync the buffer. When set to true, VRI will 760 * create a sync transaction with BBQ and send the resulting buffer back to the 761 * SurfaceSyncGroup. If false, VRI will not try to sync a buffer in BBQ, but still report when a 762 * draw occurred. 763 */ 764 private boolean mSyncBuffer = false; 765 766 /** 767 * Flag to determine whether the client needs to check with WMS if it can draw. WMS will notify 768 * the client that it can't draw if we're still in the middle of a sync set that includes this 769 * window. Once the sync is complete, the window can resume drawing. This is to ensure we don't 770 * deadlock the client by trying to request draws when there may not be any buffers available. 771 */ 772 private boolean mCheckIfCanDraw = false; 773 774 private boolean mWasLastDrawCanceled; 775 private boolean mLastTraversalWasVisible = true; 776 private boolean mLastDrawScreenOff; 777 778 private boolean mDrewOnceForSync = false; 779 780 int mSyncSeqId = 0; 781 int mLastSyncSeqId = 0; 782 783 private boolean mUpdateSurfaceNeeded; 784 boolean mFullRedrawNeeded; 785 boolean mNewSurfaceNeeded; 786 boolean mForceNextWindowRelayout; 787 CountDownLatch mWindowDrawCountDown; 788 789 /** 790 * Value to indicate whether someone has called {@link #applyTransactionOnDraw}before the 791 * traversal. This is used to determine whether a RT frame callback needs to be registered to 792 * merge the transaction with the next frame. The value is cleared after the VRI has run a 793 * traversal pass. 794 */ 795 boolean mHasPendingTransactions; 796 /** 797 * The combined transactions passed in from {@link #applyTransactionOnDraw} 798 */ 799 private Transaction mPendingTransaction = new Transaction(); 800 801 802 boolean mIsDrawing; 803 int mLastSystemUiVisibility; 804 int mClientWindowLayoutFlags; 805 806 // Pool of queued input events. 807 private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10; 808 private QueuedInputEvent mQueuedInputEventPool; 809 private int mQueuedInputEventPoolSize; 810 811 /* Input event queue. 812 * Pending input events are input events waiting to be delivered to the input stages 813 * and handled by the application. 814 */ 815 QueuedInputEvent mPendingInputEventHead; 816 QueuedInputEvent mPendingInputEventTail; 817 int mPendingInputEventCount; 818 boolean mProcessInputEventsScheduled; 819 boolean mUnbufferedInputDispatch; 820 @InputSourceClass 821 int mUnbufferedInputSource = SOURCE_CLASS_NONE; 822 823 String mPendingInputEventQueueLengthCounterName = "pq"; 824 825 InputStage mFirstInputStage; 826 InputStage mFirstPostImeInputStage; 827 InputStage mSyntheticInputStage; 828 829 private final UnhandledKeyManager mUnhandledKeyManager = new UnhandledKeyManager(); 830 831 boolean mWindowAttributesChanged = false; 832 833 // These can be accessed by any thread, must be protected with a lock. 834 // Surface can never be reassigned or cleared (use Surface.clear()). 835 @UnsupportedAppUsage 836 public final Surface mSurface = new Surface(); 837 private final SurfaceControl mSurfaceControl = new SurfaceControl(); 838 839 private BLASTBufferQueue mBlastBufferQueue; 840 private IBinder mBbqApplyToken = new Binder(); 841 842 private final HdrRenderState mHdrRenderState = new HdrRenderState(this); 843 844 /** 845 * Child container layer of {@code mSurface} with the same bounds as its parent, and cropped to 846 * the surface insets. This surface is created only if a client requests it via 847 * {@link #updateAndGetBoundsLayer(Transaction)}. By parenting to this bounds surface, child 848 * surfaces can ensure they do not draw into the surface inset region set by the parent window. 849 */ 850 private SurfaceControl mBoundsLayer; 851 private final Transaction mTransaction = new Transaction(); 852 private final Transaction mFrameRateTransaction = new Transaction(); 853 854 @UnsupportedAppUsage 855 boolean mAdded; 856 boolean mAddedTouchMode; 857 858 /** 859 * It usually keeps the latest layout result from {@link IWindow#resized} or 860 * {@link IWindowSession#relayout}. 861 */ 862 private final ClientWindowFrames mTmpFrames = new ClientWindowFrames(); 863 864 // These are accessed by multiple threads. 865 final Rect mWinFrame; // frame given by window manager. 866 private final Rect mLastLayoutFrame; 867 Rect mOverrideInsetsFrame; 868 869 final Rect mPendingBackDropFrame = new Rect(); 870 871 boolean mPendingAlwaysConsumeSystemBars; 872 private int mRelayoutSeq; 873 private final Rect mWinFrameInScreen = new Rect(); 874 private final InsetsState mTempInsets = new InsetsState(); 875 private final InsetsSourceControl.Array mTempControls = new InsetsSourceControl.Array(); 876 private final WindowConfiguration mTempWinConfig = new WindowConfiguration(); 877 private float mInvCompatScale = 1f; 878 final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets 879 = new ViewTreeObserver.InternalInsetsInfo(); 880 881 private WindowInsets mLastWindowInsets; 882 883 // Insets types hidden by legacy window flags or system UI flags. 884 private @InsetsType int mTypesHiddenByFlags = 0; 885 886 /** Last applied configuration obtained from resources. */ 887 private final Configuration mLastConfigurationFromResources = new Configuration(); 888 /** Last configuration reported from WM or via {@link #MSG_UPDATE_CONFIGURATION}. */ 889 private final MergedConfiguration mLastReportedMergedConfiguration = new MergedConfiguration(); 890 /** Configurations waiting to be applied. */ 891 private final MergedConfiguration mPendingMergedConfiguration = new MergedConfiguration(); 892 893 /** Non-{@code null} if {@link #mActivityConfigCallback} is not {@code null}. */ 894 @Nullable 895 private ActivityWindowInfo mPendingActivityWindowInfo; 896 /** Non-{@code null} if {@link #mActivityConfigCallback} is not {@code null}. */ 897 @Nullable 898 private ActivityWindowInfo mLastReportedActivityWindowInfo; 899 private final ClientWindowFrames mLastReportedFrames = new ClientWindowFrames(); 900 private int mLastReportedInsetsStateSeq = getInitSeq(); 901 private int mLastReportedActiveControlsSeq = getInitSeq(); 902 903 boolean mScrollMayChange; 904 @SoftInputModeFlags 905 int mSoftInputMode; 906 @UnsupportedAppUsage 907 WeakReference<View> mLastScrolledFocus; 908 int mScrollY; 909 int mCurScrollY; 910 Scroller mScroller; 911 static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator(); 912 private ArrayList<LayoutTransition> mPendingTransitions; 913 914 final ViewConfiguration mViewConfiguration; 915 916 /* Drag/drop */ 917 ClipDescription mDragDescription; 918 View mCurrentDragView; 919 View mStartedDragViewForA11y; 920 volatile Object mLocalDragState; 921 final PointF mDragPoint = new PointF(); 922 final PointF mLastTouchPoint = new PointF(); 923 int mLastTouchSource; 924 int mLastTouchDeviceId = KeyCharacterMap.VIRTUAL_KEYBOARD; 925 int mLastTouchPointerId; 926 /** Tracks last {@link MotionEvent#getToolType(int)} with {@link MotionEvent#ACTION_UP}. **/ 927 private int mLastClickToolType; 928 929 private boolean mProfileRendering; 930 private Choreographer.FrameCallback mRenderProfiler; 931 private boolean mRenderProfilingEnabled; 932 933 // Variables to track frames per second, enabled via DEBUG_FPS flag 934 private long mFpsStartTime = -1; 935 private long mFpsPrevTime = -1; 936 private int mFpsNumFrames; 937 938 private boolean mInsetsAnimationRunning; 939 940 private long mPreviousFrameDrawnTime = -1; 941 // The largest view size percentage to the display size. Used on trace to collect metric. 942 private float mLargestChildPercentage = 0.0f; 943 // The reason the category was changed. 944 private int mFrameRateCategoryChangeReason = 0; 945 private String mFrameRateCategoryView; 946 947 /** 948 * The resolved pointer icon requested by this window. 949 * A null value indicates the resolved pointer icon has not yet been calculated. 950 */ 951 @Nullable 952 private PointerIcon mResolvedPointerIcon = null; 953 954 /** 955 * see {@link #playSoundEffect(int)} 956 */ 957 AudioManager mAudioManager; 958 959 /** 960 * see {@link #performHapticFeedback(int, int, int)} 961 */ 962 Vibrator mVibrator; 963 964 final AccessibilityManager mAccessibilityManager; 965 966 AccessibilityInteractionController mAccessibilityInteractionController; 967 968 Paint mRoundDisplayAccessibilityHighlightPaint; 969 970 final AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager = 971 new AccessibilityInteractionConnectionManager(); 972 final HighContrastTextManager mHighContrastTextManager; 973 974 SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent; 975 976 HashSet<View> mTempHashSet; 977 978 private final int mDensity; 979 private final int mNoncompatDensity; 980 981 private boolean mInLayout = false; 982 ArrayList<View> mLayoutRequesters = new ArrayList<View>(); 983 boolean mHandlingLayoutInLayoutRequest = false; 984 985 private int mViewLayoutDirectionInitial; 986 987 /** Set to true once doDie() has been called. */ 988 private boolean mRemoved; 989 990 private boolean mNeedsRendererSetup; 991 992 private final InputEventCompatProcessor mInputCompatProcessor; 993 994 /** 995 * Consistency verifier for debugging purposes. 996 */ 997 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 998 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 999 new InputEventConsistencyVerifier(this, 0) : null; 1000 1001 private final InsetsController mInsetsController; 1002 private final ImeBackAnimationController mImeBackAnimationController; 1003 private final ImeFocusController mImeFocusController; 1004 1005 private boolean mIsSurfaceOpaque; 1006 1007 private final BackgroundBlurDrawable.Aggregator mBlurRegionAggregator = 1008 new BackgroundBlurDrawable.Aggregator(this); 1009 1010 /** 1011 * @return {@link ImeFocusController} for this instance. 1012 */ 1013 @NonNull getImeFocusController()1014 public ImeFocusController getImeFocusController() { 1015 return mImeFocusController; 1016 } 1017 1018 private final ViewRootRectTracker mGestureExclusionTracker = 1019 new ViewRootRectTracker(v -> v.getSystemGestureExclusionRects()); 1020 private final ViewRootRectTracker mKeepClearRectsTracker = 1021 new ViewRootRectTracker(v -> v.collectPreferKeepClearRects()); 1022 private final ViewRootRectTracker mUnrestrictedKeepClearRectsTracker = 1023 new ViewRootRectTracker(v -> v.collectUnrestrictedPreferKeepClearRects()); 1024 private boolean mHasPendingKeepClearAreaChange; 1025 private Rect mKeepClearAccessibilityFocusRect; 1026 1027 private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection; 1028 1029 private final ISensitiveContentProtectionManager mSensitiveContentProtectionService; 1030 1031 static final class SystemUiVisibilityInfo { 1032 int globalVisibility; 1033 int localValue; 1034 int localChanges; 1035 } 1036 1037 private final HandwritingInitiator mHandwritingInitiator; 1038 1039 /** 1040 * Used by InputMethodManager. 1041 * @hide 1042 */ 1043 @NonNull getHandwritingInitiator()1044 public HandwritingInitiator getHandwritingInitiator() { 1045 return mHandwritingInitiator; 1046 } 1047 1048 /** 1049 * A SurfaceSyncGroup that is created when WMS requested to sync the buffer 1050 */ 1051 private SurfaceSyncGroup mWmsRequestSyncGroup; 1052 1053 /** 1054 * The SurfaceSyncGroup that represents the active VRI SurfaceSyncGroup. This is non null if 1055 * anyone requested the SurfaceSyncGroup for this VRI to ensure that anyone trying to sync with 1056 * this VRI are collected together. The SurfaceSyncGroup is cleared when the VRI draws since 1057 * that is the stop point where all changes are have been applied. A new SurfaceSyncGroup is 1058 * created after that point when something wants to sync VRI again. 1059 */ 1060 private SurfaceSyncGroup mActiveSurfaceSyncGroup; 1061 1062 1063 private final Object mPreviousSyncSafeguardLock = new Object(); 1064 1065 /** 1066 * Wraps the TransactionCommitted callback for the previous SSG so it can be added to the next 1067 * SSG if started before previous has completed. 1068 */ 1069 @GuardedBy("mPreviousSyncSafeguardLock") 1070 private SurfaceSyncGroup mPreviousSyncSafeguard; 1071 1072 private static final Object sSyncProgressLock = new Object(); 1073 // The count needs to be static since it's used to enable or disable RT animations which is 1074 // done at a global level per process. If any VRI syncs are in progress, we can't enable RT 1075 // animations until all are done. 1076 private static int sNumSyncsInProgress = 0; 1077 1078 private int mNumPausedForSync = 0; 1079 1080 private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks; 1081 1082 private long mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS; 1083 1084 /** 1085 * Increment this value when the surface has been replaced. 1086 */ 1087 private int mSurfaceSequenceId = 0; 1088 1089 private boolean mRelayoutRequested; 1090 1091 /** 1092 * Whether sandboxing of {@link android.view.View#getBoundsOnScreen}, 1093 * {@link android.view.View#getLocationOnScreen(int[])}, 1094 * {@link android.view.View#getWindowDisplayFrame} and 1095 * {@link android.view.View#getWindowVisibleDisplayFrame} 1096 * within Activity bounds is enabled for the current application. 1097 */ 1098 private final boolean mViewBoundsSandboxingEnabled; 1099 1100 private AccessibilityWindowAttributes mAccessibilityWindowAttributes; 1101 1102 /* 1103 * for Variable Refresh Rate project 1104 */ 1105 1106 // The preferred frame rate category of the view that 1107 // could be updated on a frame-by-frame basis. 1108 private int mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_DEFAULT; 1109 // The preferred frame rate category of the last frame that 1110 // could be used to lower frame rate after touch boost 1111 private int mLastPreferredFrameRateCategory = FRAME_RATE_CATEGORY_DEFAULT; 1112 // The preferred frame rate of the view that is mainly used for 1113 // touch boosting, view velocity handling, and TextureView. 1114 private float mPreferredFrameRate = 0; 1115 // The last preferred frame rate of the view that is mainly used to 1116 // track the difference between the current preferred frame rate and the previous value. 1117 private float mLastPreferredFrameRate = 0; 1118 // Used to check if it is in the frame rate boosting period. 1119 private boolean mIsFrameRateBoosting = false; 1120 // Used to check if it is in touch boosting period. 1121 private boolean mIsTouchBoosting = false; 1122 // Used to track if an ongoing press gesture is occurring. 1123 private boolean mIsPressedGesture = false; 1124 private boolean mDrawnThisFrame = false; 1125 // Used to check if there is a conflict between different frame rate voting. 1126 // Take 24 and 30 as an example, 24 is not a divisor of 30. 1127 // We consider there is a conflict. 1128 private boolean mIsFrameRateConflicted = false; 1129 // Used to check whether SurfaceControl has been replaced. 1130 private boolean mSurfaceReplaced = false; 1131 // Indicates whether a draw operation occurred during this frame while a touch event was active. 1132 private boolean mTouchAndDrawn = false; 1133 // Used to set frame rate compatibility. 1134 @Surface.FrameRateCompatibility int mFrameRateCompatibility = 1135 FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; 1136 // time for initial touch boost period. 1137 private static final int FRAME_RATE_INITIAL_TOUCH_BOOST_TIME = 30; 1138 // time for touch boost period. 1139 private static final int FRAME_RATE_TOUCH_BOOST_TIME = 3000; 1140 // Timeout for the other frame rate boosts other than touch boost. 1141 private static final int FRAME_RATE_BOOST_TIME = 3000; 1142 // time for evaluating the interval between current time and 1143 // the time when frame rate was set previously. 1144 private static final int FRAME_RATE_SETTING_REEVALUATE_TIME = 100; 1145 // timeout for surface replaced. 1146 private static final int FRAME_RATE_SURFACE_REPLACED_TIME = 3000; 1147 1148 /* 1149 * The variables below are used to update frame rate category 1150 */ 1151 private static final int FRAME_RATE_CATEGORY_COUNT = 5; 1152 private int mFrameRateCategoryHighCount = 0; 1153 private int mFrameRateCategoryHighHintCount = 0; 1154 private int mFrameRateCategoryNormalCount = 0; 1155 private int mFrameRateCategoryLowCount = 0; 1156 1157 /* 1158 * the variables below are used to determine whther a dVRR feature should be enabled 1159 */ 1160 1161 /** 1162 * Object for relayoutWindow to return the latest window info, including the SyncSeqId 1163 * system. The SyncSeqId system was designed to work without synchronous relayout 1164 * window, and actually synchronous relayout window presents a problem. We could have 1165 * a sequence like this: 1166 * 1. We send MSG_RESIZED to the client with a new syncSeqId to begin a new sync 1167 * 2. Due to scheduling the client executes performTraversals before calling MSG_RESIZED 1168 * 3. Coincidentally for some random reason it also calls relayout 1169 * 4. It observes the new state from relayout, and so the next frame will contain the state 1170 * However it hasn't received the seqId yet, and so under the designed operation of 1171 * seqId flowing through MSG_RESIZED, the next frame wouldn't be synced. Since it 1172 * contains our target sync state, we need to sync it! This problem won't come up once 1173 * we get rid of synchronous relayout, until then, we use this bundle to channel the 1174 * integer back over relayout. 1175 */ 1176 private final WindowRelayoutResult mRelayoutResult = new WindowRelayoutResult( 1177 mTmpFrames, mPendingMergedConfiguration, mSurfaceControl, mTempInsets, mTempControls); 1178 1179 private static volatile boolean sAnrReported = false; 1180 static BLASTBufferQueue.TransactionHangCallback sTransactionHangCallback = 1181 new BLASTBufferQueue.TransactionHangCallback() { 1182 @Override 1183 public void onTransactionHang(String reason) { 1184 if (sAnrReported) { 1185 return; 1186 } 1187 1188 sAnrReported = true; 1189 // If we're making an in-process call to ActivityManagerService 1190 // and the previous binder call on this thread was oneway, the 1191 // calling PID will be 0. Clearing the calling identity fixes 1192 // this and ensures ActivityManager gets the correct calling 1193 // pid. 1194 final long identityToken = Binder.clearCallingIdentity(); 1195 try { 1196 ActivityManager.getService().appNotResponding(reason); 1197 } catch (RemoteException e) { 1198 // We asked the system to crash us, but the system 1199 // already crashed. Unfortunately things may be 1200 // out of control. 1201 } finally { 1202 Binder.restoreCallingIdentity(identityToken); 1203 } 1204 } 1205 }; 1206 private final Rect mChildBoundingInsets = new Rect(); 1207 private boolean mChildBoundingInsetsChanged = false; 1208 1209 private final boolean mDisableDrawWakeLock; 1210 1211 private String mTag = TAG; 1212 private String mFpsTraceName; 1213 private String mLargestViewTraceName; 1214 1215 private final boolean mAppStartInfoTimestampsFlagValue; 1216 private AtomicBoolean mAppStartTimestampsSent = new AtomicBoolean(false); 1217 private boolean mAppStartTrackingStarted = false; 1218 private long mRenderThreadDrawStartTimeNs = -1; 1219 private long mFirstFramePresentedTimeNs = -1; 1220 1221 private final boolean mSendPerfHintOnTouch; 1222 1223 private static boolean sToolkitSetFrameRateReadOnlyFlagValue; 1224 private static boolean sToolkitFrameRateFunctionEnablingReadOnlyFlagValue; 1225 private static boolean sToolkitMetricsForFrameRateDecisionFlagValue; 1226 private static boolean sToolkitFrameRateTypingReadOnlyFlagValue; 1227 private static final boolean sToolkitFrameRateViewEnablingReadOnlyFlagValue; 1228 private static boolean sToolkitFrameRateVelocityMappingReadOnlyFlagValue = 1229 toolkitFrameRateVelocityMappingReadOnly(); 1230 private static boolean sToolkitEnableInvalidateCheckThreadFlagValue = 1231 Flags.enableInvalidateCheckThread(); 1232 private static boolean sSurfaceFlingerBugfixFlagValue = 1233 com.android.graphics.surfaceflinger.flags.Flags.vrrBugfix24q4(); 1234 private static final boolean sEnableVrr = ViewProperties.vrr_enabled().orElse(true); 1235 private static final boolean sToolkitInitialTouchBoostFlagValue = toolkitInitialTouchBoost(); 1236 private static boolean sToolkitFrameRateDebugFlagValue = toolkitFrameRateDebug(); 1237 1238 static { 1239 sToolkitSetFrameRateReadOnlyFlagValue = toolkitSetFrameRateReadOnly(); 1240 sToolkitMetricsForFrameRateDecisionFlagValue = toolkitMetricsForFrameRateDecision(); 1241 sToolkitFrameRateTypingReadOnlyFlagValue = toolkitFrameRateTypingReadOnly(); 1242 sToolkitFrameRateFunctionEnablingReadOnlyFlagValue = 1243 toolkitFrameRateFunctionEnablingReadOnly(); 1244 sToolkitFrameRateViewEnablingReadOnlyFlagValue = 1245 toolkitFrameRateViewEnablingReadOnly(); 1246 } 1247 1248 // The latest input event from the gesture that was used to resolve the pointer icon. 1249 private MotionEvent mPointerIconEvent = null; 1250 private @ActivityInfo.ColorMode int mCurrentColorMode = ActivityInfo.COLOR_MODE_DEFAULT; 1251 private long mColorModeLastSetMillis = -1; 1252 1253 private final boolean mIsSubscribeGranularDisplayEventsEnabled; 1254 ViewRootImpl(Context context, Display display)1255 public ViewRootImpl(Context context, Display display) { 1256 this(context, display, WindowManagerGlobal.getWindowSession(), new WindowLayout()); 1257 } 1258 ViewRootImpl(@iContext Context context, Display display, IWindowSession session, WindowLayout windowLayout)1259 public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session, 1260 WindowLayout windowLayout) { 1261 mContext = context; 1262 mWindowSession = session; 1263 mWindowLayout = windowLayout; 1264 mDisplay = display; 1265 mBasePackageName = context.getBasePackageName(); 1266 final String name = DisplayProperties.debug_vri_package().orElse(null); 1267 mExtraDisplayListenerLogging = !TextUtils.isEmpty(name) && name.equals(mBasePackageName); 1268 mThread = Thread.currentThread(); 1269 mLocation = new WindowLeaked(null); 1270 mWidth = -1; 1271 mHeight = -1; 1272 mDirty = new Rect(); 1273 mWinFrame = new Rect(); 1274 mLastLayoutFrame = new Rect(); 1275 mWindow = new W(this); 1276 mLeashToken = new Binder(); 1277 mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion; 1278 mViewVisibility = View.GONE; 1279 mTransparentRegion = new Region(); 1280 mPreviousTransparentRegion = new Region(); 1281 mFirst = true; // true for the first time the view is added 1282 mPerformContentCapture = true; // also true for the first time the view is added 1283 mAdded = false; 1284 mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this, 1285 context); 1286 mCompatibleVisibilityInfo = new SystemUiVisibilityInfo(); 1287 mAccessibilityManager = AccessibilityManager.getInstance(context); 1288 mHighContrastTextManager = new HighContrastTextManager(); 1289 mViewConfiguration = ViewConfiguration.get(context); 1290 mDensity = context.getResources().getDisplayMetrics().densityDpi; 1291 mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi; 1292 mFallbackEventHandler = new PhoneFallbackEventHandler(context); 1293 mChoreographer = Choreographer.getInstance(); 1294 mInsetsController = new InsetsController(new ViewRootInsetsControllerHost(this)); 1295 mImeBackAnimationController = new ImeBackAnimationController(this, mInsetsController); 1296 mHandwritingInitiator = new HandwritingInitiator( 1297 mViewConfiguration, 1298 mContext.getSystemService(InputMethodManager.class)); 1299 1300 mViewBoundsSandboxingEnabled = getViewBoundsSandboxingEnabled(); 1301 mIsStylusPointerIconEnabled = 1302 InputSettings.isStylusPointerIconEnabled(mContext); 1303 1304 initializeProtoLogInProcess(); 1305 1306 String processorOverrideName = context.getResources().getString( 1307 R.string.config_inputEventCompatProcessorOverrideClassName); 1308 if (processorOverrideName.isEmpty()) { 1309 // No compatibility processor override, using default. 1310 mInputCompatProcessor = new InputEventCompatProcessor(context, mHandler); 1311 } else { 1312 InputEventCompatProcessor compatProcessor = null; 1313 try { 1314 final Class<? extends InputEventCompatProcessor> klass = 1315 (Class<? extends InputEventCompatProcessor>) Class.forName( 1316 processorOverrideName); 1317 compatProcessor = klass.getConstructor(Context.class).newInstance(context); 1318 } catch (Exception e) { 1319 Log.e(TAG, "Unable to create the InputEventCompatProcessor. ", e); 1320 } finally { 1321 mInputCompatProcessor = compatProcessor; 1322 } 1323 } 1324 1325 if (!sCompatibilityDone) { 1326 sAlwaysAssignFocus = mTargetSdkVersion < Build.VERSION_CODES.P; 1327 1328 sCompatibilityDone = true; 1329 } 1330 1331 loadSystemProperties(); 1332 mImeFocusController = new ImeFocusController(this); 1333 1334 mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS; 1335 mOnBackInvokedDispatcher = new WindowOnBackInvokedDispatcher(context, Looper.myLooper()); 1336 if (sensitiveContentAppProtection()) { 1337 mSensitiveContentProtectionService = 1338 ISensitiveContentProtectionManager.Stub.asInterface( 1339 ServiceManager.getService(Context.SENSITIVE_CONTENT_PROTECTION_SERVICE)); 1340 if (mSensitiveContentProtectionService == null) { 1341 Log.e(TAG, "SensitiveContentProtectionService shouldn't be null"); 1342 } 1343 } else { 1344 mSensitiveContentProtectionService = null; 1345 } 1346 1347 mAppStartInfoTimestampsFlagValue = android.app.Flags.appStartInfoTimestamps(); 1348 1349 // Disable DRAW_WAKE_LOCK starting U. 1350 mDisableDrawWakeLock = 1351 CompatChanges.isChangeEnabled(DISABLE_DRAW_WAKE_LOCK) && disableDrawWakeLock(); 1352 mIsSubscribeGranularDisplayEventsEnabled = 1353 com.android.server.display.feature.flags.Flags.subscribeGranularDisplayEvents(); 1354 1355 mSendPerfHintOnTouch = adpfViewrootimplActionDownBoost(); 1356 1357 if (!sPreInitializedBufferAllocator) { 1358 preInitBufferAllocator(); 1359 sPreInitializedBufferAllocator = true; 1360 } 1361 } 1362 1363 public static void addFirstDrawHandler(Runnable callback) { 1364 synchronized (sFirstDrawHandlers) { 1365 if (!sFirstDrawComplete) { 1366 sFirstDrawHandlers.add(callback); 1367 } 1368 } 1369 } 1370 1371 /** Add static config callback to be notified about global config changes. */ 1372 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 1373 public static void addConfigCallback(ConfigChangedCallback callback) { 1374 synchronized (sConfigCallbacks) { 1375 sConfigCallbacks.add(callback); 1376 } 1377 } 1378 1379 /** Remove a static config callback. */ 1380 public static void removeConfigCallback(ConfigChangedCallback callback) { 1381 synchronized (sConfigCallbacks) { 1382 sConfigCallbacks.remove(callback); 1383 } 1384 } 1385 1386 /** 1387 * Add activity config callback to be notified about override config changes and camera 1388 * compat control state updates. 1389 */ 1390 public void setActivityConfigCallback(@Nullable ActivityConfigCallback callback) { 1391 mActivityConfigCallback = callback; 1392 if (callback == null) { 1393 mPendingActivityWindowInfo = null; 1394 mLastReportedActivityWindowInfo = null; 1395 } else { 1396 mPendingActivityWindowInfo = new ActivityWindowInfo(); 1397 mLastReportedActivityWindowInfo = new ActivityWindowInfo(); 1398 } 1399 } 1400 1401 public void setOnContentApplyWindowInsetsListener(OnContentApplyWindowInsetsListener listener) { 1402 mAttachInfo.mContentOnApplyWindowInsetsListener = listener; 1403 1404 // System windows will be fitted on first traversal, so no reason to request additional 1405 // (possibly getting executed after the first traversal). 1406 if (!mFirst) { 1407 requestFitSystemWindows(); 1408 } 1409 } 1410 1411 public void addWindowCallbacks(WindowCallbacks callback) { 1412 mWindowCallbacks.add(callback); 1413 } 1414 1415 public void removeWindowCallbacks(WindowCallbacks callback) { 1416 mWindowCallbacks.remove(callback); 1417 } 1418 1419 public void reportDrawFinish() { 1420 if (mWindowDrawCountDown != null) { 1421 mWindowDrawCountDown.countDown(); 1422 } 1423 } 1424 1425 // FIXME for perf testing only 1426 private boolean mProfile = false; 1427 1428 /** 1429 * Call this to profile the next traversal call. 1430 * FIXME for perf testing only. Remove eventually 1431 */ 1432 public void profile() { 1433 mProfile = true; 1434 } 1435 1436 private boolean isInTouchMode() { 1437 if (mAttachInfo == null) { 1438 return mContext.getResources().getBoolean(R.bool.config_defaultInTouchMode); 1439 } 1440 return mAttachInfo.mInTouchMode; 1441 } 1442 1443 /** 1444 * Notifies us that our child has been rebuilt, following 1445 * a window preservation operation. In these cases we 1446 * keep the same DecorView, but the activity controlling it 1447 * is a different instance, and we need to update our 1448 * callbacks. 1449 * 1450 * @hide 1451 */ 1452 public void notifyChildRebuilt() { 1453 if (mView instanceof RootViewSurfaceTaker) { 1454 if (mSurfaceHolderCallback != null) { 1455 mSurfaceHolder.removeCallback(mSurfaceHolderCallback); 1456 } 1457 1458 mSurfaceHolderCallback = 1459 ((RootViewSurfaceTaker)mView).willYouTakeTheSurface(); 1460 1461 if (mSurfaceHolderCallback != null) { 1462 mSurfaceHolder = new TakenSurfaceHolder(); 1463 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN); 1464 mSurfaceHolder.addCallback(mSurfaceHolderCallback); 1465 } else { 1466 mSurfaceHolder = null; 1467 } 1468 1469 mInputQueueCallback = 1470 ((RootViewSurfaceTaker)mView).willYouTakeTheInputQueue(); 1471 if (mInputQueueCallback != null) { 1472 mInputQueueCallback.onInputQueueCreated(mInputQueue); 1473 } 1474 } 1475 1476 // Update the last resource config in case the resource configuration was changed while 1477 // activity relaunched. 1478 updateLastConfigurationFromResources(getConfiguration()); 1479 // Make sure to report the completion of draw for relaunch with preserved window. 1480 reportNextDraw("rebuilt"); 1481 // Make sure to resume this root view when relaunching its host activity which was stopped. 1482 if (mStopped) { 1483 setWindowStopped(false); 1484 } 1485 } 1486 1487 private Configuration getConfiguration() { 1488 return mContext.getResources().getConfiguration(); 1489 } 1490 1491 private WindowConfiguration getCompatWindowConfiguration() { 1492 final WindowConfiguration winConfig = getConfiguration().windowConfiguration; 1493 if (mInvCompatScale == 1f) { 1494 return winConfig; 1495 } 1496 mTempWinConfig.setTo(winConfig); 1497 mTempWinConfig.scale(mInvCompatScale); 1498 return mTempWinConfig; 1499 } 1500 1501 /** 1502 * We have one child 1503 */ 1504 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { 1505 setView(view, attrs, panelParentView, UserHandle.myUserId()); 1506 } 1507 1508 /** 1509 * We have one child 1510 */ 1511 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, 1512 int userId) { 1513 synchronized (this) { 1514 if (mView == null) { 1515 mView = view; 1516 1517 mViewLayoutDirectionInitial = mView.getRawLayoutDirection(); 1518 mFallbackEventHandler.setView(view); 1519 mWindowAttributes.copyFrom(attrs); 1520 if (mWindowAttributes.packageName == null) { 1521 mWindowAttributes.packageName = mBasePackageName; 1522 } 1523 1524 attrs = mWindowAttributes; 1525 setTag(); 1526 mFpsTraceName = "FPS of " + getTitle(); 1527 mLargestViewTraceName = "Largest view percentage(per hundred) of " + getTitle(); 1528 1529 if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags 1530 & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0 1531 && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) { 1532 Slog.d(mTag, "setView: FLAG_KEEP_SCREEN_ON changed from true to false!"); 1533 } 1534 // Keep track of the actual window flags supplied by the client. 1535 mClientWindowLayoutFlags = attrs.flags; 1536 1537 adjustLayoutInDisplayCutoutMode(attrs); 1538 setAccessibilityFocus(null, null); 1539 1540 if (view instanceof RootViewSurfaceTaker) { 1541 mSurfaceHolderCallback = 1542 ((RootViewSurfaceTaker)view).willYouTakeTheSurface(); 1543 if (mSurfaceHolderCallback != null) { 1544 mSurfaceHolder = new TakenSurfaceHolder(); 1545 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN); 1546 mSurfaceHolder.addCallback(mSurfaceHolderCallback); 1547 } 1548 } 1549 1550 // Compute surface insets required to draw at specified Z value. 1551 // TODO: Use real shadow insets for a constant max Z. 1552 if (!attrs.hasManualSurfaceInsets) { 1553 attrs.setSurfaceInsets(view, false /*manual*/, true /*preservePrevious*/); 1554 } 1555 1556 CompatibilityInfo compatibilityInfo = 1557 mDisplay.getDisplayAdjustments().getCompatibilityInfo(); 1558 mTranslator = compatibilityInfo.getTranslator(); 1559 1560 // If the application owns the surface, don't enable hardware acceleration 1561 if (mSurfaceHolder == null) { 1562 // While this is supposed to enable only, it can effectively disable 1563 // the acceleration too. 1564 enableHardwareAcceleration(attrs); 1565 final boolean useMTRenderer = MT_RENDERER_AVAILABLE 1566 && mAttachInfo.mThreadedRenderer != null; 1567 if (mUseMTRenderer != useMTRenderer) { 1568 // Shouldn't be resizing, as it's done only in window setup, 1569 // but end just in case. 1570 endDragResizing(); 1571 mUseMTRenderer = useMTRenderer; 1572 } 1573 } 1574 1575 boolean restore = false; 1576 if (mTranslator != null) { 1577 mSurface.setCompatibilityTranslator(mTranslator); 1578 restore = true; 1579 attrs.backup(); 1580 mTranslator.translateWindowLayout(attrs); 1581 } 1582 if (DEBUG_LAYOUT) Log.d(mTag, "WindowLayout in setView:" + attrs); 1583 1584 mSoftInputMode = attrs.softInputMode; 1585 mWindowAttributesChanged = true; 1586 mAttachInfo.mRootView = view; 1587 mAttachInfo.mScalingRequired = mTranslator != null; 1588 mAttachInfo.mApplicationScale = 1589 mTranslator == null ? 1.0f : mTranslator.applicationScale; 1590 if (panelParentView != null) { 1591 mAttachInfo.mPanelParentWindowToken 1592 = panelParentView.getApplicationWindowToken(); 1593 } 1594 if (!fixViewRootCallTrace()) { 1595 mAdded = true; 1596 } 1597 int res; /* = WindowManagerImpl.ADD_OKAY; */ 1598 1599 // Schedule the first layout -before- adding to the window 1600 // manager, to make sure we do the relayout before receiving 1601 // any other events from the system. 1602 requestLayout(); 1603 InputChannel inputChannel = null; 1604 if ((mWindowAttributes.inputFeatures 1605 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) { 1606 inputChannel = new InputChannel(); 1607 } 1608 mForceDecorViewVisibility = (mWindowAttributes.privateFlags 1609 & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0; 1610 1611 if (mView instanceof RootViewSurfaceTaker) { 1612 PendingInsetsController pendingInsetsController = 1613 ((RootViewSurfaceTaker) mView).providePendingInsetsController(); 1614 if (pendingInsetsController != null) { 1615 pendingInsetsController.replayAndAttach(mInsetsController); 1616 } 1617 } 1618 if (mView instanceof DecorView) { 1619 mWindowAttributes.privateFlags |= PRIVATE_FLAG_APP_PROGRESS_GENERATION_ALLOWED; 1620 } 1621 1622 try { 1623 mOrigWindowType = mWindowAttributes.type; 1624 mAttachInfo.mRecomputeGlobalAttributes = true; 1625 collectViewAttributes(); 1626 adjustLayoutParamsForCompatibility(mWindowAttributes, 1627 mInsetsController.getAppearanceControlled(), 1628 mInsetsController.isBehaviorControlled()); 1629 controlInsetsForCompatibility(mWindowAttributes); 1630 1631 Rect attachedFrame = new Rect(); 1632 final float[] compatScale = { 1f }; 1633 res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes, 1634 getHostVisibility(), mDisplay.getDisplayId(), userId, 1635 mInsetsController.getRequestedVisibleTypes(), inputChannel, mTempInsets, 1636 mTempControls, attachedFrame, compatScale); 1637 if (!attachedFrame.isValid()) { 1638 attachedFrame = null; 1639 } 1640 if (mTranslator != null) { 1641 mTranslator.translateRectInScreenToAppWindow(attachedFrame); 1642 } 1643 mTmpFrames.attachedFrame = attachedFrame; 1644 mTmpFrames.compatScale = compatScale[0]; 1645 mInvCompatScale = 1f / compatScale[0]; 1646 } catch (RemoteException | RuntimeException e) { 1647 if (!fixViewRootCallTrace()) { 1648 mAdded = false; 1649 } 1650 mView = null; 1651 mAttachInfo.mRootView = null; 1652 mFallbackEventHandler.setView(null); 1653 unscheduleTraversals(); 1654 setAccessibilityFocus(null, null); 1655 throw new RuntimeException("Adding window failed", e); 1656 } finally { 1657 if (restore) { 1658 attrs.restore(); 1659 } 1660 } 1661 1662 mAttachInfo.mAlwaysConsumeSystemBars = 1663 (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS) != 0; 1664 mPendingAlwaysConsumeSystemBars = mAttachInfo.mAlwaysConsumeSystemBars; 1665 handleInsetsControlChanged(mTempInsets, mTempControls); 1666 final InsetsState state = mInsetsController.getState(); 1667 final Rect displayCutoutSafe = mTempRect; 1668 state.getDisplayCutoutSafe(displayCutoutSafe); 1669 final WindowConfiguration winConfig = getCompatWindowConfiguration(); 1670 mWindowLayout.computeFrames(mWindowAttributes, state, 1671 displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(), 1672 UNSPECIFIED_LENGTH, UNSPECIFIED_LENGTH, 1673 mInsetsController.getRequestedVisibleTypes(), 1f /* compactScale */, 1674 mTmpFrames); 1675 setFrame(mTmpFrames.frame, true /* withinRelayout */); 1676 registerBackCallbackOnWindow(); 1677 if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow); 1678 if (res < WindowManagerGlobal.ADD_OKAY) { 1679 mAttachInfo.mRootView = null; 1680 if (!fixViewRootCallTrace()) { 1681 mAdded = false; 1682 } 1683 mFallbackEventHandler.setView(null); 1684 unscheduleTraversals(); 1685 setAccessibilityFocus(null, null); 1686 switch (res) { 1687 case WindowManagerGlobal.ADD_BAD_APP_TOKEN: 1688 case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN: 1689 throw new WindowManager.BadTokenException( 1690 "Unable to add window -- token " + attrs.token 1691 + " is not valid; is your activity running?"); 1692 case WindowManagerGlobal.ADD_NOT_APP_TOKEN: 1693 throw new WindowManager.BadTokenException( 1694 "Unable to add window -- token " + attrs.token 1695 + " is not for an application"); 1696 case WindowManagerGlobal.ADD_APP_EXITING: 1697 throw new WindowManager.BadTokenException( 1698 "Unable to add window -- app for token " + attrs.token 1699 + " is exiting"); 1700 case WindowManagerGlobal.ADD_DUPLICATE_ADD: 1701 throw new WindowManager.BadTokenException( 1702 "Unable to add window -- window " + mWindow 1703 + " has already been added"); 1704 case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED: 1705 // Silently ignore -- we would have just removed it 1706 // right away, anyway. 1707 return; 1708 case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON: 1709 throw new WindowManager.BadTokenException("Unable to add window " 1710 + mWindow + " -- another window of type " 1711 + mWindowAttributes.type + " already exists"); 1712 case WindowManagerGlobal.ADD_PERMISSION_DENIED: 1713 throw new WindowManager.BadTokenException("Unable to add window " 1714 + mWindow + " -- permission denied for window type " 1715 + mWindowAttributes.type); 1716 case WindowManagerGlobal.ADD_INVALID_DISPLAY: 1717 throw new WindowManager.InvalidDisplayException("Unable to add window " 1718 + mWindow + " -- the specified display can not be found"); 1719 case WindowManagerGlobal.ADD_INVALID_TYPE: 1720 throw new WindowManager.InvalidDisplayException("Unable to add window " 1721 + mWindow + " -- the specified window type " 1722 + mWindowAttributes.type + " is not valid"); 1723 case WindowManagerGlobal.ADD_INVALID_USER: 1724 throw new WindowManager.BadTokenException("Unable to add Window " 1725 + mWindow + " -- requested userId is not valid"); 1726 } 1727 throw new RuntimeException( 1728 "Unable to add window -- unknown error code " + res); 1729 } 1730 1731 registerListeners(); 1732 // We should update mAttachInfo.mDisplayState after registerDisplayListener 1733 // because displayState might be changed before registerDisplayListener. 1734 mAttachInfo.mDisplayState = mDisplay.getState(); 1735 if (mExtraDisplayListenerLogging) { 1736 Slog.i(mTag, "(" + mBasePackageName + ") Initial DisplayState: " 1737 + mAttachInfo.mDisplayState, new Throwable()); 1738 } 1739 1740 if (view instanceof RootViewSurfaceTaker) { 1741 mInputQueueCallback = 1742 ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue(); 1743 } 1744 if (inputChannel != null) { 1745 if (mInputQueueCallback != null) { 1746 mInputQueue = new InputQueue(); 1747 mInputQueueCallback.onInputQueueCreated(mInputQueue); 1748 } 1749 mInputEventReceiver = new WindowInputEventReceiver(inputChannel, 1750 Looper.myLooper()); 1751 1752 if (ENABLE_INPUT_LATENCY_TRACKING && mAttachInfo.mThreadedRenderer != null) { 1753 InputMetricsListener listener = new InputMetricsListener(); 1754 mHardwareRendererObserver = new HardwareRendererObserver( 1755 listener, listener.data, mHandler, true /*waitForPresentTime*/); 1756 mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver); 1757 } 1758 // Update unbuffered request when set the root view. 1759 mUnbufferedInputSource = mView.mUnbufferedInputSource; 1760 } 1761 1762 view.assignParent(this); 1763 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0; 1764 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0; 1765 1766 if (mAccessibilityManager.isEnabled()) { 1767 mAccessibilityInteractionConnectionManager.ensureConnection(); 1768 setAccessibilityWindowAttributesIfNeeded(); 1769 } 1770 1771 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 1772 view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); 1773 } 1774 1775 // Set up the input pipeline. 1776 CharSequence counterSuffix = attrs.getTitle(); 1777 mSyntheticInputStage = new SyntheticInputStage(); 1778 InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage); 1779 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage, 1780 "aq:native-post-ime:" + counterSuffix); 1781 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage); 1782 InputStage imeStage = new ImeInputStage(earlyPostImeStage, 1783 "aq:ime:" + counterSuffix); 1784 InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage); 1785 InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage, 1786 "aq:native-pre-ime:" + counterSuffix); 1787 1788 mFirstInputStage = nativePreImeStage; 1789 mFirstPostImeInputStage = earlyPostImeStage; 1790 mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix; 1791 if (fixViewRootCallTrace()) { 1792 mAdded = true; 1793 } 1794 1795 if (!mRemoved || !mAppVisible) { 1796 AnimationHandler.requestAnimatorsEnabled(mAppVisible, this); 1797 } else if (LOCAL_LOGV) { 1798 Log.v(mTag, "setView() enabling visibility when removed"); 1799 } 1800 } 1801 } 1802 } 1803 1804 private void setAccessibilityWindowAttributesIfNeeded() { 1805 final boolean registered = mAttachInfo.mAccessibilityWindowId 1806 != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 1807 if (registered) { 1808 final AccessibilityWindowAttributes attributes = new AccessibilityWindowAttributes( 1809 mWindowAttributes, mContext.getResources().getConfiguration().getLocales()); 1810 if (!attributes.equals(mAccessibilityWindowAttributes)) { 1811 mAccessibilityWindowAttributes = attributes; 1812 mAccessibilityManager.setAccessibilityWindowAttributes(getDisplayId(), 1813 mAttachInfo.mAccessibilityWindowId, attributes); 1814 } 1815 1816 } 1817 } 1818 1819 /** 1820 * Register any kind of listeners if setView was success. 1821 */ 1822 private void registerListeners() { 1823 if (mExtraDisplayListenerLogging) { 1824 Slog.i(mTag, "Register listeners: " + mBasePackageName); 1825 } 1826 mAccessibilityManager.addAccessibilityStateChangeListener( 1827 mAccessibilityInteractionConnectionManager, mHandler); 1828 mAccessibilityManager.addHighContrastTextStateChangeListener( 1829 mExecutor, mHighContrastTextManager); 1830 1831 1832 long eventsToBeRegistered = 1833 (mIsSubscribeGranularDisplayEventsEnabled) 1834 ? DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED 1835 | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_STATE 1836 | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED 1837 : DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED 1838 | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED 1839 | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE 1840 | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED; 1841 DisplayManagerGlobal 1842 .getInstance() 1843 .registerDisplayListener( 1844 mDisplayListener, 1845 mHandler, 1846 eventsToBeRegistered, 1847 mBasePackageName); 1848 1849 // LINT.IfChange(fi_cb) 1850 if (forceInvertColor()) { 1851 if (mForceInvertObserver == null) { 1852 mForceInvertObserver = new ContentObserver(mHandler) { 1853 @Override 1854 public void onChange(boolean selfChange) { 1855 updateForceDarkMode(); 1856 } 1857 }; 1858 final Uri[] urisToObserve = { 1859 Settings.Secure.getUriFor( 1860 Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED), 1861 Settings.Secure.getUriFor(Settings.Secure.UI_NIGHT_MODE) 1862 }; 1863 for (Uri uri : urisToObserve) { 1864 mContext.getContentResolver().registerContentObserver( 1865 uri, 1866 false, 1867 mForceInvertObserver, 1868 UserHandle.myUserId()); 1869 } 1870 } 1871 } 1872 // LINT.ThenChange(/services/core/java/com/android/server/UiModeManagerService.java:fi_cb) 1873 } 1874 1875 /** 1876 * Unregister all listeners while detachedFromWindow. 1877 */ 1878 private void unregisterListeners() { 1879 mAccessibilityManager.removeAccessibilityStateChangeListener( 1880 mAccessibilityInteractionConnectionManager); 1881 mAccessibilityManager.removeHighContrastTextStateChangeListener( 1882 mHighContrastTextManager); 1883 DisplayManagerGlobal 1884 .getInstance() 1885 .unregisterDisplayListener(mDisplayListener); 1886 1887 if (forceInvertColor()) { 1888 if (mForceInvertObserver != null) { 1889 mContext.getContentResolver().unregisterContentObserver(mForceInvertObserver); 1890 mForceInvertObserver = null; 1891 } 1892 } 1893 1894 if (mExtraDisplayListenerLogging) { 1895 Slog.w(mTag, "Unregister listeners: " + mBasePackageName, new Throwable()); 1896 } 1897 } 1898 1899 private void setTag() { 1900 final String[] split = mWindowAttributes.getTitle().toString().split("\\."); 1901 if (split.length > 0) { 1902 mTag = "VRI[" + split[split.length - 1] + "]"; 1903 } 1904 } 1905 1906 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 1907 public int getWindowFlags() { 1908 return mWindowAttributes.flags; 1909 } 1910 1911 public int getDisplayId() { 1912 return mDisplay.getDisplayId(); 1913 } 1914 1915 public CharSequence getTitle() { 1916 return mWindowAttributes.getTitle(); 1917 } 1918 1919 /** 1920 * @return the width of the root view. Note that this will return {@code -1} until the first 1921 * layout traversal, when the width is set. 1922 * 1923 * @hide 1924 */ 1925 public int getWidth() { 1926 return mWidth; 1927 } 1928 1929 /** 1930 * @return the height of the root view. Note that this will return {@code -1} until the first 1931 * layout traversal, when the height is set. 1932 * 1933 * @hide 1934 */ 1935 public int getHeight() { 1936 return mHeight; 1937 } 1938 1939 /** 1940 * Destroys hardware rendering resources for this ViewRootImpl 1941 * 1942 * May be called on any thread 1943 */ 1944 @AnyThread 1945 void destroyHardwareResources() { 1946 final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer; 1947 if (renderer != null) { 1948 // This is called by WindowManagerGlobal which may or may not be on the right thread 1949 if (Looper.myLooper() != mAttachInfo.mHandler.getLooper()) { 1950 mAttachInfo.mHandler.postAtFrontOfQueue(this::destroyHardwareResources); 1951 return; 1952 } 1953 renderer.destroyHardwareResources(mView); 1954 renderer.destroy(); 1955 } 1956 } 1957 1958 /** 1959 * Does nothing; Here only because of @UnsupportedAppUsage 1960 */ 1961 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, 1962 publicAlternatives = "Use {@link android.webkit.WebView} instead") 1963 public void detachFunctor(long functor) { } 1964 1965 /** 1966 * Does nothing; Here only because of @UnsupportedAppUsage 1967 */ 1968 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, 1969 publicAlternatives = "Use {@link android.webkit.WebView} instead") 1970 public static void invokeFunctor(long functor, boolean waitForCompletion) { } 1971 1972 /** 1973 * @param animator animator to register with the hardware renderer 1974 */ 1975 public void registerAnimatingRenderNode(RenderNode animator) { 1976 if (mAttachInfo.mThreadedRenderer != null) { 1977 mAttachInfo.mThreadedRenderer.registerAnimatingRenderNode(animator); 1978 } else { 1979 if (mAttachInfo.mPendingAnimatingRenderNodes == null) { 1980 mAttachInfo.mPendingAnimatingRenderNodes = new ArrayList<RenderNode>(); 1981 } 1982 mAttachInfo.mPendingAnimatingRenderNodes.add(animator); 1983 } 1984 } 1985 1986 /** 1987 * @param animator animator to register with the hardware renderer 1988 */ 1989 public void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator) { 1990 if (mAttachInfo.mThreadedRenderer != null) { 1991 mAttachInfo.mThreadedRenderer.registerVectorDrawableAnimator(animator); 1992 } 1993 } 1994 1995 /** 1996 * Registers a callback to be executed when the next frame is being drawn on RenderThread. This 1997 * callback will be executed on a RenderThread worker thread, and only used for the next frame 1998 * and thus it will only fire once. 1999 * 2000 * @param callback The callback to register. 2001 */ 2002 public void registerRtFrameCallback(@NonNull FrameDrawingCallback callback) { 2003 if (mAttachInfo.mThreadedRenderer != null) { 2004 mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() { 2005 @Override 2006 public void onFrameDraw(long frame) { 2007 } 2008 2009 @Override 2010 public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, 2011 long frame) { 2012 try { 2013 return callback.onFrameDraw(syncResult, frame); 2014 } catch (Exception e) { 2015 Log.e(TAG, "Exception while executing onFrameDraw", e); 2016 } 2017 return null; 2018 } 2019 }); 2020 } 2021 } 2022 2023 @UnsupportedAppUsage 2024 private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) { 2025 mAttachInfo.mHardwareAccelerated = false; 2026 mAttachInfo.mHardwareAccelerationRequested = false; 2027 2028 // Don't enable hardware acceleration when the application is in compatibility mode 2029 if (mTranslator != null) return; 2030 2031 // Try to enable hardware acceleration if requested 2032 final boolean hardwareAccelerated = 2033 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0; 2034 2035 if (hardwareAccelerated) { 2036 // Persistent processes (including the system) should not do 2037 // accelerated rendering on low-end devices. In that case, 2038 // sRendererDisabled will be set. In addition, the system process 2039 // itself should never do accelerated rendering. In that case, both 2040 // sRendererDisabled and sSystemRendererDisabled are set. When 2041 // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED 2042 // can be used by code on the system process to escape that and enable 2043 // HW accelerated drawing. (This is basically for the lock screen.) 2044 2045 final boolean forceHwAccelerated = (attrs.privateFlags & 2046 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0; 2047 2048 if (ThreadedRenderer.sRendererEnabled || forceHwAccelerated) { 2049 if (mAttachInfo.mThreadedRenderer != null) { 2050 mAttachInfo.mThreadedRenderer.destroy(); 2051 } 2052 2053 final Rect insets = attrs.surfaceInsets; 2054 final boolean hasSurfaceInsets = insets.left != 0 || insets.right != 0 2055 || insets.top != 0 || insets.bottom != 0; 2056 final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets; 2057 final ThreadedRenderer renderer = ThreadedRenderer.create(mContext, translucent, 2058 attrs.getTitle().toString()); 2059 mAttachInfo.mThreadedRenderer = renderer; 2060 renderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue); 2061 updateColorModeIfNeeded(attrs.getColorMode(), attrs.getDesiredHdrHeadroom()); 2062 mHdrRenderState.forceUpdateHdrSdrRatio(); 2063 updateForceDarkMode(); 2064 mAttachInfo.mHardwareAccelerated = true; 2065 mAttachInfo.mHardwareAccelerationRequested = true; 2066 if (mHardwareRendererObserver != null) { 2067 renderer.addObserver(mHardwareRendererObserver); 2068 } 2069 } 2070 } 2071 } 2072 2073 private int getNightMode() { 2074 return getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; 2075 } 2076 2077 /** 2078 * Determines the type of force dark to apply, considering force inversion, system night mode, 2079 * and app-specific settings (including developer opt-outs). 2080 * 2081 * @return A {@link ForceDarkType.ForceDarkTypeDef} constant indicating the force dark type. 2082 */ 2083 @VisibleForTesting 2084 public @ForceDarkType.ForceDarkTypeDef int determineForceDarkType() { 2085 TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme); 2086 try { 2087 if (forceInvertColor()) { 2088 // Force invert ignores all developer opt-outs. 2089 // We also ignore dark theme, since the app developer can override the user's 2090 // preference for dark mode in configuration.uiMode. Instead, we assume that both 2091 // force invert and the system's dark theme are enabled. 2092 if (shouldApplyForceInvertDark()) { 2093 // TODO: b/368725782 - Use hwui color area detection instead of / in 2094 // addition to these heuristics. 2095 final boolean isLightTheme = 2096 a.getBoolean(R.styleable.Theme_isLightTheme, false); 2097 final boolean isBackgroundColorLight; 2098 if (mView != null && mView.getBackground() 2099 instanceof ColorDrawable colorDrawable) { 2100 isBackgroundColorLight = 2101 !ContrastColorUtil.isColorDarkLab(colorDrawable.getColor()); 2102 } else { 2103 // Treat unknown as light, so that only isLightTheme is used to determine 2104 // force dark treatment. 2105 isBackgroundColorLight = true; 2106 } 2107 if (isLightTheme && isBackgroundColorLight) { 2108 return ForceDarkType.FORCE_INVERT_COLOR_DARK; 2109 } else { 2110 return ForceDarkType.NONE; 2111 } 2112 } 2113 } 2114 2115 boolean useAutoDark = getNightMode() == Configuration.UI_MODE_NIGHT_YES; 2116 if (useAutoDark) { 2117 boolean forceDarkAllowedDefault = 2118 SystemProperties.getBoolean(ThreadedRenderer.DEBUG_FORCE_DARK, false); 2119 useAutoDark = a.getBoolean(R.styleable.Theme_isLightTheme, true) 2120 && a.getBoolean(R.styleable.Theme_forceDarkAllowed, 2121 forceDarkAllowedDefault); 2122 } 2123 return useAutoDark ? ForceDarkType.FORCE_DARK : ForceDarkType.NONE; 2124 } finally { 2125 a.recycle(); 2126 } 2127 } 2128 2129 private boolean shouldApplyForceInvertDark() { 2130 final UiModeManager uiModeManager = mContext.getSystemService(UiModeManager.class); 2131 if (uiModeManager == null) { 2132 return false; 2133 } 2134 return uiModeManager.getForceInvertState() == UiModeManager.FORCE_INVERT_TYPE_DARK; 2135 } 2136 2137 private void updateForceDarkMode() { 2138 if (mAttachInfo.mThreadedRenderer == null) return; 2139 if (mAttachInfo.mThreadedRenderer.setForceDark(determineForceDarkType())) { 2140 // TODO: Don't require regenerating all display lists to apply this setting 2141 if (forceInvertColor()) { 2142 destroyAndInvalidate(); 2143 } else { 2144 invalidateWorld(mView); 2145 } 2146 } 2147 } 2148 2149 @UnsupportedAppUsage 2150 public View getView() { 2151 return mView; 2152 } 2153 2154 final WindowLeaked getLocation() { 2155 return mLocation; 2156 } 2157 2158 @VisibleForTesting 2159 public void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) { 2160 synchronized (this) { 2161 final int oldInsetLeft = mWindowAttributes.surfaceInsets.left; 2162 final int oldInsetTop = mWindowAttributes.surfaceInsets.top; 2163 final int oldInsetRight = mWindowAttributes.surfaceInsets.right; 2164 final int oldInsetBottom = mWindowAttributes.surfaceInsets.bottom; 2165 final int oldSoftInputMode = mWindowAttributes.softInputMode; 2166 final boolean oldHasManualSurfaceInsets = mWindowAttributes.hasManualSurfaceInsets; 2167 2168 if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags 2169 & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0 2170 && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) { 2171 Slog.d(mTag, "setLayoutParams: FLAG_KEEP_SCREEN_ON from true to false!"); 2172 } 2173 2174 // Keep track of the actual window flags supplied by the client. 2175 mClientWindowLayoutFlags = attrs.flags; 2176 2177 // Preserve system UI visibility. 2178 final int systemUiVisibility = mWindowAttributes.systemUiVisibility; 2179 final int subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility; 2180 2181 // Preserve appearance and behavior. 2182 final int appearance = mWindowAttributes.insetsFlags.appearance; 2183 final int behavior = mWindowAttributes.insetsFlags.behavior; 2184 2185 // Calling this before copying prevents redundant LAYOUT_CHANGED. 2186 final int layoutInDisplayCutoutModeFromCaller = adjustLayoutInDisplayCutoutMode(attrs); 2187 2188 final int changes = mWindowAttributes.copyFrom(attrs); 2189 if ((changes & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) { 2190 // Recompute system ui visibility. 2191 mAttachInfo.mRecomputeGlobalAttributes = true; 2192 } 2193 if ((changes & WindowManager.LayoutParams.LAYOUT_CHANGED) != 0) { 2194 // Request to update light center. 2195 mAttachInfo.mNeedsUpdateLightCenter = true; 2196 } 2197 if ((changes & WindowManager.LayoutParams.COLOR_MODE_CHANGED) != 0) { 2198 invalidate(); 2199 } 2200 if (mWindowAttributes.packageName == null) { 2201 mWindowAttributes.packageName = mBasePackageName; 2202 } 2203 2204 // Restore the layoutInDisplayCutoutMode of the caller; 2205 attrs.layoutInDisplayCutoutMode = layoutInDisplayCutoutModeFromCaller; 2206 2207 // Restore preserved flags. 2208 mWindowAttributes.systemUiVisibility = systemUiVisibility; 2209 mWindowAttributes.subtreeSystemUiVisibility = subtreeSystemUiVisibility; 2210 mWindowAttributes.insetsFlags.appearance = appearance; 2211 mWindowAttributes.insetsFlags.behavior = behavior; 2212 2213 if (mWindowAttributes.preservePreviousSurfaceInsets) { 2214 // Restore old surface insets. 2215 mWindowAttributes.surfaceInsets.set( 2216 oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom); 2217 mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets; 2218 } else if (mWindowAttributes.surfaceInsets.left != oldInsetLeft 2219 || mWindowAttributes.surfaceInsets.top != oldInsetTop 2220 || mWindowAttributes.surfaceInsets.right != oldInsetRight 2221 || mWindowAttributes.surfaceInsets.bottom != oldInsetBottom) { 2222 mNeedsRendererSetup = true; 2223 } 2224 2225 applyKeepScreenOnFlag(mWindowAttributes); 2226 2227 if (newView) { 2228 mSoftInputMode = attrs.softInputMode; 2229 requestLayout(); 2230 } 2231 2232 // Don't lose the mode we last auto-computed. 2233 if ((attrs.softInputMode & SOFT_INPUT_MASK_ADJUST) 2234 == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) { 2235 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode 2236 & ~SOFT_INPUT_MASK_ADJUST) | (oldSoftInputMode & SOFT_INPUT_MASK_ADJUST); 2237 } 2238 2239 if (mWindowAttributes.softInputMode != oldSoftInputMode) { 2240 requestFitSystemWindows(); 2241 } 2242 2243 mWindowAttributesChanged = true; 2244 scheduleTraversals(); 2245 setAccessibilityWindowAttributesIfNeeded(); 2246 } 2247 } 2248 2249 private int adjustLayoutInDisplayCutoutMode(WindowManager.LayoutParams attrs) { 2250 final int originalMode = attrs.layoutInDisplayCutoutMode; 2251 if ((attrs.privateFlags & (PRIVATE_FLAG_EDGE_TO_EDGE_ENFORCED 2252 | PRIVATE_FLAG_OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE)) != 0 2253 && attrs.isFullscreen() 2254 && attrs.getFitInsetsTypes() == 0 2255 && attrs.getFitInsetsSides() == 0) { 2256 if (originalMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) { 2257 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; 2258 } 2259 } 2260 return originalMode; 2261 } 2262 2263 void handleAppVisibility(boolean visible) { 2264 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 2265 Trace.instant(Trace.TRACE_TAG_VIEW, TextUtils.formatSimple( 2266 "%s visibilityChanged oldVisibility=%b newVisibility=%b", mTag, 2267 mAppVisible, visible)); 2268 } 2269 if (mAppVisible != visible) { 2270 final boolean previousVisible = getHostVisibility() == View.VISIBLE; 2271 mAppVisible = visible; 2272 final boolean currentVisible = getHostVisibility() == View.VISIBLE; 2273 // Root view only cares about whether it is visible or not. 2274 if (previousVisible != currentVisible) { 2275 Log.d(mTag, "visibilityChanged oldVisibility=" + previousVisible + " newVisibility=" 2276 + currentVisible); 2277 mAppVisibilityChanged = true; 2278 scheduleTraversals(); 2279 } 2280 // Only enable if the window is not already removed (via earlier call to doDie()) 2281 if (!mRemoved || !mAppVisible) { 2282 AnimationHandler.requestAnimatorsEnabled(mAppVisible, this); 2283 } else if (LOCAL_LOGV) { 2284 Log.v(mTag, "handleAppVisibility() enabling visibility when removed"); 2285 } 2286 } 2287 } 2288 2289 void handleGetNewSurface() { 2290 mNewSurfaceNeeded = true; 2291 mFullRedrawNeeded = true; 2292 scheduleTraversals(); 2293 } 2294 2295 /** Handles messages {@link #MSG_RESIZED} and {@link #MSG_RESIZED_REPORT}. */ 2296 private void handleResized(ClientWindowFrames frames, boolean reportDraw, 2297 MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout, 2298 boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing, 2299 @Nullable ActivityWindowInfo activityWindowInfo) { 2300 if (!mAdded) { 2301 return; 2302 } 2303 2304 onClientWindowFramesChanged(frames); 2305 2306 CompatibilityInfo.applyOverrideIfNeeded(mergedConfiguration); 2307 final Rect frame = frames.frame; 2308 final Rect displayFrame = frames.displayFrame; 2309 final Rect attachedFrame = frames.attachedFrame; 2310 if (mTranslator != null) { 2311 mTranslator.translateRectInScreenToAppWindow(frame); 2312 mTranslator.translateRectInScreenToAppWindow(displayFrame); 2313 mTranslator.translateRectInScreenToAppWindow(attachedFrame); 2314 } 2315 onInsetsStateChanged(insetsState); 2316 final float compatScale = frames.compatScale; 2317 final boolean frameChanged = !mWinFrame.equals(frame); 2318 final boolean shouldReportActivityWindowInfoChanged = 2319 // Can be null if callbacks is not set 2320 mLastReportedActivityWindowInfo != null 2321 // Can be null if not activity window 2322 && activityWindowInfo != null 2323 && !mLastReportedActivityWindowInfo.equals(activityWindowInfo); 2324 final boolean configChanged = !mLastReportedMergedConfiguration.equals(mergedConfiguration) 2325 || shouldReportActivityWindowInfoChanged; 2326 final boolean attachedFrameChanged = 2327 !Objects.equals(mTmpFrames.attachedFrame, attachedFrame); 2328 final boolean displayChanged = mDisplay.getDisplayId() != displayId; 2329 final boolean compatScaleChanged = mTmpFrames.compatScale != compatScale; 2330 final boolean dragResizingChanged = mPendingDragResizing != dragResizing; 2331 if (!reportDraw && !frameChanged && !configChanged && !attachedFrameChanged 2332 && !displayChanged && !forceLayout 2333 && !compatScaleChanged && !dragResizingChanged) { 2334 return; 2335 } 2336 2337 mPendingDragResizing = dragResizing; 2338 mTmpFrames.compatScale = compatScale; 2339 mInvCompatScale = 1f / compatScale; 2340 2341 if (configChanged) { 2342 // If configuration changed - notify about that and, maybe, about move to display. 2343 performConfigurationChange(mergedConfiguration, false /* force */, 2344 displayChanged ? displayId : INVALID_DISPLAY /* same display */, 2345 activityWindowInfo); 2346 } else if (displayChanged) { 2347 // Moved to display without config change - report last applied one. 2348 onMovedToDisplay(displayId, mLastConfigurationFromResources); 2349 } 2350 2351 setFrame(frame, false /* withinRelayout */); 2352 mTmpFrames.displayFrame.set(displayFrame); 2353 if (mTmpFrames.attachedFrame != null && attachedFrame != null) { 2354 mTmpFrames.attachedFrame.set(attachedFrame); 2355 } 2356 2357 if (mDragResizing && mUseMTRenderer) { 2358 boolean fullscreen = frame.equals(mPendingBackDropFrame); 2359 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { 2360 mWindowCallbacks.get(i).onWindowSizeIsChanging(mPendingBackDropFrame, fullscreen, 2361 mAttachInfo.mVisibleInsets, mAttachInfo.mStableInsets); 2362 } 2363 } 2364 2365 mForceNextWindowRelayout |= forceLayout; 2366 mPendingAlwaysConsumeSystemBars = alwaysConsumeSystemBars; 2367 mSyncSeqId = syncSeqId > mSyncSeqId ? syncSeqId : mSyncSeqId; 2368 2369 if (reportDraw) { 2370 reportNextDraw("resized"); 2371 } 2372 2373 if (mView != null && (frameChanged || configChanged)) { 2374 forceLayout(mView); 2375 } 2376 requestLayout(); 2377 } 2378 2379 /** Handles messages {@link #MSG_INSETS_CONTROL_CHANGED}. */ 2380 @VisibleForTesting handleInsetsControlChanged(@onNull InsetsState insetsState, @NonNull InsetsSourceControl.Array activeControls)2381 public void handleInsetsControlChanged(@NonNull InsetsState insetsState, 2382 @NonNull InsetsSourceControl.Array activeControls) { 2383 // Deliver state change before control change, such that: 2384 // a) When gaining control, controller can compare with server state to evaluate 2385 // whether it needs to run animation. 2386 // b) When loosing control, controller can restore server state by taking last 2387 // dispatched state as truth. 2388 onInsetsStateChanged(insetsState); 2389 onActiveControlsChanged(activeControls); 2390 } 2391 onClientWindowFramesChanged(@onNull ClientWindowFrames inOutFrames)2392 private void onClientWindowFramesChanged(@NonNull ClientWindowFrames inOutFrames) { 2393 if (isIncomingSeqStale(mLastReportedFrames.seq, inOutFrames.seq)) { 2394 // If the incoming is stale, use the last reported instead. 2395 inOutFrames.setTo(mLastReportedFrames); 2396 } else { 2397 // Keep track of the latest. 2398 mLastReportedFrames.setTo(inOutFrames); 2399 } 2400 } 2401 onInsetsStateChanged(@onNull InsetsState insetsState)2402 private void onInsetsStateChanged(@NonNull InsetsState insetsState) { 2403 if (isIncomingSeqStale(mLastReportedInsetsStateSeq, insetsState.getSeq())) { 2404 // The incoming is stale. Skip. 2405 return; 2406 } 2407 // Keep track of the latest. 2408 mLastReportedInsetsStateSeq = insetsState.getSeq(); 2409 2410 if (mTranslator != null) { 2411 mTranslator.translateInsetsStateInScreenToAppWindow(insetsState); 2412 } 2413 mInsetsController.onStateChanged(insetsState); 2414 } 2415 onActiveControlsChanged(@onNull InsetsSourceControl.Array activeControls)2416 private void onActiveControlsChanged(@NonNull InsetsSourceControl.Array activeControls) { 2417 if (!mAdded) { 2418 // Do not update the last report if window is not added yet. 2419 activeControls.release(); 2420 return; 2421 } 2422 2423 if (isIncomingSeqStale(mLastReportedActiveControlsSeq, activeControls.getSeq())) { 2424 // The incoming is stale. Skip. 2425 activeControls.release(); 2426 return; 2427 } 2428 // Keep track of the latest. 2429 mLastReportedActiveControlsSeq = activeControls.getSeq(); 2430 2431 final InsetsSourceControl[] controls = activeControls.get(); 2432 if (mTranslator != null) { 2433 mTranslator.translateSourceControlsInScreenToAppWindow(controls); 2434 } 2435 mInsetsController.onControlsChanged(controls); 2436 } 2437 2438 private final DisplayListener mDisplayListener = new DisplayListener() { 2439 @Override 2440 public void onDisplayChanged(int displayId) { 2441 if (mExtraDisplayListenerLogging) { 2442 Slog.i(mTag, "Received onDisplayChanged - " + mView); 2443 } 2444 if (mView != null && mDisplay.getDisplayId() == displayId) { 2445 final int oldDisplayState = mAttachInfo.mDisplayState; 2446 final int newDisplayState = mDisplay.getState(); 2447 if (mExtraDisplayListenerLogging) { 2448 Slog.i(mTag, "DisplayState - old: " + oldDisplayState 2449 + ", new: " + newDisplayState); 2450 } 2451 if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) { 2452 Trace.traceCounter(Trace.TRACE_TAG_WINDOW_MANAGER, 2453 "vri#screenState[" + mTag + "] state=", newDisplayState); 2454 } 2455 if (oldDisplayState != newDisplayState) { 2456 mAttachInfo.mDisplayState = newDisplayState; 2457 pokeDrawLockIfNeeded(); 2458 if (oldDisplayState != Display.STATE_UNKNOWN) { 2459 final int oldScreenState = toViewScreenState(oldDisplayState); 2460 final int newScreenState = toViewScreenState(newDisplayState); 2461 if (oldScreenState != newScreenState) { 2462 mView.dispatchScreenStateChanged(newScreenState); 2463 } 2464 if (oldDisplayState == Display.STATE_OFF) { 2465 // Draw was suppressed so we need to for it to happen here. 2466 mFullRedrawNeeded = true; 2467 scheduleTraversals(); 2468 } 2469 } 2470 } 2471 } 2472 } 2473 2474 @Override 2475 public void onDisplayRemoved(int displayId) { 2476 } 2477 2478 @Override 2479 public void onDisplayAdded(int displayId) { 2480 } 2481 2482 private int toViewScreenState(int displayState) { 2483 return displayState == Display.STATE_OFF ? 2484 View.SCREEN_STATE_OFF : View.SCREEN_STATE_ON; 2485 } 2486 }; 2487 2488 /** 2489 * Notify about move to a different display. 2490 * @param displayId The id of the display where this view root is moved to. 2491 * @param config Configuration of the resources on new display after move. 2492 * 2493 * @hide 2494 */ onMovedToDisplay(int displayId, Configuration config)2495 public void onMovedToDisplay(int displayId, Configuration config) { 2496 if (mDisplay.getDisplayId() == displayId) { 2497 return; 2498 } 2499 2500 // Get new instance of display based on current display adjustments. It may be updated later 2501 // if moving between the displays also involved a configuration change. 2502 updateInternalDisplay(displayId, mView.getResources()); 2503 mImeFocusController.onMovedToDisplay(); 2504 mAttachInfo.mDisplayState = mDisplay.getState(); 2505 // Internal state updated, now notify the view hierarchy. 2506 mView.dispatchMovedToDisplay(mDisplay, config); 2507 } 2508 2509 /** 2510 * Updates {@link #mDisplay} to the display object corresponding to {@param displayId}. 2511 * Uses DEFAULT_DISPLAY if there isn't a display object in the system corresponding 2512 * to {@param displayId}. 2513 */ updateInternalDisplay(int displayId, Resources resources)2514 private void updateInternalDisplay(int displayId, Resources resources) { 2515 final Display preferredDisplay = 2516 ResourcesManager.getInstance().getAdjustedDisplay(displayId, resources); 2517 mHdrRenderState.stopListening(); 2518 if (preferredDisplay == null) { 2519 // Fallback to use default display. 2520 Slog.w(TAG, "Cannot get desired display with Id: " + displayId); 2521 mDisplay = ResourcesManager.getInstance() 2522 .getAdjustedDisplay(DEFAULT_DISPLAY, resources); 2523 } else { 2524 mDisplay = preferredDisplay; 2525 } 2526 mHdrRenderState.startListening(); 2527 mContext.updateDisplay(mDisplay.getDisplayId()); 2528 } 2529 pokeDrawLockIfNeeded()2530 void pokeDrawLockIfNeeded() { 2531 // Disable DRAW_WAKE_LOCK starting U. Otherwise, only need to acquire it for DOZE state. 2532 if (mDisableDrawWakeLock || mAttachInfo.mDisplayState != Display.STATE_DOZE) { 2533 // In DOZE_SUSPEND, Android shouldn't control the display; therefore we only poke the 2534 // draw wake lock when display state is DOZE. Noted that Display#isDozeState includes 2535 // DOZE_SUSPEND as well, so, it's not feasible here. 2536 return; 2537 } 2538 if (mWindowAttributes.type != WindowManager.LayoutParams.TYPE_BASE_APPLICATION) { 2539 // Non-activity windows should be responsible to hold wake lock by themself, because 2540 // usually they are system windows. 2541 return; 2542 } 2543 if (mAdded && mTraversalScheduled && mAttachInfo.mHasWindowFocus) { 2544 try { 2545 mWindowSession.pokeDrawLock(mWindow); 2546 } catch (RemoteException ex) { 2547 // System server died, oh well. 2548 } 2549 } 2550 } 2551 2552 @Override requestFitSystemWindows()2553 public void requestFitSystemWindows() { 2554 checkThread(); 2555 mApplyInsetsRequested = true; 2556 scheduleTraversals(); 2557 } 2558 notifyInsetsChanged()2559 void notifyInsetsChanged() { 2560 mApplyInsetsRequested = true; 2561 requestLayout(); 2562 2563 // See comment for View.sForceLayoutWhenInsetsChanged 2564 if (View.sForceLayoutWhenInsetsChanged && mView != null 2565 && (mWindowAttributes.softInputMode & SOFT_INPUT_MASK_ADJUST) 2566 == SOFT_INPUT_ADJUST_RESIZE) { 2567 forceLayout(mView); 2568 } 2569 2570 // If this changes during traversal, no need to schedule another one as it will dispatch it 2571 // during the current traversal. 2572 if (!mIsInTraversal) { 2573 scheduleTraversals(); 2574 } 2575 } 2576 2577 /** 2578 * Notify the when the animating insets types have changed. 2579 * 2580 * @hide 2581 */ updateAnimatingTypes(@nsetsType int animatingTypes, @Nullable ImeTracker.Token statsToken)2582 public void updateAnimatingTypes(@InsetsType int animatingTypes, 2583 @Nullable ImeTracker.Token statsToken) { 2584 if (sToolkitSetFrameRateReadOnlyFlagValue) { 2585 boolean running = animatingTypes != 0; 2586 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 2587 Trace.instant(Trace.TRACE_TAG_VIEW, 2588 TextUtils.formatSimple("notifyInsetsAnimationRunningStateChanged(%s)", 2589 Boolean.toString(running))); 2590 } 2591 mInsetsAnimationRunning = running; 2592 try { 2593 mWindowSession.updateAnimatingTypes(mWindow, animatingTypes, statsToken); 2594 } catch (RemoteException e) { 2595 } 2596 } 2597 } 2598 2599 @Override requestLayout()2600 public void requestLayout() { 2601 if (!mHandlingLayoutInLayoutRequest) { 2602 checkThread(); 2603 mLayoutRequested = true; 2604 scheduleTraversals(); 2605 } 2606 } 2607 2608 @Override isLayoutRequested()2609 public boolean isLayoutRequested() { 2610 return mLayoutRequested; 2611 } 2612 2613 @Override onDescendantInvalidated(@onNull View child, @NonNull View descendant)2614 public void onDescendantInvalidated(@NonNull View child, @NonNull View descendant) { 2615 if (sToolkitEnableInvalidateCheckThreadFlagValue) { 2616 checkThread(); 2617 } 2618 if ((descendant.mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 2619 mIsAnimating = true; 2620 } 2621 invalidate(); 2622 } 2623 2624 @UnsupportedAppUsage invalidate()2625 void invalidate() { 2626 mDirty.set(0, 0, mWidth, mHeight); 2627 if (!mWillDrawSoon) { 2628 scheduleTraversals(); 2629 } 2630 } 2631 invalidateWorld(View view)2632 void invalidateWorld(View view) { 2633 view.invalidate(); 2634 if (view instanceof ViewGroup) { 2635 ViewGroup parent = (ViewGroup) view; 2636 for (int i = 0; i < parent.getChildCount(); i++) { 2637 invalidateWorld(parent.getChildAt(i)); 2638 } 2639 } 2640 } 2641 2642 @Override invalidateChild(View child, Rect dirty)2643 public void invalidateChild(View child, Rect dirty) { 2644 invalidateChildInParent(null, dirty); 2645 } 2646 2647 @Override invalidateChildInParent(int[] location, Rect dirty)2648 public ViewParent invalidateChildInParent(int[] location, Rect dirty) { 2649 checkThread(); 2650 if (DEBUG_DRAW) Log.v(mTag, "Invalidate child: " + dirty); 2651 2652 if (dirty == null) { 2653 invalidate(); 2654 return null; 2655 } else if (dirty.isEmpty() && !mIsAnimating) { 2656 return null; 2657 } 2658 2659 if (mCurScrollY != 0 || mTranslator != null) { 2660 mTempRect.set(dirty); 2661 dirty = mTempRect; 2662 if (mCurScrollY != 0) { 2663 dirty.offset(0, -mCurScrollY); 2664 } 2665 if (mTranslator != null) { 2666 mTranslator.translateRectInAppWindowToScreen(dirty); 2667 } 2668 if (mAttachInfo.mScalingRequired) { 2669 dirty.inset(-1, -1); 2670 } 2671 } 2672 2673 invalidateRectOnScreen(dirty); 2674 2675 return null; 2676 } 2677 invalidateRectOnScreen(Rect dirty)2678 private void invalidateRectOnScreen(Rect dirty) { 2679 if (DEBUG_DRAW) Log.v(mTag, "invalidateRectOnScreen: " + dirty); 2680 final Rect localDirty = mDirty; 2681 2682 // Add the new dirty rect to the current one 2683 localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom); 2684 // Intersect with the bounds of the window to skip 2685 // updates that lie outside of the visible region 2686 final float appScale = mAttachInfo.mApplicationScale; 2687 final boolean intersected = localDirty.intersect(0, 0, 2688 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f)); 2689 if (!intersected) { 2690 localDirty.setEmpty(); 2691 } 2692 if (!mWillDrawSoon && (intersected || mIsAnimating)) { 2693 scheduleTraversals(); 2694 } 2695 } 2696 setIsAmbientMode(boolean ambient)2697 public void setIsAmbientMode(boolean ambient) { 2698 mIsAmbientMode = ambient; 2699 } 2700 setWindowStopped(boolean stopped)2701 void setWindowStopped(boolean stopped) { 2702 checkThread(); 2703 if (mStopped != stopped) { 2704 mStopped = stopped; 2705 final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer; 2706 if (renderer != null) { 2707 if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped); 2708 renderer.setStopped(mStopped); 2709 } 2710 if (!mStopped) { 2711 // Make sure that relayoutWindow will be called to get valid surface because 2712 // the previous surface may have been released. 2713 mAppVisibilityChanged = true; 2714 scheduleTraversals(); 2715 } else { 2716 if (renderer != null) { 2717 renderer.destroyHardwareResources(mView); 2718 } 2719 2720 if (mSurface.isValid()) { 2721 if (mSurfaceHolder != null) { 2722 notifyHolderSurfaceDestroyed(); 2723 } 2724 notifySurfaceDestroyed(); 2725 } 2726 destroySurface(); 2727 2728 // Reset so they can be sent again for warm starts. 2729 mAppStartTimestampsSent.set(false); 2730 mAppStartTrackingStarted = false; 2731 mRenderThreadDrawStartTimeNs = -1; 2732 mFirstFramePresentedTimeNs = -1; 2733 } 2734 } 2735 logColorMode(mCurrentColorMode, true); 2736 } 2737 2738 2739 /** Register callbacks to be notified when the ViewRootImpl surface changes. */ 2740 public interface SurfaceChangedCallback { surfaceCreated(Transaction t)2741 void surfaceCreated(Transaction t); surfaceReplaced(Transaction t)2742 void surfaceReplaced(Transaction t); surfaceDestroyed()2743 void surfaceDestroyed(); vriDrawStarted(boolean isWmSync)2744 default void vriDrawStarted(boolean isWmSync) {}; 2745 } 2746 2747 private final ArrayList<SurfaceChangedCallback> mSurfaceChangedCallbacks = new ArrayList<>(); addSurfaceChangedCallback(SurfaceChangedCallback c)2748 public void addSurfaceChangedCallback(SurfaceChangedCallback c) { 2749 mSurfaceChangedCallbacks.add(c); 2750 } 2751 removeSurfaceChangedCallback(SurfaceChangedCallback c)2752 public void removeSurfaceChangedCallback(SurfaceChangedCallback c) { 2753 mSurfaceChangedCallbacks.remove(c); 2754 } 2755 notifySurfaceCreated(Transaction t)2756 private void notifySurfaceCreated(Transaction t) { 2757 for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) { 2758 mSurfaceChangedCallbacks.get(i).surfaceCreated(t); 2759 } 2760 } 2761 2762 /** 2763 * Notify listeners when the ViewRootImpl surface has been replaced. This callback will not be 2764 * called if a new surface is created, only if the valid surface has been replaced with another 2765 * valid surface. 2766 */ notifySurfaceReplaced(Transaction t)2767 private void notifySurfaceReplaced(Transaction t) { 2768 for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) { 2769 mSurfaceChangedCallbacks.get(i).surfaceReplaced(t); 2770 } 2771 } 2772 notifySurfaceDestroyed()2773 private void notifySurfaceDestroyed() { 2774 for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) { 2775 mSurfaceChangedCallbacks.get(i).surfaceDestroyed(); 2776 } 2777 } 2778 notifyDrawStarted(boolean isWmSync)2779 private void notifyDrawStarted(boolean isWmSync) { 2780 for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) { 2781 mSurfaceChangedCallbacks.get(i).vriDrawStarted(isWmSync); 2782 } 2783 } 2784 2785 /** 2786 * @return child layer with the same bounds as its parent {@code mSurface} and cropped to the 2787 * surface insets. If the layer does not exist, it is created. 2788 * 2789 * <p>Parenting to this layer will ensure that its children are cropped by the view's surface 2790 * insets. 2791 */ updateAndGetBoundsLayer(Transaction t)2792 public SurfaceControl updateAndGetBoundsLayer(Transaction t) { 2793 if (mBoundsLayer == null) { 2794 mBoundsLayer = new SurfaceControl.Builder() 2795 .setContainerLayer() 2796 .setName("Bounds for - " + getTitle().toString()) 2797 .setParent(getSurfaceControl()) 2798 .setCallsite("ViewRootImpl.getBoundsLayer") 2799 .build(); 2800 setBoundsLayerCrop(t); 2801 t.show(mBoundsLayer); 2802 } 2803 return mBoundsLayer; 2804 } 2805 updateBlastSurfaceIfNeeded()2806 void updateBlastSurfaceIfNeeded() { 2807 if (!mSurfaceControl.isValid()) { 2808 return; 2809 } 2810 2811 if (mBlastBufferQueue != null && mBlastBufferQueue.isSameSurfaceControl(mSurfaceControl)) { 2812 mBlastBufferQueue.update(mSurfaceControl, 2813 mSurfaceSize.x, mSurfaceSize.y, 2814 mWindowAttributes.format); 2815 return; 2816 } 2817 2818 // If the SurfaceControl has been updated, destroy and recreate the BBQ to reset the BQ and 2819 // BBQ states. 2820 if (mBlastBufferQueue != null) { 2821 mBlastBufferQueue.destroy(); 2822 } 2823 mBlastBufferQueue = new BLASTBufferQueue(mTag, true /* updateDestinationFrame */); 2824 // If we create and destroy BBQ without recreating the SurfaceControl, we can end up 2825 // queuing buffers on multiple apply tokens causing out of order buffer submissions. We 2826 // fix this by setting the same apply token on all BBQs created by this VRI. 2827 mBlastBufferQueue.setApplyToken(mBbqApplyToken); 2828 mBlastBufferQueue.update(mSurfaceControl, mSurfaceSize.x, mSurfaceSize.y, 2829 mWindowAttributes.format); 2830 mBlastBufferQueue.setTransactionHangCallback(sTransactionHangCallback); 2831 mBlastBufferQueue.setWaitForBufferReleaseCallback(mChoreographer::onWaitForBufferRelease); 2832 Surface blastSurface; 2833 if (addSchandleToVriSurface()) { 2834 blastSurface = mBlastBufferQueue.createSurfaceWithHandle(); 2835 } else { 2836 blastSurface = mBlastBufferQueue.createSurface(); 2837 } 2838 // Only call transferFrom if the surface has changed to prevent inc the generation ID and 2839 // causing EGL resources to be recreated. 2840 mSurface.transferFrom(blastSurface); 2841 2842 // Since the SurfaceControl is a VRI, indicate that it can recover from buffer stuffing. 2843 mTransaction.setRecoverableFromBufferStuffing(mSurfaceControl).applyAsyncUnsafe(); 2844 } 2845 setBoundsLayerCrop(Transaction t)2846 private void setBoundsLayerCrop(Transaction t) { 2847 // Adjust of insets and update the bounds layer so child surfaces do not draw into 2848 // the surface inset region. 2849 mTempRect.set(0, 0, mSurfaceSize.x, mSurfaceSize.y); 2850 mTempRect.inset(mWindowAttributes.surfaceInsets.left, 2851 mWindowAttributes.surfaceInsets.top, 2852 mWindowAttributes.surfaceInsets.right, mWindowAttributes.surfaceInsets.bottom); 2853 mTempRect.inset(mChildBoundingInsets.left, mChildBoundingInsets.top, 2854 mChildBoundingInsets.right, mChildBoundingInsets.bottom); 2855 t.setWindowCrop(mBoundsLayer, mTempRect); 2856 } 2857 2858 /** 2859 * Called after window layout to update the bounds surface. If the surface insets have changed 2860 * or the surface has resized, update the bounds surface. 2861 */ updateBoundsLayer(SurfaceControl.Transaction t)2862 private boolean updateBoundsLayer(SurfaceControl.Transaction t) { 2863 if (mBoundsLayer != null) { 2864 setBoundsLayerCrop(t); 2865 return true; 2866 } 2867 return false; 2868 } 2869 prepareSurfaces()2870 private void prepareSurfaces() { 2871 final SurfaceControl.Transaction t = mTransaction; 2872 final SurfaceControl sc = getSurfaceControl(); 2873 if (!sc.isValid()) return; 2874 2875 if (updateBoundsLayer(t)) { 2876 applyTransactionOnDraw(t); 2877 } 2878 2879 // Set the frame rate selection strategy to FRAME_RATE_SELECTION_STRATEGY_SELF 2880 // This strategy ensures that the frame rate specifications do not cascade down to 2881 // the descendant layers. This is particularly important for applications like Chrome, 2882 // where child surfaces should adhere to default behavior instead of no preference. 2883 // This issue only happens when ViewRootImpl calls setFrameRateCategory. This is 2884 // no longer needed if the dVRR feature is disabled. 2885 if (shouldEnableDvrr()) { 2886 try { 2887 if (sToolkitFrameRateFunctionEnablingReadOnlyFlagValue) { 2888 mFrameRateTransaction.setFrameRateSelectionStrategy(sc, 2889 sc.FRAME_RATE_SELECTION_STRATEGY_SELF).applyAsyncUnsafe(); 2890 } 2891 } catch (Exception e) { 2892 Log.e(mTag, "Unable to set frame rate selection strategy ", e); 2893 } 2894 } 2895 } 2896 destroySurface()2897 private void destroySurface() { 2898 if (mBoundsLayer != null) { 2899 mBoundsLayer.release(); 2900 mBoundsLayer = null; 2901 } 2902 mSurface.release(); 2903 mSurfaceControl.release(); 2904 2905 if (mBlastBufferQueue != null) { 2906 mBlastBufferQueue.destroy(); 2907 mBlastBufferQueue = null; 2908 } 2909 2910 if (mAttachInfo.mThreadedRenderer != null) { 2911 mAttachInfo.mThreadedRenderer.setSurfaceControl(null, null); 2912 } 2913 2914 // Also reset the VRR relevant values. 2915 mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_DEFAULT; 2916 mLastPreferredFrameRateCategory = FRAME_RATE_CATEGORY_DEFAULT; 2917 mPreferredFrameRate = 0; 2918 mLastPreferredFrameRate = 0; 2919 } 2920 2921 /** 2922 * Block the input events during an Activity Transition. The KEYCODE_BACK event is allowed 2923 * through to allow quick reversal of the Activity Transition. 2924 * 2925 * @param paused true to pause, false to resume. 2926 */ setPausedForTransition(boolean paused)2927 public void setPausedForTransition(boolean paused) { 2928 mPausedForTransition = paused; 2929 } 2930 2931 @Override getParent()2932 public ViewParent getParent() { 2933 return null; 2934 } 2935 2936 @Override getChildVisibleRect(View child, Rect r, android.graphics.Point offset)2937 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) { 2938 if (child != mView) { 2939 throw new RuntimeException("child is not mine, honest!"); 2940 } 2941 // Note: don't apply scroll offset, because we want to know its 2942 // visibility in the virtual canvas being given to the view hierarchy. 2943 return r.intersect(0, 0, mWidth, mHeight); 2944 } 2945 2946 @Override getChildLocalHitRegion(@onNull View child, @NonNull Region region, @NonNull Matrix matrix, boolean isHover)2947 public boolean getChildLocalHitRegion(@NonNull View child, @NonNull Region region, 2948 @NonNull Matrix matrix, boolean isHover) { 2949 if (child != mView) { 2950 throw new IllegalArgumentException("child " + child + " is not the root view " 2951 + mView + " managed by this ViewRootImpl"); 2952 } 2953 2954 RectF rectF = new RectF(0, 0, mWidth, mHeight); 2955 matrix.mapRect(rectF); 2956 // Note: don't apply scroll offset, because we want to know its 2957 // visibility in the virtual canvas being given to the view hierarchy. 2958 return region.op(Math.round(rectF.left), Math.round(rectF.top), 2959 Math.round(rectF.right), Math.round(rectF.bottom), Region.Op.INTERSECT); 2960 } 2961 2962 @Override bringChildToFront(View child)2963 public void bringChildToFront(View child) { 2964 } 2965 2966 // keep in sync with getHostVisibilityReason getHostVisibility()2967 int getHostVisibility() { 2968 return mView != null && (mAppVisible || mForceDecorViewVisibility) 2969 ? mView.getVisibility() : View.GONE; 2970 } 2971 getHostVisibilityReason()2972 String getHostVisibilityReason() { 2973 if (mView == null) { 2974 return "mView is null"; 2975 } 2976 if (!mAppVisible && !mForceDecorViewVisibility) { 2977 return "!mAppVisible && !mForceDecorViewVisibility"; 2978 } 2979 switch (mView.getVisibility()) { 2980 case View.VISIBLE: return "View.VISIBLE"; 2981 case View.GONE: return "View.GONE"; 2982 case View.INVISIBLE: return "View.INVISIBLE"; 2983 default: return ""; 2984 } 2985 } 2986 2987 /** 2988 * Add LayoutTransition to the list of transitions to be started in the next traversal. 2989 * This list will be cleared after the transitions on the list are start()'ed. These 2990 * transitionsa re added by LayoutTransition itself when it sets up animations. The setup 2991 * happens during the layout phase of traversal, which we want to complete before any of the 2992 * animations are started (because those animations may side-effect properties that layout 2993 * depends upon, like the bounding rectangles of the affected views). So we add the transition 2994 * to the list and it is started just prior to starting the drawing phase of traversal. 2995 * 2996 * @param transition The LayoutTransition to be started on the next traversal. 2997 * 2998 * @hide 2999 */ requestTransitionStart(LayoutTransition transition)3000 public void requestTransitionStart(LayoutTransition transition) { 3001 if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) { 3002 if (mPendingTransitions == null) { 3003 mPendingTransitions = new ArrayList<LayoutTransition>(); 3004 } 3005 mPendingTransitions.add(transition); 3006 } 3007 } 3008 3009 /** 3010 * Notifies the HardwareRenderer that a new frame will be coming soon. 3011 * Currently only {@link ThreadedRenderer} cares about this, and uses 3012 * this knowledge to adjust the scheduling of off-thread animations 3013 */ notifyRendererOfFramePending()3014 void notifyRendererOfFramePending() { 3015 if (mAttachInfo.mThreadedRenderer != null) { 3016 mAttachInfo.mThreadedRenderer.notifyFramePending(); 3017 } 3018 } 3019 3020 /** 3021 * Notifies the HardwareRenderer of an expensive upcoming frame, to 3022 * allow better handling of power and scheduling requirements. 3023 * 3024 * @hide 3025 */ notifyRendererOfExpensiveFrame()3026 public void notifyRendererOfExpensiveFrame() { 3027 if (mAttachInfo.mThreadedRenderer != null) { 3028 mAttachInfo.mThreadedRenderer.notifyExpensiveFrame(); 3029 } 3030 } 3031 3032 /** 3033 * Same as notifyRendererOfExpensiveFrame(), but adding {@code reason} for tracing. 3034 * 3035 * @hide 3036 */ notifyRendererOfExpensiveFrame(String reason)3037 public void notifyRendererOfExpensiveFrame(String reason) { 3038 Trace.traceBegin(Trace.TRACE_TAG_VIEW, reason); 3039 try { 3040 notifyRendererOfExpensiveFrame(); 3041 } finally { 3042 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 3043 } 3044 } 3045 3046 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) scheduleTraversals()3047 void scheduleTraversals() { 3048 if (!mTraversalScheduled) { 3049 mTraversalScheduled = true; 3050 mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); 3051 mChoreographer.postCallback( 3052 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); 3053 notifyRendererOfFramePending(); 3054 pokeDrawLockIfNeeded(); 3055 } 3056 } 3057 unscheduleTraversals()3058 void unscheduleTraversals() { 3059 if (mTraversalScheduled) { 3060 mTraversalScheduled = false; 3061 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); 3062 mChoreographer.removeCallbacks( 3063 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); 3064 } 3065 } 3066 doTraversal()3067 void doTraversal() { 3068 if (mTraversalScheduled) { 3069 mTraversalScheduled = false; 3070 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); 3071 3072 if (mProfile) { 3073 Debug.startMethodTracing("ViewAncestor"); 3074 } 3075 3076 performTraversals(); 3077 3078 if (mProfile) { 3079 Debug.stopMethodTracing(); 3080 mProfile = false; 3081 } 3082 } 3083 } 3084 applyKeepScreenOnFlag(WindowManager.LayoutParams params)3085 private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) { 3086 // Update window's global keep screen on flag: if a view has requested 3087 // that the screen be kept on, then it is always set; otherwise, it is 3088 // set to whatever the client last requested for the global state. 3089 if (mAttachInfo.mKeepScreenOn) { 3090 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; 3091 } else { 3092 params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) 3093 | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 3094 } 3095 } 3096 collectViewAttributes()3097 private boolean collectViewAttributes() { 3098 if (mAttachInfo.mRecomputeGlobalAttributes) { 3099 //Log.i(mTag, "Computing view hierarchy attributes!"); 3100 mAttachInfo.mRecomputeGlobalAttributes = false; 3101 boolean oldScreenOn = mAttachInfo.mKeepScreenOn; 3102 mAttachInfo.mKeepScreenOn = false; 3103 mAttachInfo.mSystemUiVisibility = 0; 3104 mAttachInfo.mHasSystemUiListeners = false; 3105 mView.dispatchCollectViewAttributes(mAttachInfo, 0); 3106 mAttachInfo.mSystemUiVisibility &= ~mAttachInfo.mDisabledSystemUiVisibility; 3107 WindowManager.LayoutParams params = mWindowAttributes; 3108 mAttachInfo.mSystemUiVisibility |= getImpliedSystemUiVisibility(params); 3109 mCompatibleVisibilityInfo.globalVisibility = 3110 (mCompatibleVisibilityInfo.globalVisibility & ~View.SYSTEM_UI_FLAG_LOW_PROFILE) 3111 | (mAttachInfo.mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE); 3112 dispatchDispatchSystemUiVisibilityChanged(); 3113 if (mAttachInfo.mKeepScreenOn != oldScreenOn 3114 || mAttachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility 3115 || mAttachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) { 3116 applyKeepScreenOnFlag(params); 3117 params.subtreeSystemUiVisibility = mAttachInfo.mSystemUiVisibility; 3118 params.hasSystemUiListeners = mAttachInfo.mHasSystemUiListeners; 3119 mView.dispatchWindowSystemUiVisiblityChanged(mAttachInfo.mSystemUiVisibility); 3120 return true; 3121 } 3122 } 3123 return false; 3124 } 3125 getImpliedSystemUiVisibility(WindowManager.LayoutParams params)3126 private int getImpliedSystemUiVisibility(WindowManager.LayoutParams params) { 3127 int vis = 0; 3128 // Translucent decor window flags imply stable system ui visibility. 3129 if ((params.flags & FLAG_TRANSLUCENT_STATUS) != 0) { 3130 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 3131 } 3132 if ((params.flags & FLAG_TRANSLUCENT_NAVIGATION) != 0) { 3133 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; 3134 } 3135 return vis; 3136 } 3137 3138 /** 3139 * Update the compatible system UI visibility for dispatching it to the legacy app. 3140 */ updateCompatSysUiVisibility(@nsetsType int visibleTypes, @InsetsType int requestedVisibleTypes, @InsetsType int controllableTypes)3141 void updateCompatSysUiVisibility(@InsetsType int visibleTypes, 3142 @InsetsType int requestedVisibleTypes, @InsetsType int controllableTypes) { 3143 // If a type is controllable, the visibility is overridden by the requested visibility. 3144 visibleTypes = 3145 (requestedVisibleTypes & controllableTypes) | (visibleTypes & ~controllableTypes); 3146 3147 updateCompatSystemUiVisibilityInfo(SYSTEM_UI_FLAG_FULLSCREEN, Type.statusBars(), 3148 visibleTypes, controllableTypes); 3149 updateCompatSystemUiVisibilityInfo(SYSTEM_UI_FLAG_HIDE_NAVIGATION, Type.navigationBars(), 3150 visibleTypes, controllableTypes); 3151 dispatchDispatchSystemUiVisibilityChanged(); 3152 } 3153 updateCompatSystemUiVisibilityInfo(int systemUiFlag, @InsetsType int insetsType, @InsetsType int visibleTypes, @InsetsType int controllableTypes)3154 private void updateCompatSystemUiVisibilityInfo(int systemUiFlag, @InsetsType int insetsType, 3155 @InsetsType int visibleTypes, @InsetsType int controllableTypes) { 3156 final SystemUiVisibilityInfo info = mCompatibleVisibilityInfo; 3157 final boolean willBeVisible = (visibleTypes & insetsType) != 0; 3158 final boolean hasControl = (controllableTypes & insetsType) != 0; 3159 final boolean wasInvisible = (mAttachInfo.mSystemUiVisibility & systemUiFlag) != 0; 3160 if (willBeVisible) { 3161 info.globalVisibility &= ~systemUiFlag; 3162 if (hasControl && wasInvisible) { 3163 // The local system UI visibility can only be cleared while we have the control. 3164 info.localChanges |= systemUiFlag; 3165 } 3166 } else { 3167 info.globalVisibility |= systemUiFlag; 3168 info.localChanges &= ~systemUiFlag; 3169 } 3170 } 3171 3172 /** 3173 * If the system is forcing showing any system bar, the legacy low profile flag should be 3174 * cleared for compatibility. 3175 * 3176 * @param showTypes {@link InsetsType types} shown by the system. 3177 * @param fromIme {@code true} if the invocation is from IME. 3178 */ clearLowProfileModeIfNeeded(@nsetsType int showTypes, boolean fromIme)3179 private void clearLowProfileModeIfNeeded(@InsetsType int showTypes, boolean fromIme) { 3180 final SystemUiVisibilityInfo info = mCompatibleVisibilityInfo; 3181 if ((showTypes & Type.systemBars()) != 0 && !fromIme 3182 && (info.globalVisibility & SYSTEM_UI_FLAG_LOW_PROFILE) != 0) { 3183 info.globalVisibility &= ~SYSTEM_UI_FLAG_LOW_PROFILE; 3184 info.localChanges |= SYSTEM_UI_FLAG_LOW_PROFILE; 3185 dispatchDispatchSystemUiVisibilityChanged(); 3186 } 3187 } 3188 dispatchDispatchSystemUiVisibilityChanged()3189 private void dispatchDispatchSystemUiVisibilityChanged() { 3190 if (mDispatchedSystemUiVisibility != mCompatibleVisibilityInfo.globalVisibility) { 3191 mHandler.removeMessages(MSG_DISPATCH_SYSTEM_UI_VISIBILITY); 3192 mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY)); 3193 } 3194 } 3195 handleDispatchSystemUiVisibilityChanged()3196 private void handleDispatchSystemUiVisibilityChanged() { 3197 if (mView == null) { 3198 return; 3199 } 3200 final SystemUiVisibilityInfo info = mCompatibleVisibilityInfo; 3201 if (info.localChanges != 0) { 3202 mView.updateLocalSystemUiVisibility(info.localValue, info.localChanges); 3203 info.localChanges = 0; 3204 } 3205 3206 final int visibility = info.globalVisibility & View.SYSTEM_UI_CLEARABLE_FLAGS; 3207 if (mDispatchedSystemUiVisibility != visibility) { 3208 mDispatchedSystemUiVisibility = visibility; 3209 mView.dispatchSystemUiVisibilityChanged(visibility); 3210 } 3211 } 3212 3213 @VisibleForTesting adjustLayoutParamsForCompatibility(WindowManager.LayoutParams inOutParams, @Appearance int appearanceControlled, boolean behaviorControlled)3214 public static void adjustLayoutParamsForCompatibility(WindowManager.LayoutParams inOutParams, 3215 @Appearance int appearanceControlled, boolean behaviorControlled) { 3216 final int sysUiVis = inOutParams.systemUiVisibility | inOutParams.subtreeSystemUiVisibility; 3217 final int flags = inOutParams.flags; 3218 final int type = inOutParams.type; 3219 final int adjust = inOutParams.softInputMode & SOFT_INPUT_MASK_ADJUST; 3220 3221 @Appearance int appearance = inOutParams.insetsFlags.appearance; 3222 if ((appearanceControlled & APPEARANCE_LOW_PROFILE_BARS) == 0) { 3223 appearance &= ~APPEARANCE_LOW_PROFILE_BARS; 3224 appearance |= (sysUiVis & SYSTEM_UI_FLAG_LOW_PROFILE) != 0 3225 ? APPEARANCE_LOW_PROFILE_BARS 3226 : 0; 3227 } 3228 if ((appearanceControlled & APPEARANCE_LIGHT_STATUS_BARS) == 0) { 3229 appearance &= ~APPEARANCE_LIGHT_STATUS_BARS; 3230 appearance |= (sysUiVis & SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0 3231 ? APPEARANCE_LIGHT_STATUS_BARS 3232 : 0; 3233 } 3234 if ((appearanceControlled & APPEARANCE_LIGHT_NAVIGATION_BARS) == 0) { 3235 appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS; 3236 appearance |= (sysUiVis & SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0 3237 ? APPEARANCE_LIGHT_NAVIGATION_BARS 3238 : 0; 3239 } 3240 inOutParams.insetsFlags.appearance = appearance; 3241 3242 if (!behaviorControlled) { 3243 if ((sysUiVis & SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0 3244 || (flags & FLAG_FULLSCREEN) != 0) { 3245 inOutParams.insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; 3246 } else { 3247 inOutParams.insetsFlags.behavior = BEHAVIOR_DEFAULT; 3248 } 3249 } 3250 3251 inOutParams.privateFlags &= ~PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME; 3252 3253 if ((inOutParams.privateFlags & PRIVATE_FLAG_FIT_INSETS_CONTROLLED) != 0) { 3254 return; 3255 } 3256 3257 int types = inOutParams.getFitInsetsTypes(); 3258 boolean ignoreVis = inOutParams.isFitInsetsIgnoringVisibility(); 3259 3260 if (((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0 3261 || (flags & FLAG_LAYOUT_IN_SCREEN) != 0) 3262 || (flags & FLAG_TRANSLUCENT_STATUS) != 0) { 3263 types &= ~Type.statusBars(); 3264 } 3265 if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0 3266 || (flags & FLAG_TRANSLUCENT_NAVIGATION) != 0) { 3267 types &= ~Type.systemBars(); 3268 } 3269 if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) { 3270 ignoreVis = true; 3271 } else if ((types & Type.systemBars()) == Type.systemBars()) { 3272 if (adjust == SOFT_INPUT_ADJUST_RESIZE) { 3273 types |= Type.ime(); 3274 } else { 3275 inOutParams.privateFlags |= PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME; 3276 } 3277 } 3278 inOutParams.setFitInsetsTypes(types); 3279 inOutParams.setFitInsetsIgnoringVisibility(ignoreVis); 3280 3281 // The fitting of insets are not really controlled by the clients, so we remove the flag. 3282 inOutParams.privateFlags &= ~PRIVATE_FLAG_FIT_INSETS_CONTROLLED; 3283 } 3284 3285 /** Updates the {@link InsetsType}s to hide or show based on layout params. */ 3286 @VisibleForTesting controlInsetsForCompatibility(WindowManager.LayoutParams params)3287 public void controlInsetsForCompatibility(WindowManager.LayoutParams params) { 3288 final int sysUiVis = params.systemUiVisibility | params.subtreeSystemUiVisibility; 3289 final int flags = params.flags; 3290 final boolean matchParent = params.width == MATCH_PARENT && params.height == MATCH_PARENT; 3291 final boolean nonAttachedAppWindow = params.type >= FIRST_APPLICATION_WINDOW 3292 && params.type <= LAST_APPLICATION_WINDOW; 3293 final boolean statusWasHiddenByFlags = (mTypesHiddenByFlags & Type.statusBars()) != 0; 3294 final boolean statusIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_FULLSCREEN) != 0 3295 || ((flags & FLAG_FULLSCREEN) != 0 && matchParent && nonAttachedAppWindow); 3296 final boolean navWasHiddenByFlags = (mTypesHiddenByFlags & Type.navigationBars()) != 0; 3297 final boolean navIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0; 3298 final boolean captionWasHiddenByFlags = (mTypesHiddenByFlags & Type.captionBar()) != 0; 3299 final boolean captionIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_FULLSCREEN) != 0 3300 || ((flags & FLAG_FULLSCREEN) != 0 && matchParent && nonAttachedAppWindow); 3301 3302 @InsetsType int typesToHide = 0; 3303 @InsetsType int typesToShow = 0; 3304 if (statusIsHiddenByFlags && !statusWasHiddenByFlags) { 3305 typesToHide |= Type.statusBars(); 3306 } else if (!statusIsHiddenByFlags && statusWasHiddenByFlags) { 3307 typesToShow |= Type.statusBars(); 3308 } 3309 if (navIsHiddenByFlags && !navWasHiddenByFlags) { 3310 typesToHide |= Type.navigationBars(); 3311 } else if (!navIsHiddenByFlags && navWasHiddenByFlags) { 3312 typesToShow |= Type.navigationBars(); 3313 } 3314 if (captionIsHiddenByFlags && !captionWasHiddenByFlags 3315 && ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION.isTrue()) { 3316 typesToHide |= Type.captionBar(); 3317 } else if (!captionIsHiddenByFlags && captionWasHiddenByFlags 3318 && ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION.isTrue()) { 3319 typesToShow |= Type.captionBar(); 3320 } 3321 if (typesToHide != 0) { 3322 getInsetsController().hide(typesToHide); 3323 } 3324 if (typesToShow != 0) { 3325 getInsetsController().show(typesToShow); 3326 } 3327 mTypesHiddenByFlags |= typesToHide; 3328 mTypesHiddenByFlags &= ~typesToShow; 3329 } 3330 measureHierarchy(final View host, final WindowManager.LayoutParams lp, final Resources res, final int desiredWindowWidth, final int desiredWindowHeight, boolean forRootSizeOnly)3331 private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp, 3332 final Resources res, final int desiredWindowWidth, final int desiredWindowHeight, 3333 boolean forRootSizeOnly) { 3334 int childWidthMeasureSpec; 3335 int childHeightMeasureSpec; 3336 boolean windowSizeMayChange = false; 3337 3338 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(mTag, 3339 "Measuring " + host + " in display " + desiredWindowWidth 3340 + "x" + desiredWindowHeight + "..."); 3341 3342 boolean goodMeasure = false; 3343 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) { 3344 // On large screens, we don't want to allow dialogs to just 3345 // stretch to fill the entire width of the screen to display 3346 // one line of text. First try doing the layout at a smaller 3347 // size to see if it will fit. 3348 final DisplayMetrics packageMetrics = res.getDisplayMetrics(); 3349 res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true); 3350 int baseSize = 0; 3351 if (mTmpValue.type == TypedValue.TYPE_DIMENSION) { 3352 baseSize = (int)mTmpValue.getDimension(packageMetrics); 3353 } 3354 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": baseSize=" + baseSize 3355 + ", desiredWindowWidth=" + desiredWindowWidth); 3356 if (baseSize != 0 && desiredWindowWidth > baseSize) { 3357 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width, lp.privateFlags); 3358 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height, 3359 lp.privateFlags); 3360 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 3361 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured (" 3362 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() 3363 + ") from width spec: " + MeasureSpec.toString(childWidthMeasureSpec) 3364 + " and height spec: " + MeasureSpec.toString(childHeightMeasureSpec)); 3365 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) { 3366 goodMeasure = true; 3367 } else { 3368 // Didn't fit in that size... try expanding a bit. 3369 baseSize = (baseSize+desiredWindowWidth)/2; 3370 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": next baseSize=" 3371 + baseSize); 3372 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width, lp.privateFlags); 3373 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 3374 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured (" 3375 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")"); 3376 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) { 3377 if (DEBUG_DIALOG) Log.v(mTag, "Good!"); 3378 goodMeasure = true; 3379 } 3380 } 3381 } 3382 } 3383 3384 if (!goodMeasure) { 3385 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width, 3386 lp.privateFlags); 3387 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height, 3388 lp.privateFlags); 3389 if (!forRootSizeOnly || !setMeasuredRootSizeFromSpec( 3390 childWidthMeasureSpec, childHeightMeasureSpec)) { 3391 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 3392 } else { 3393 // We already know how big the window should be before measuring the views. 3394 // We can measure the views before laying out them. This is to avoid unnecessary 3395 // measure. 3396 mViewMeasureDeferred = true; 3397 } 3398 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) { 3399 windowSizeMayChange = true; 3400 } 3401 } 3402 3403 if (DBG) { 3404 System.out.println("======================================"); 3405 System.out.println("performTraversals -- after measure"); 3406 host.debug(); 3407 } 3408 3409 return windowSizeMayChange; 3410 } 3411 3412 /** 3413 * Sets the measured root size for requesting the window frame. 3414 * 3415 * @param widthMeasureSpec contains the size and the mode of the width. 3416 * @param heightMeasureSpec contains the size and the mode of the height. 3417 * @return {@code true} if we actually set the measured size; {@code false} otherwise. 3418 */ setMeasuredRootSizeFromSpec(int widthMeasureSpec, int heightMeasureSpec)3419 private boolean setMeasuredRootSizeFromSpec(int widthMeasureSpec, int heightMeasureSpec) { 3420 final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 3421 final int heightMode = MeasureSpec.getMode(heightMeasureSpec); 3422 if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) { 3423 // We don't know the exact size. We need to measure the hierarchy to know that. 3424 return false; 3425 } 3426 mMeasuredWidth = MeasureSpec.getSize(widthMeasureSpec); 3427 mMeasuredHeight = MeasureSpec.getSize(heightMeasureSpec); 3428 return true; 3429 } 3430 3431 /** 3432 * Modifies the input matrix such that it maps view-local coordinates to 3433 * on-screen coordinates. 3434 * 3435 * @param m input matrix to modify 3436 */ transformMatrixToGlobal(Matrix m)3437 void transformMatrixToGlobal(Matrix m) { 3438 m.preTranslate(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 3439 } 3440 3441 /** 3442 * Modifies the input matrix such that it maps on-screen coordinates to 3443 * view-local coordinates. 3444 * 3445 * @param m input matrix to modify 3446 */ transformMatrixToLocal(Matrix m)3447 void transformMatrixToLocal(Matrix m) { 3448 m.postTranslate(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop); 3449 } 3450 getWindowInsets(boolean forceConstruct)3451 /* package */ WindowInsets getWindowInsets(boolean forceConstruct) { 3452 if (mLastWindowInsets == null || forceConstruct) { 3453 final Configuration config = getConfiguration(); 3454 mLastWindowInsets = mInsetsController.calculateInsets( 3455 config.isScreenRound(), mWindowAttributes.type, 3456 config.windowConfiguration.getActivityType(), mWindowAttributes.softInputMode, 3457 mWindowAttributes.flags, (mWindowAttributes.systemUiVisibility 3458 | mWindowAttributes.subtreeSystemUiVisibility)); 3459 3460 mAttachInfo.mContentInsets.set(mLastWindowInsets.getSystemWindowInsets().toRect()); 3461 mAttachInfo.mStableInsets.set(mLastWindowInsets.getStableInsets().toRect()); 3462 mAttachInfo.mVisibleInsets.set(mInsetsController.calculateVisibleInsets( 3463 mWindowAttributes.type, config.windowConfiguration.getActivityType(), 3464 mWindowAttributes.softInputMode, mWindowAttributes.flags).toRect()); 3465 } 3466 return mLastWindowInsets; 3467 } 3468 dispatchApplyInsets(View host)3469 public void dispatchApplyInsets(View host) { 3470 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchApplyInsets"); 3471 mApplyInsetsRequested = false; 3472 WindowInsets insets = getWindowInsets(true /* forceConstruct */); 3473 if (!shouldDispatchCutout()) { 3474 // Window is either not laid out in cutout or the status bar inset takes care of 3475 // clearing the cutout, so we don't need to dispatch the cutout to the hierarchy. 3476 insets = insets.consumeDisplayCutout(); 3477 } 3478 host.dispatchApplyWindowInsets(insets); 3479 mAttachInfo.delayNotifyContentCaptureInsetsEvent(insets.getInsets(Type.all())); 3480 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 3481 } 3482 shouldDispatchCutout()3483 private boolean shouldDispatchCutout() { 3484 return mWindowAttributes.layoutInDisplayCutoutMode 3485 == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS 3486 || mWindowAttributes.layoutInDisplayCutoutMode 3487 == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; 3488 } 3489 getInsetsController()3490 public InsetsController getInsetsController() { 3491 return mInsetsController; 3492 } 3493 shouldUseDisplaySize(final WindowManager.LayoutParams lp)3494 private static boolean shouldUseDisplaySize(final WindowManager.LayoutParams lp) { 3495 return lp.type == TYPE_STATUS_BAR_ADDITIONAL 3496 || lp.type == TYPE_INPUT_METHOD 3497 || lp.type == TYPE_VOLUME_OVERLAY; 3498 } 3499 3500 /** 3501 * @return {@code true} if we should reduce unnecessary measure for the window. 3502 * TODO(b/260382739): Apply this to all windows. 3503 */ shouldOptimizeMeasure(final WindowManager.LayoutParams lp)3504 private static boolean shouldOptimizeMeasure(final WindowManager.LayoutParams lp) { 3505 if (com.android.window.flags.Flags.reduceUnnecessaryMeasure()) { 3506 return true; 3507 } 3508 return (lp.privateFlags & PRIVATE_FLAG_OPTIMIZE_MEASURE) != 0; 3509 } 3510 getWindowBoundsInsetSystemBars()3511 private Rect getWindowBoundsInsetSystemBars() { 3512 final Rect bounds = new Rect( 3513 mContext.getResources().getConfiguration().windowConfiguration.getBounds()); 3514 bounds.inset(mInsetsController.getState().calculateInsets( 3515 bounds, Type.systemBars(), false /* ignoreVisibility */)); 3516 return bounds; 3517 } 3518 dipToPx(int dip)3519 int dipToPx(int dip) { 3520 final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics(); 3521 return (int) (displayMetrics.density * dip + 0.5f); 3522 } 3523 performTraversals()3524 private void performTraversals() { 3525 mLastPerformTraversalsSkipDrawReason = null; 3526 3527 // cache mView since it is used so much below... 3528 final View host = mView; 3529 if (DBG) { 3530 System.out.println("======================================"); 3531 System.out.println("performTraversals"); 3532 host.debug(); 3533 } 3534 3535 if (host == null || !mAdded) { 3536 mLastPerformTraversalsSkipDrawReason = host == null ? "no_host" : "not_added"; 3537 return; 3538 } 3539 3540 if (mNumPausedForSync > 0) { 3541 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 3542 Trace.instant(Trace.TRACE_TAG_VIEW, 3543 TextUtils.formatSimple("performTraversals#mNumPausedForSync=%d", 3544 mNumPausedForSync)); 3545 } 3546 if (DEBUG_BLAST) { 3547 Log.d(mTag, "Skipping traversal due to sync " + mNumPausedForSync); 3548 } 3549 mLastPerformTraversalsSkipDrawReason = "paused_for_sync"; 3550 return; 3551 } 3552 3553 mIsInTraversal = true; 3554 mWillDrawSoon = true; 3555 boolean cancelDraw = false; 3556 String cancelReason = null; 3557 boolean isSyncRequest = false; 3558 3559 boolean windowSizeMayChange = false; 3560 WindowManager.LayoutParams lp = mWindowAttributes; 3561 3562 int desiredWindowWidth; 3563 int desiredWindowHeight; 3564 3565 final int viewVisibility = getHostVisibility(); 3566 final String viewVisibilityReason = getHostVisibilityReason(); 3567 final boolean viewVisibilityChanged = !mFirst 3568 && (mViewVisibility != viewVisibility || mNewSurfaceNeeded 3569 // Also check for possible double visibility update, which will make current 3570 // viewVisibility value equal to mViewVisibility and we may miss it. 3571 || mAppVisibilityChanged); 3572 mAppVisibilityChanged = false; 3573 final boolean viewUserVisibilityChanged = !mFirst && 3574 ((mViewVisibility == View.VISIBLE) != (viewVisibility == View.VISIBLE)); 3575 final boolean shouldOptimizeMeasure = shouldOptimizeMeasure(lp); 3576 3577 WindowManager.LayoutParams params = null; 3578 Rect frame = mWinFrame; 3579 if (mFirst) { 3580 mFullRedrawNeeded = true; 3581 mLayoutRequested = true; 3582 3583 final Configuration config = getConfiguration(); 3584 if (shouldUseDisplaySize(lp)) { 3585 // NOTE -- system code, won't try to do compat mode. 3586 Point size = new Point(); 3587 mDisplay.getRealSize(size); 3588 desiredWindowWidth = size.x; 3589 desiredWindowHeight = size.y; 3590 } else if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT 3591 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) { 3592 // For wrap content, we have to remeasure later on anyways. Use size consistent with 3593 // below so we get best use of the measure cache. 3594 final Rect bounds = getWindowBoundsInsetSystemBars(); 3595 desiredWindowWidth = bounds.width(); 3596 desiredWindowHeight = bounds.height(); 3597 } else { 3598 // After addToDisplay, the frame contains the frameHint from window manager, which 3599 // for most windows is going to be the same size as the result of relayoutWindow. 3600 // Using this here allows us to avoid remeasuring after relayoutWindow 3601 desiredWindowWidth = frame.width(); 3602 desiredWindowHeight = frame.height(); 3603 } 3604 3605 // We used to use the following condition to choose 32 bits drawing caches: 3606 // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888 3607 // However, windows are now always 32 bits by default, so choose 32 bits 3608 mAttachInfo.mUse32BitDrawingCache = true; 3609 mAttachInfo.mWindowVisibility = viewVisibility; 3610 mAttachInfo.mRecomputeGlobalAttributes = false; 3611 mLastConfigurationFromResources.setTo(config); 3612 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility; 3613 // Set the layout direction if it has not been set before (inherit is the default) 3614 if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) { 3615 host.setLayoutDirection(config.getLayoutDirection()); 3616 } 3617 host.dispatchAttachedToWindow(mAttachInfo, 0); 3618 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true); 3619 dispatchApplyInsets(host); 3620 if (!mOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled() 3621 // Don't register compat OnBackInvokedCallback for windowless window. 3622 // The onBackInvoked event by default should forward to host app, so the 3623 // host app can decide the behavior. 3624 && mWindowlessBackKeyCallback == null) { 3625 // For apps requesting legacy back behavior, we add a compat callback that 3626 // dispatches {@link KeyEvent#KEYCODE_BACK} to their root views. 3627 // This way from system point of view, these apps are providing custom 3628 // {@link OnBackInvokedCallback}s, and will not play system back animations 3629 // for them. 3630 registerCompatOnBackInvokedCallback(); 3631 } 3632 } else { 3633 desiredWindowWidth = frame.width(); 3634 desiredWindowHeight = frame.height(); 3635 if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) { 3636 if (DEBUG_ORIENTATION) Log.v(mTag, "View " + host + " resized to: " + frame); 3637 mFullRedrawNeeded = true; 3638 mLayoutRequested = true; 3639 windowSizeMayChange = true; 3640 } 3641 } 3642 3643 if (viewVisibilityChanged) { 3644 mAttachInfo.mWindowVisibility = viewVisibility; 3645 host.dispatchWindowVisibilityChanged(viewVisibility); 3646 mAttachInfo.mTreeObserver.dispatchOnWindowVisibilityChange(viewVisibility); 3647 if (viewUserVisibilityChanged) { 3648 host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE); 3649 } 3650 if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) { 3651 endDragResizing(); 3652 destroyHardwareResources(); 3653 } 3654 3655 if (shouldEnableDvrr() && viewVisibility == View.VISIBLE) { 3656 // Boost frame rate when the viewVisibility becomes true. 3657 // This is mainly for lanuchers that lanuch new windows. 3658 boostFrameRate(FRAME_RATE_BOOST_TIME); 3659 } 3660 } 3661 3662 // Non-visible windows can't hold accessibility focus. 3663 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 3664 host.clearAccessibilityFocus(); 3665 } 3666 3667 // Execute enqueued actions on every traversal in case a detached view enqueued an action 3668 getRunQueue().executeActions(mAttachInfo.mHandler); 3669 3670 if (mFirst) { 3671 // make sure touch mode code executes by setting cached value 3672 // to opposite of the added touch mode. 3673 mAttachInfo.mInTouchMode = !mAddedTouchMode; 3674 ensureTouchModeLocally(mAddedTouchMode); 3675 } 3676 3677 boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw); 3678 if (layoutRequested) { 3679 if (!mFirst) { 3680 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT 3681 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) { 3682 windowSizeMayChange = true; 3683 3684 if (shouldUseDisplaySize(lp)) { 3685 // NOTE -- system code, won't try to do compat mode. 3686 Point size = new Point(); 3687 mDisplay.getRealSize(size); 3688 desiredWindowWidth = size.x; 3689 desiredWindowHeight = size.y; 3690 } else { 3691 final Rect bounds = getWindowBoundsInsetSystemBars(); 3692 desiredWindowWidth = bounds.width(); 3693 desiredWindowHeight = bounds.height(); 3694 } 3695 } 3696 } 3697 3698 // Ask host how big it wants to be 3699 windowSizeMayChange |= measureHierarchy(host, lp, mView.getContext().getResources(), 3700 desiredWindowWidth, desiredWindowHeight, shouldOptimizeMeasure); 3701 } 3702 3703 if (collectViewAttributes()) { 3704 params = lp; 3705 } 3706 if (mAttachInfo.mForceReportNewAttributes) { 3707 mAttachInfo.mForceReportNewAttributes = false; 3708 params = lp; 3709 } 3710 3711 if (mFirst || mAttachInfo.mViewVisibilityChanged) { 3712 mAttachInfo.mViewVisibilityChanged = false; 3713 int resizeMode = mSoftInputMode & SOFT_INPUT_MASK_ADJUST; 3714 // If we are in auto resize mode, then we need to determine 3715 // what mode to use now. 3716 if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) { 3717 final int N = mAttachInfo.mScrollContainers.size(); 3718 for (int i=0; i<N; i++) { 3719 if (mAttachInfo.mScrollContainers.get(i).isShown()) { 3720 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; 3721 } 3722 } 3723 if (resizeMode == 0) { 3724 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN; 3725 } 3726 if ((lp.softInputMode & SOFT_INPUT_MASK_ADJUST) != resizeMode) { 3727 lp.softInputMode = (lp.softInputMode & ~SOFT_INPUT_MASK_ADJUST) | resizeMode; 3728 params = lp; 3729 } 3730 } 3731 } 3732 3733 if (mApplyInsetsRequested) { 3734 dispatchApplyInsets(host); 3735 if (mLayoutRequested) { 3736 // Short-circuit catching a new layout request here, so 3737 // we don't need to go through two layout passes when things 3738 // change due to fitting system windows, which can happen a lot. 3739 windowSizeMayChange |= measureHierarchy(host, lp, 3740 mView.getContext().getResources(), desiredWindowWidth, desiredWindowHeight, 3741 shouldOptimizeMeasure); 3742 } 3743 } 3744 3745 if (layoutRequested) { 3746 // Clear this now, so that if anything requests a layout in the 3747 // rest of this function we will catch it and re-run a full 3748 // layout pass. 3749 mLayoutRequested = false; 3750 } 3751 3752 boolean windowShouldResize = layoutRequested && windowSizeMayChange 3753 && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) 3754 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT && 3755 frame.width() < desiredWindowWidth && frame.width() != mWidth) 3756 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT && 3757 frame.height() < desiredWindowHeight && frame.height() != mHeight)); 3758 windowShouldResize |= mDragResizing && mPendingDragResizing; 3759 3760 // Determine whether to compute insets. 3761 // If there are no inset listeners remaining then we may still need to compute 3762 // insets in case the old insets were non-empty and must be reset. 3763 final boolean computesInternalInsets = 3764 mAttachInfo.mTreeObserver.hasComputeInternalInsetsListeners() 3765 || mAttachInfo.mHasNonEmptyGivenInternalInsets; 3766 3767 boolean insetsPending = false; 3768 int relayoutResult = 0; 3769 boolean updatedConfiguration = false; 3770 3771 final int surfaceGenerationId = mSurface.getGenerationId(); 3772 3773 final boolean isViewVisible = viewVisibility == View.VISIBLE; 3774 boolean surfaceSizeChanged = false; 3775 boolean surfaceCreated = false; 3776 boolean surfaceDestroyed = false; 3777 // True if surface generation id changes or relayout result is RELAYOUT_RES_SURFACE_CHANGED. 3778 boolean surfaceReplaced = false; 3779 3780 final boolean windowAttributesChanged = mWindowAttributesChanged; 3781 if (windowAttributesChanged) { 3782 mWindowAttributesChanged = false; 3783 params = lp; 3784 } 3785 3786 if (params != null) { 3787 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0 3788 && !PixelFormat.formatHasAlpha(params.format)) { 3789 params.format = PixelFormat.TRANSLUCENT; 3790 } 3791 adjustLayoutParamsForCompatibility(params, 3792 mInsetsController.getAppearanceControlled(), 3793 mInsetsController.isBehaviorControlled()); 3794 controlInsetsForCompatibility(params); 3795 if (mDispatchedSystemBarAppearance != params.insetsFlags.appearance) { 3796 mDispatchedSystemBarAppearance = params.insetsFlags.appearance; 3797 mView.onSystemBarAppearanceChanged(mDispatchedSystemBarAppearance); 3798 } 3799 } 3800 3801 if (mFirst || windowShouldResize || viewVisibilityChanged || params != null 3802 || mForceNextWindowRelayout) { 3803 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 3804 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 3805 TextUtils.formatSimple("%s-relayoutWindow#" 3806 + "first=%b/resize=%b/vis=%b/params=%b/force=%b", mTag, 3807 mFirst, windowShouldResize, viewVisibilityChanged, params != null, 3808 mForceNextWindowRelayout)); 3809 } 3810 3811 mForceNextWindowRelayout = false; 3812 3813 // If this window is giving internal insets to the window manager, then we want to first 3814 // make the provided insets unchanged during layout. This avoids it briefly causing 3815 // other windows to resize/move based on the raw frame of the window, waiting until we 3816 // can finish laying out this window and get back to the window manager with the 3817 // ultimately computed insets. 3818 insetsPending = computesInternalInsets 3819 // If this window provides insets via params, its insets source frame can be 3820 // updated directly without waiting for WindowSession#setInsets. 3821 && mWindowAttributes.providedInsets == null; 3822 3823 if (mSurfaceHolder != null) { 3824 mSurfaceHolder.mSurfaceLock.lock(); 3825 mDrawingAllowed = true; 3826 } 3827 3828 boolean hwInitialized = false; 3829 boolean dispatchApplyInsets = false; 3830 boolean hadSurface = mSurface.isValid(); 3831 3832 try { 3833 if (DEBUG_LAYOUT) { 3834 Log.i(mTag, "host=w:" + host.getMeasuredWidth() + ", h:" + 3835 host.getMeasuredHeight() + ", params=" + params); 3836 } 3837 3838 if (mFirst || viewVisibilityChanged) { 3839 mViewFrameInfo.flags |= FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED; 3840 } 3841 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending); 3842 cancelDraw = (relayoutResult & RELAYOUT_RES_CANCEL_AND_REDRAW) 3843 == RELAYOUT_RES_CANCEL_AND_REDRAW; 3844 cancelReason = "relayout"; 3845 final boolean dragResizing = mPendingDragResizing; 3846 if (mSyncSeqId > mLastSyncSeqId) { 3847 mLastSyncSeqId = mSyncSeqId; 3848 if (DEBUG_BLAST) { 3849 Log.d(mTag, "Relayout called with blastSync"); 3850 } 3851 reportNextDraw("relayout"); 3852 mSyncBuffer = true; 3853 isSyncRequest = true; 3854 if (!cancelDraw) { 3855 mDrewOnceForSync = false; 3856 } 3857 } 3858 3859 final boolean surfaceControlChanged = 3860 (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED) 3861 == RELAYOUT_RES_SURFACE_CHANGED; 3862 3863 if (mSurfaceControl.isValid()) { 3864 updateOpacity(mWindowAttributes, dragResizing, 3865 surfaceControlChanged /*forceUpdate */); 3866 // No need to updateDisplayDecoration if it's a new SurfaceControl and 3867 // mDisplayDecorationCached is false, since that's the default for a new 3868 // SurfaceControl. 3869 if (surfaceControlChanged && mDisplayDecorationCached) { 3870 updateDisplayDecoration(); 3871 } 3872 if (surfaceControlChanged 3873 && mWindowAttributes.type 3874 == WindowManager.LayoutParams.TYPE_STATUS_BAR) { 3875 mTransaction.setDefaultFrameRateCompatibility(mSurfaceControl, 3876 Surface.FRAME_RATE_COMPATIBILITY_NO_VOTE).apply(); 3877 } 3878 3879 if (setScPropertiesInClient()) { 3880 if (surfaceControlChanged || windowAttributesChanged) { 3881 boolean colorSpaceAgnostic = (lp.privateFlags 3882 & WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC) 3883 != 0; 3884 mTransaction.setColorSpaceAgnostic(mSurfaceControl, colorSpaceAgnostic) 3885 .apply(); 3886 } 3887 } 3888 } 3889 3890 if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString() 3891 + " surface=" + mSurface); 3892 3893 // If the pending {@link MergedConfiguration} handed back from 3894 // {@link #relayoutWindow} does not match the one last reported, 3895 // WindowManagerService has reported back a frame from a configuration not yet 3896 // handled by the client. In this case, we need to accept the configuration so we 3897 // do not lay out and draw with the wrong configuration. 3898 boolean shouldPerformConfigurationUpdate = 3899 !mPendingMergedConfiguration.equals(mLastReportedMergedConfiguration) 3900 || !Objects.equals(mPendingActivityWindowInfo, 3901 mLastReportedActivityWindowInfo); 3902 if (mRelayoutRequested && shouldPerformConfigurationUpdate) { 3903 if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: " 3904 + mPendingMergedConfiguration.getMergedConfiguration()); 3905 performConfigurationChange(new MergedConfiguration(mPendingMergedConfiguration), 3906 !mFirst, INVALID_DISPLAY /* same display */, 3907 mPendingActivityWindowInfo != null 3908 ? new ActivityWindowInfo(mPendingActivityWindowInfo) 3909 : null); 3910 updatedConfiguration = true; 3911 } 3912 final boolean updateSurfaceNeeded = mUpdateSurfaceNeeded; 3913 mUpdateSurfaceNeeded = false; 3914 3915 surfaceSizeChanged = false; 3916 if (!mLastSurfaceSize.equals(mSurfaceSize)) { 3917 surfaceSizeChanged = true; 3918 mLastSurfaceSize.set(mSurfaceSize.x, mSurfaceSize.y); 3919 } 3920 final boolean alwaysConsumeSystemBarsChanged = 3921 mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars; 3922 updateColorModeIfNeeded(lp.getColorMode(), lp.getDesiredHdrHeadroom()); 3923 surfaceCreated = !hadSurface && mSurface.isValid(); 3924 surfaceDestroyed = hadSurface && !mSurface.isValid(); 3925 3926 // When using Blast, the surface generation id may not change when there's a new 3927 // SurfaceControl. In that case, we also check relayout flag 3928 // RELAYOUT_RES_SURFACE_CHANGED since it should indicate that WMS created a new 3929 // SurfaceControl. 3930 surfaceReplaced = (surfaceGenerationId != mSurface.getGenerationId() 3931 || surfaceControlChanged) && mSurface.isValid(); 3932 if (surfaceReplaced) { 3933 mSurfaceReplaced = true; 3934 mSurfaceSequenceId++; 3935 mHandler.removeMessages(MSG_SURFACE_REPLACED_TIMEOUT); 3936 mHandler.sendEmptyMessageDelayed(MSG_SURFACE_REPLACED_TIMEOUT, 3937 FRAME_RATE_SURFACE_REPLACED_TIME); 3938 } 3939 if (alwaysConsumeSystemBarsChanged) { 3940 mAttachInfo.mAlwaysConsumeSystemBars = mPendingAlwaysConsumeSystemBars; 3941 dispatchApplyInsets = true; 3942 } 3943 if (dispatchApplyInsets || mLastSystemUiVisibility != 3944 mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested) { 3945 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility; 3946 dispatchApplyInsets(host); 3947 // We applied insets so force contentInsetsChanged to ensure the 3948 // hierarchy is measured below. 3949 dispatchApplyInsets = true; 3950 } 3951 3952 if (surfaceCreated) { 3953 // If we are creating a new surface, then we need to 3954 // completely redraw it. 3955 mFullRedrawNeeded = true; 3956 mPreviousTransparentRegion.setEmpty(); 3957 3958 // Only initialize up-front if transparent regions are not 3959 // requested, otherwise defer to see if the entire window 3960 // will be transparent 3961 if (mAttachInfo.mThreadedRenderer != null) { 3962 try { 3963 hwInitialized = mAttachInfo.mThreadedRenderer.initialize(mSurface); 3964 if (hwInitialized && (host.mPrivateFlags 3965 & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) { 3966 // Don't pre-allocate if transparent regions 3967 // are requested as they may not be needed 3968 mAttachInfo.mThreadedRenderer.allocateBuffers(); 3969 } 3970 } catch (OutOfResourcesException e) { 3971 handleOutOfResourcesException(e); 3972 mLastPerformTraversalsSkipDrawReason = "oom_initialize_renderer"; 3973 return; 3974 } 3975 } 3976 } else if (surfaceDestroyed) { 3977 // If the surface has been removed, then reset the scroll 3978 // positions. 3979 if (mLastScrolledFocus != null) { 3980 mLastScrolledFocus.clear(); 3981 } 3982 mScrollY = mCurScrollY = 0; 3983 if (mView instanceof RootViewSurfaceTaker) { 3984 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY); 3985 } 3986 if (mScroller != null) { 3987 mScroller.abortAnimation(); 3988 } 3989 // Our surface is gone 3990 if (isHardwareEnabled()) { 3991 mAttachInfo.mThreadedRenderer.destroy(); 3992 } 3993 } else if ((surfaceReplaced || surfaceSizeChanged || updateSurfaceNeeded) 3994 && mSurfaceHolder == null 3995 && mAttachInfo.mThreadedRenderer != null 3996 && mSurface.isValid()) { 3997 mFullRedrawNeeded = true; 3998 try { 3999 // Need to do updateSurface (which leads to CanvasContext::setSurface and 4000 // re-create the EGLSurface) if either the Surface changed (as indicated by 4001 // generation id), or WindowManager changed the surface size. The latter is 4002 // because on some chips, changing the consumer side's BufferQueue size may 4003 // not take effect immediately unless we create a new EGLSurface. 4004 // Note that frame size change doesn't always imply surface size change (eg. 4005 // drag resizing uses fullscreen surface), need to check surfaceSizeChanged 4006 // flag from WindowManager. 4007 mAttachInfo.mThreadedRenderer.updateSurface(mSurface); 4008 } catch (OutOfResourcesException e) { 4009 handleOutOfResourcesException(e); 4010 mLastPerformTraversalsSkipDrawReason = "oom_update_surface"; 4011 return; 4012 } 4013 } 4014 4015 if (mDragResizing != dragResizing) { 4016 if (dragResizing) { 4017 final boolean backdropSizeMatchesFrame = 4018 mWinFrame.width() == mPendingBackDropFrame.width() 4019 && mWinFrame.height() == mPendingBackDropFrame.height(); 4020 // TODO: Need cutout? 4021 startDragResizing(mPendingBackDropFrame, !backdropSizeMatchesFrame, 4022 mAttachInfo.mContentInsets, mAttachInfo.mStableInsets); 4023 } else { 4024 // We shouldn't come here, but if we come we should end the resize. 4025 endDragResizing(); 4026 } 4027 } 4028 if (!mUseMTRenderer) { 4029 if (dragResizing) { 4030 mCanvasOffsetX = mWinFrame.left; 4031 mCanvasOffsetY = mWinFrame.top; 4032 } else { 4033 mCanvasOffsetX = mCanvasOffsetY = 0; 4034 } 4035 } 4036 } catch (RemoteException e) { 4037 } finally { 4038 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 4039 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 4040 } 4041 } 4042 4043 if (DEBUG_ORIENTATION) Log.v( 4044 TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface); 4045 4046 mAttachInfo.mWindowLeft = frame.left; 4047 mAttachInfo.mWindowTop = frame.top; 4048 4049 // !!FIXME!! This next section handles the case where we did not get the 4050 // window size we asked for. We should avoid this by getting a maximum size from 4051 // the window session beforehand. 4052 if (mWidth != frame.width() || mHeight != frame.height()) { 4053 mWidth = frame.width(); 4054 mHeight = frame.height(); 4055 } 4056 4057 if (mSurfaceHolder != null) { 4058 // The app owns the surface; tell it about what is going on. 4059 if (mSurface.isValid()) { 4060 // XXX .copyFrom() doesn't work! 4061 //mSurfaceHolder.mSurface.copyFrom(mSurface); 4062 mSurfaceHolder.mSurface = mSurface; 4063 } 4064 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight); 4065 mSurfaceHolder.mSurfaceLock.unlock(); 4066 if (surfaceCreated) { 4067 mSurfaceHolder.ungetCallbacks(); 4068 4069 mIsCreating = true; 4070 SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks(); 4071 if (callbacks != null) { 4072 for (SurfaceHolder.Callback c : callbacks) { 4073 c.surfaceCreated(mSurfaceHolder); 4074 } 4075 } 4076 } 4077 4078 if ((surfaceCreated || surfaceReplaced || surfaceSizeChanged 4079 || windowAttributesChanged) && mSurface.isValid()) { 4080 SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks(); 4081 if (callbacks != null) { 4082 for (SurfaceHolder.Callback c : callbacks) { 4083 c.surfaceChanged(mSurfaceHolder, lp.format, 4084 mWidth, mHeight); 4085 } 4086 } 4087 mIsCreating = false; 4088 } 4089 4090 if (surfaceDestroyed) { 4091 notifyHolderSurfaceDestroyed(); 4092 mSurfaceHolder.mSurfaceLock.lock(); 4093 try { 4094 mSurfaceHolder.mSurface = new Surface(); 4095 } finally { 4096 mSurfaceHolder.mSurfaceLock.unlock(); 4097 } 4098 } 4099 } 4100 4101 final ThreadedRenderer threadedRenderer = mAttachInfo.mThreadedRenderer; 4102 if (threadedRenderer != null && threadedRenderer.isEnabled()) { 4103 if (hwInitialized 4104 || mWidth != threadedRenderer.getWidth() 4105 || mHeight != threadedRenderer.getHeight() 4106 || mNeedsRendererSetup) { 4107 threadedRenderer.setup(mWidth, mHeight, mAttachInfo, 4108 mWindowAttributes.surfaceInsets); 4109 mNeedsRendererSetup = false; 4110 } 4111 } 4112 4113 // TODO: In the CL "ViewRootImpl: Fix issue with early draw report in 4114 // seamless rotation". We moved processing of RELAYOUT_RES_BLAST_SYNC 4115 // earlier in the function, potentially triggering a call to 4116 // reportNextDraw(). That same CL changed this and the next reference 4117 // to wasReportNextDraw, such that this logic would remain undisturbed 4118 // (it continues to operate as if the code was never moved). This was 4119 // done to achieve a more hermetic fix for S, but it's entirely 4120 // possible that checking the most recent value is actually more 4121 // correct here. 4122 if (!mStopped || mReportNextDraw) { 4123 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight() 4124 || dispatchApplyInsets || updatedConfiguration) { 4125 int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width, 4126 lp.privateFlags); 4127 int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height, 4128 lp.privateFlags); 4129 4130 if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed! mWidth=" 4131 + mWidth + " measuredWidth=" + host.getMeasuredWidth() 4132 + " mHeight=" + mHeight 4133 + " measuredHeight=" + host.getMeasuredHeight() 4134 + " dispatchApplyInsets=" + dispatchApplyInsets); 4135 4136 // Ask host how big it wants to be 4137 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 4138 4139 // Implementation of weights from WindowManager.LayoutParams 4140 // We just grow the dimensions as needed and re-measure if 4141 // needs be 4142 int width = host.getMeasuredWidth(); 4143 int height = host.getMeasuredHeight(); 4144 boolean measureAgain = false; 4145 4146 if (lp.horizontalWeight > 0.0f) { 4147 width += (int) ((mWidth - width) * lp.horizontalWeight); 4148 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width, 4149 MeasureSpec.EXACTLY); 4150 measureAgain = true; 4151 } 4152 if (lp.verticalWeight > 0.0f) { 4153 height += (int) ((mHeight - height) * lp.verticalWeight); 4154 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, 4155 MeasureSpec.EXACTLY); 4156 measureAgain = true; 4157 } 4158 4159 if (measureAgain) { 4160 if (DEBUG_LAYOUT) Log.v(mTag, 4161 "And hey let's measure once more: width=" + width 4162 + " height=" + height); 4163 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 4164 } 4165 4166 layoutRequested = true; 4167 } 4168 } 4169 } else { 4170 // Not the first pass and no window/insets/visibility change but the window 4171 // may have moved and we need check that and if so to update the left and right 4172 // in the attach info. We translate only the window frame since on window move 4173 // the window manager tells us only for the new frame but the insets are the 4174 // same and we do not want to translate them more than once. 4175 maybeHandleWindowMove(frame); 4176 } 4177 4178 if (mViewMeasureDeferred) { 4179 // It's time to measure the views since we are going to layout them. 4180 performMeasure( 4181 MeasureSpec.makeMeasureSpec(frame.width(), MeasureSpec.EXACTLY), 4182 MeasureSpec.makeMeasureSpec(frame.height(), MeasureSpec.EXACTLY)); 4183 } 4184 4185 if (!mRelayoutRequested && mCheckIfCanDraw) { 4186 // We had a sync previously, but we didn't call IWindowSession#relayout in this 4187 // traversal. So we don't know if the sync is complete that we can continue to draw. 4188 // Here invokes cancelDraw to obtain the information. 4189 try { 4190 cancelDraw = mWindowSession.cancelDraw(mWindow); 4191 cancelReason = "wm_sync"; 4192 if (DEBUG_BLAST) { 4193 Log.d(mTag, "cancelDraw returned " + cancelDraw); 4194 } 4195 } catch (RemoteException e) { 4196 } 4197 } 4198 4199 if (surfaceSizeChanged || surfaceReplaced || surfaceCreated || 4200 windowAttributesChanged || mChildBoundingInsetsChanged) { 4201 // If the surface has been replaced, there's a chance the bounds layer is not parented 4202 // to the new layer. When updating bounds layer, also reparent to the main VRI 4203 // SurfaceControl to ensure it's correctly placed in the hierarchy. 4204 // 4205 // This needs to be done on the client side since WMS won't reparent the children to the 4206 // new surface if it thinks the app is closing. WMS gets the signal that the app is 4207 // stopping, but on the client side it doesn't get stopped since it's restarted quick 4208 // enough. WMS doesn't want to keep around old children since they will leak when the 4209 // client creates new children. 4210 prepareSurfaces(); 4211 mChildBoundingInsetsChanged = false; 4212 } 4213 4214 final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw); 4215 boolean triggerGlobalLayoutListener = didLayout 4216 || mAttachInfo.mRecomputeGlobalAttributes; 4217 if (didLayout) { 4218 performLayout(lp, mWidth, mHeight); 4219 4220 // By this point all views have been sized and positioned 4221 // We can compute the transparent area 4222 4223 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 4224 // start out transparent 4225 // TODO: AVOID THAT CALL BY CACHING THE RESULT? 4226 host.getLocationInWindow(mTmpLocation); 4227 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1], 4228 mTmpLocation[0] + host.mRight - host.mLeft, 4229 mTmpLocation[1] + host.mBottom - host.mTop); 4230 4231 host.gatherTransparentRegion(mTransparentRegion); 4232 final Rect bounds = mAttachInfo.mTmpInvalRect; 4233 if (getAccessibilityFocusedRect(bounds)) { 4234 host.applyDrawableToTransparentRegion(getAccessibilityFocusedDrawable(), 4235 mTransparentRegion); 4236 } 4237 if (mTranslator != null) { 4238 mTranslator.translateRegionInWindowToScreen(mTransparentRegion); 4239 } 4240 4241 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) { 4242 mPreviousTransparentRegion.set(mTransparentRegion); 4243 mFullRedrawNeeded = true; 4244 // TODO: Ideally we would do this in prepareSurfaces, 4245 // but prepareSurfaces is currently working under 4246 // the assumption that we paused the render thread 4247 // via the WM relayout code path. We probably eventually 4248 // want to synchronize transparent region hint changes 4249 // with draws. 4250 SurfaceControl sc = getSurfaceControl(); 4251 if (sc.isValid()) { 4252 mTransaction.setTransparentRegionHint(sc, mTransparentRegion).apply(); 4253 } 4254 } 4255 } 4256 4257 if (DBG) { 4258 System.out.println("======================================"); 4259 System.out.println("performTraversals -- after setFrame"); 4260 host.debug(); 4261 } 4262 } 4263 4264 boolean didUseTransaction = false; 4265 // These callbacks will trigger SurfaceView SurfaceHolder.Callbacks and must be invoked 4266 // after the measure pass. If its invoked before the measure pass and the app modifies 4267 // the view hierarchy in the callbacks, we could leave the views in a broken state. 4268 if (surfaceCreated) { 4269 notifySurfaceCreated(mTransaction); 4270 didUseTransaction = true; 4271 } else if (surfaceReplaced) { 4272 notifySurfaceReplaced(mTransaction); 4273 didUseTransaction = true; 4274 } else if (surfaceDestroyed) { 4275 notifySurfaceDestroyed(); 4276 } 4277 4278 if (didUseTransaction) { 4279 applyTransactionOnDraw(mTransaction); 4280 } 4281 4282 if (triggerGlobalLayoutListener) { 4283 mAttachInfo.mRecomputeGlobalAttributes = false; 4284 mAttachInfo.mTreeObserver.dispatchOnGlobalLayout(); 4285 } 4286 4287 Rect contentInsets = null; 4288 Rect visibleInsets = null; 4289 Region touchableRegion = null; 4290 int touchableInsetMode = TOUCHABLE_INSETS_REGION; 4291 boolean computedInternalInsets = false; 4292 if (computesInternalInsets) { 4293 final ViewTreeObserver.InternalInsetsInfo insets = mAttachInfo.mGivenInternalInsets; 4294 4295 // Clear the original insets. 4296 insets.reset(); 4297 4298 // Compute new insets in place. 4299 mAttachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets); 4300 mAttachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty(); 4301 4302 // Tell the window manager. 4303 if (insetsPending || !mLastGivenInsets.equals(insets)) { 4304 mLastGivenInsets.set(insets); 4305 4306 // Translate insets to screen coordinates if needed. 4307 if (mTranslator != null) { 4308 contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets); 4309 visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets); 4310 touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion); 4311 } else { 4312 contentInsets = insets.contentInsets; 4313 visibleInsets = insets.visibleInsets; 4314 touchableRegion = insets.touchableRegion; 4315 } 4316 computedInternalInsets = true; 4317 } 4318 touchableInsetMode = insets.mTouchableInsets; 4319 } 4320 boolean needsSetInsets = computedInternalInsets; 4321 needsSetInsets |= !Objects.equals(mPreviousTouchableRegion, mTouchableRegion) && 4322 (mTouchableRegion != null); 4323 if (needsSetInsets) { 4324 if (mTouchableRegion != null) { 4325 if (mPreviousTouchableRegion == null) { 4326 mPreviousTouchableRegion = new Region(); 4327 } 4328 mPreviousTouchableRegion.set(mTouchableRegion); 4329 if (touchableInsetMode != TOUCHABLE_INSETS_REGION) { 4330 Log.e(mTag, "Setting touchableInsetMode to non TOUCHABLE_INSETS_REGION" + 4331 " from OnComputeInternalInsets, while also using setTouchableRegion" + 4332 " causes setTouchableRegion to be ignored"); 4333 } 4334 } else { 4335 mPreviousTouchableRegion = null; 4336 } 4337 if (contentInsets == null) contentInsets = new Rect(0,0,0,0); 4338 if (visibleInsets == null) visibleInsets = new Rect(0,0,0,0); 4339 if (touchableRegion == null) { 4340 touchableRegion = mTouchableRegion; 4341 } else if (touchableRegion != null && mTouchableRegion != null) { 4342 touchableRegion.op(touchableRegion, mTouchableRegion, Region.Op.UNION); 4343 } 4344 try { 4345 mWindowSession.setInsets(mWindow, touchableInsetMode, 4346 contentInsets, visibleInsets, touchableRegion); 4347 } catch (RemoteException e) { 4348 throw e.rethrowFromSystemServer(); 4349 } 4350 } else if (mTouchableRegion == null && mPreviousTouchableRegion != null) { 4351 mPreviousTouchableRegion = null; 4352 try { 4353 mWindowSession.clearTouchableRegion(mWindow); 4354 } catch (RemoteException e) { 4355 throw e.rethrowFromSystemServer(); 4356 } 4357 } 4358 4359 if (mFirst) { 4360 if (sAlwaysAssignFocus || !isInTouchMode()) { 4361 // handle first focus request 4362 if (DEBUG_INPUT_RESIZE) { 4363 Log.v(mTag, "First: mView.hasFocus()=" + mView.hasFocus()); 4364 } 4365 if (mView != null) { 4366 if (!mView.hasFocus()) { 4367 mView.restoreDefaultFocus(); 4368 if (DEBUG_INPUT_RESIZE) { 4369 Log.v(mTag, "First: requested focused view=" + mView.findFocus()); 4370 } 4371 } else { 4372 if (DEBUG_INPUT_RESIZE) { 4373 Log.v(mTag, "First: existing focused view=" + mView.findFocus()); 4374 } 4375 } 4376 } 4377 } else { 4378 // Some views (like ScrollView) won't hand focus to descendants that aren't within 4379 // their viewport. Before layout, there's a good change these views are size 0 4380 // which means no children can get focus. After layout, this view now has size, but 4381 // is not guaranteed to hand-off focus to a focusable child (specifically, the edge- 4382 // case where the child has a size prior to layout and thus won't trigger 4383 // focusableViewAvailable). 4384 View focused = mView.findFocus(); 4385 if (focused instanceof ViewGroup 4386 && ((ViewGroup) focused).getDescendantFocusability() 4387 == ViewGroup.FOCUS_AFTER_DESCENDANTS) { 4388 focused.restoreDefaultFocus(); 4389 } 4390 } 4391 4392 if (shouldEnableDvrr()) { 4393 // Boost the frame rate when the ViewRootImpl first becomes available. 4394 boostFrameRate(FRAME_RATE_BOOST_TIME); 4395 } 4396 } 4397 4398 final boolean changedVisibility = (viewVisibilityChanged || mFirst) && isViewVisible; 4399 if (changedVisibility) { 4400 maybeFireAccessibilityWindowStateChangedEvent(); 4401 } 4402 4403 mFirst = false; 4404 mWillDrawSoon = false; 4405 mNewSurfaceNeeded = false; 4406 mViewVisibility = viewVisibility; 4407 4408 final boolean hasWindowFocus = mAttachInfo.mHasWindowFocus && isViewVisible; 4409 mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes); 4410 4411 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { 4412 reportNextDraw("first_relayout"); 4413 } 4414 4415 mCheckIfCanDraw = isSyncRequest || cancelDraw; 4416 4417 boolean cancelDueToPreDrawListener = mAttachInfo.mTreeObserver.dispatchOnPreDraw(); 4418 boolean cancelAndRedraw = cancelDueToPreDrawListener 4419 || (cancelDraw && mDrewOnceForSync); 4420 4421 if (!cancelAndRedraw) { 4422 // A sync was already requested before the WMS requested sync. This means we need to 4423 // sync the buffer, regardless if WMS wants to sync the buffer. 4424 if (mActiveSurfaceSyncGroup != null) { 4425 mSyncBuffer = true; 4426 } 4427 4428 createSyncIfNeeded(); 4429 notifyDrawStarted(isInWMSRequestedSync()); 4430 mDrewOnceForSync = true; 4431 4432 // If the active SSG is also requesting to sync a buffer, the following needs to happen 4433 // 1. Ensure we keep track of the number of active syncs to know when to disable RT 4434 // RT animations that conflict with syncing a buffer. 4435 // 2. Add a safeguard SSG to prevent multiple SSG that sync buffers from being submitted 4436 // out of order. 4437 if (mActiveSurfaceSyncGroup != null && mSyncBuffer) { 4438 updateSyncInProgressCount(mActiveSurfaceSyncGroup); 4439 safeguardOverlappingSyncs(mActiveSurfaceSyncGroup); 4440 } 4441 } 4442 4443 if (!isViewVisible) { 4444 if (mLastTraversalWasVisible) { 4445 logAndTrace("Not drawing due to not visible. Reason=" + viewVisibilityReason); 4446 } 4447 mLastPerformTraversalsSkipDrawReason = "view_not_visible"; 4448 if (mPendingTransitions != null && mPendingTransitions.size() > 0) { 4449 for (int i = 0; i < mPendingTransitions.size(); ++i) { 4450 mPendingTransitions.get(i).endChangingAnimations(); 4451 } 4452 mPendingTransitions.clear(); 4453 } 4454 4455 handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions, 4456 mPendingTransaction, "view not visible"); 4457 mHasPendingTransactions = false; 4458 } else if (cancelAndRedraw) { 4459 if (!mWasLastDrawCanceled) { 4460 logAndTrace("Canceling draw." 4461 + " cancelDueToPreDrawListener=" + cancelDueToPreDrawListener 4462 + " cancelDueToSync=" + (cancelDraw && mDrewOnceForSync)); 4463 } 4464 mLastPerformTraversalsSkipDrawReason = cancelDueToPreDrawListener 4465 ? "predraw_" + mAttachInfo.mTreeObserver.getLastDispatchOnPreDrawCanceledReason() 4466 : "cancel_" + cancelReason; 4467 // Try again 4468 scheduleTraversals(); 4469 } else { 4470 if (mWasLastDrawCanceled) { 4471 logAndTrace("Draw frame after cancel"); 4472 } 4473 if (!mLastTraversalWasVisible) { 4474 logAndTrace("Start draw after previous draw not visible"); 4475 } 4476 if (mPendingTransitions != null && mPendingTransitions.size() > 0) { 4477 for (int i = 0; i < mPendingTransitions.size(); ++i) { 4478 mPendingTransitions.get(i).startChangingAnimations(); 4479 } 4480 mPendingTransitions.clear(); 4481 } 4482 if (!performDraw(mActiveSurfaceSyncGroup)) { 4483 handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions, 4484 mPendingTransaction, mLastPerformDrawSkippedReason); 4485 mHasPendingTransactions = false; 4486 } 4487 } 4488 mWasLastDrawCanceled = cancelAndRedraw; 4489 mLastTraversalWasVisible = isViewVisible; 4490 4491 if (mAttachInfo.mContentCaptureEvents != null) { 4492 notifyContentCaptureEvents(); 4493 } 4494 4495 mIsInTraversal = false; 4496 mRelayoutRequested = false; 4497 4498 if (!cancelAndRedraw) { 4499 mReportNextDraw = false; 4500 mLastReportNextDrawReason = null; 4501 mActiveSurfaceSyncGroup = null; 4502 if (mHasPendingTransactions) { 4503 // TODO: We shouldn't ever actually hit this, it means mPendingTransaction wasn't 4504 // merged with a sync group or BLASTBufferQueue before making it to this point 4505 // But better a one or two frame flicker than steady-state broken from dropping 4506 // whatever is in this transaction 4507 // apply immediately with bbq apply token 4508 mergeWithNextTransaction(mPendingTransaction, 0); 4509 mHasPendingTransactions = false; 4510 } 4511 mSyncBuffer = false; 4512 if (isInWMSRequestedSync()) { 4513 mWmsRequestSyncGroup.markSyncReady(); 4514 mWmsRequestSyncGroup = null; 4515 mWmsRequestSyncGroupState = WMS_SYNC_NONE; 4516 } 4517 } 4518 4519 // For the variable refresh rate project. 4520 // We set the preferred frame rate and frame rate category at the end of performTraversals 4521 // when the values are applicable. 4522 if (mDrawnThisFrame) { 4523 if (sToolkitInitialTouchBoostFlagValue && mIsTouchBoosting) { 4524 mTouchAndDrawn = true; 4525 } 4526 4527 mDrawnThisFrame = false; 4528 if (!mInvalidationIdleMessagePosted && sSurfaceFlingerBugfixFlagValue) { 4529 mInvalidationIdleMessagePosted = true; 4530 mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE, IDLE_TIME_MILLIS); 4531 } 4532 setCategoryFromCategoryCounts(); 4533 updateInfrequentCount(); 4534 updateFrameRateFromThreadedRendererViews(); 4535 setPreferredFrameRate(mPreferredFrameRate); 4536 setPreferredFrameRateCategory(mPreferredFrameRateCategory); 4537 if (mPreferredFrameRate > 0 4538 || (mLastPreferredFrameRate != 0 && mPreferredFrameRate == 0) 4539 ) { 4540 mHandler.removeMessages(MSG_FRAME_RATE_SETTING); 4541 mHandler.sendEmptyMessageDelayed(MSG_FRAME_RATE_SETTING, 4542 FRAME_RATE_SETTING_REEVALUATE_TIME); 4543 } 4544 mFrameRateCategoryHighCount = mFrameRateCategoryHighCount > 0 4545 ? mFrameRateCategoryHighCount - 1 : mFrameRateCategoryHighCount; 4546 mFrameRateCategoryHighHintCount = mFrameRateCategoryHighHintCount > 0 4547 ? mFrameRateCategoryHighHintCount - 1 : mFrameRateCategoryHighHintCount; 4548 mFrameRateCategoryNormalCount = mFrameRateCategoryNormalCount > 0 4549 ? mFrameRateCategoryNormalCount - 1 : mFrameRateCategoryNormalCount; 4550 mFrameRateCategoryLowCount = mFrameRateCategoryLowCount > 0 4551 ? mFrameRateCategoryLowCount - 1 : mFrameRateCategoryLowCount; 4552 mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_DEFAULT; 4553 mPreferredFrameRate = -1; 4554 mIsFrameRateConflicted = false; 4555 mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_UNKNOWN; 4556 mSurfaceReplaced = false; 4557 } else if (mPreferredFrameRate == 0) { 4558 // From MSG_FRAME_RATE_SETTING, where mPreferredFrameRate is set to 0 4559 setPreferredFrameRate(0); 4560 mPreferredFrameRate = -1; 4561 } 4562 } 4563 createSyncIfNeeded()4564 private void createSyncIfNeeded() { 4565 // WMS requested sync already started or there's nothing needing to sync 4566 if (isInWMSRequestedSync() || !mReportNextDraw) { 4567 return; 4568 } 4569 4570 final int seqId = mSyncSeqId; 4571 mWmsRequestSyncGroupState = WMS_SYNC_PENDING; 4572 mWmsRequestSyncGroup = new SurfaceSyncGroup("wmsSync-" + mTag, t -> { 4573 mWmsRequestSyncGroupState = WMS_SYNC_MERGED; 4574 // See b/286355097. If the current process is not system, then invoking finishDraw on 4575 // any thread is fine since once it calls into system process, finishDrawing will run 4576 // on a different thread. However, when the current process is system, the finishDraw in 4577 // system server will be run on the current thread, which could result in a deadlock. 4578 if (mWindowSession instanceof Binder) { 4579 // The transaction should be copied to a local reference when posting onto a new 4580 // thread because up until now the SSG is holding a lock on the transaction. Once 4581 // the call jumps onto a new thread, the lock is no longer held and the transaction 4582 // send back may be modified or used again. 4583 Transaction transactionCopy = new Transaction(); 4584 transactionCopy.merge(t); 4585 mHandler.postAtFrontOfQueue(() -> reportDrawFinished(transactionCopy, seqId)); 4586 } else { 4587 reportDrawFinished(t, seqId); 4588 } 4589 }); 4590 4591 // Only trigger once per {@link ViewRootImpl} instance, so don't add listener if 4592 // {link mTransactionCompletedTimeNs} has already been set. 4593 if (mAppStartInfoTimestampsFlagValue && !mAppStartTrackingStarted) { 4594 mAppStartTrackingStarted = true; 4595 Transaction transaction = new Transaction(); 4596 transaction.addTransactionCompletedListener(mSimpleExecutor, 4597 new Consumer<TransactionStats>() { 4598 @Override 4599 public void accept(TransactionStats transactionStats) { 4600 SyncFence presentFence = transactionStats.getPresentFence(); 4601 if (presentFence.awaitForever()) { 4602 if (mFirstFramePresentedTimeNs == -1) { 4603 // Only trigger once per {@link ViewRootImpl} instance. 4604 mFirstFramePresentedTimeNs = presentFence.getSignalTime(); 4605 maybeSendAppStartTimes(); 4606 } 4607 } 4608 presentFence.close(); 4609 } 4610 }); 4611 applyTransactionOnDraw(transaction); 4612 } 4613 4614 if (DEBUG_BLAST) { 4615 Log.d(mTag, "Setup new sync=" + mWmsRequestSyncGroup.getName()); 4616 } 4617 4618 mWmsRequestSyncGroup.add(this, null /* runnable */); 4619 } 4620 maybeSendAppStartTimes()4621 private void maybeSendAppStartTimes() { 4622 if (mAppStartTimestampsSent.get()) { 4623 // Don't send timestamps more than once. 4624 return; 4625 } 4626 4627 // Post to main thread 4628 mHandler.post(new Runnable() { 4629 @Override 4630 public void run() { 4631 if (mRenderThreadDrawStartTimeNs == -1) { 4632 return; 4633 } 4634 4635 try { 4636 ActivityManager.getService().reportStartInfoViewTimestamps( 4637 mRenderThreadDrawStartTimeNs, mFirstFramePresentedTimeNs); 4638 mAppStartTimestampsSent.set(true); 4639 } catch (RemoteException e) { 4640 // Ignore, timestamps may be lost. 4641 if (DBG) Log.d(TAG, "Exception attempting to report start timestamps.", e); 4642 } 4643 } 4644 }); 4645 } 4646 4647 /** 4648 * Helper used to notify the service to block projection when a sensitive 4649 * view (the view displays sensitive content) is attached to the window. 4650 * The window manager service is also notified to unblock projection when 4651 * no attached view (to the window) displays sensitive content. 4652 * 4653 * <ol> 4654 * <li>It should only notify service to block projection when first sensitive view is 4655 * attached to the window. 4656 * <li>It should only notify service to unblock projection when all sensitive view are 4657 * removed from the window. 4658 * </ol> 4659 * 4660 * @param enableProtection if true, the protection is enabled for this window. 4661 * if false, the protection is removed for this window. 4662 */ applySensitiveContentAppProtection(boolean enableProtection)4663 private void applySensitiveContentAppProtection(boolean enableProtection) { 4664 try { 4665 if (mSensitiveContentProtectionService == null) { 4666 return; 4667 } 4668 if (DEBUG_SENSITIVE_CONTENT) { 4669 Log.d(TAG, "Notify sensitive content, package=" + mContext.getPackageName() 4670 + ", token=" + getWindowToken() + ", flag=" + enableProtection); 4671 } 4672 // The window would be blocked during screen share if it shows sensitive content. 4673 mSensitiveContentProtectionService.setSensitiveContentProtection( 4674 getWindowToken(), mContext.getPackageName(), enableProtection); 4675 } catch (RemoteException ex) { 4676 Log.e(TAG, "Unable to protect sensitive content during screen share", ex); 4677 } 4678 } 4679 4680 /** 4681 * Add sensitive content protection, when there are one or more visible sensitive views. 4682 */ addSensitiveContentAppProtection()4683 void addSensitiveContentAppProtection() { 4684 applySensitiveContentAppProtection(true); 4685 } 4686 4687 /** 4688 * Remove sensitive content protection, when there is no visible sensitive view. 4689 */ removeSensitiveContentAppProtection()4690 void removeSensitiveContentAppProtection() { 4691 if (!sensitiveContentPrematureProtectionRemovedFix()) { 4692 applySensitiveContentAppProtection(false); 4693 return; 4694 } 4695 if (DEBUG_SENSITIVE_CONTENT) { 4696 Log.d(TAG, "Add transaction to remove sensitive content protection, package=" 4697 + mContext.getPackageName() + ", token=" + getWindowToken()); 4698 } 4699 Transaction t = new Transaction(); 4700 t.addTransactionCommittedListener(mExecutor, () -> { 4701 if (mAttachInfo.mSensitiveViewsCount == 0) { 4702 applySensitiveContentAppProtection(false); 4703 } 4704 }); 4705 applyTransactionOnDraw(t); 4706 } 4707 notifyContentCaptureEvents()4708 private void notifyContentCaptureEvents() { 4709 if (!isContentCaptureEnabled()) { 4710 if (DEBUG_CONTENT_CAPTURE) { 4711 Log.d(mTag, "notifyContentCaptureEvents while disabled"); 4712 } 4713 mAttachInfo.mContentCaptureEvents = null; 4714 return; 4715 } 4716 4717 final ContentCaptureManager manager = mAttachInfo.mContentCaptureManager; 4718 if (manager != null && mAttachInfo.mContentCaptureEvents != null) { 4719 final ContentCaptureSession session = manager.getMainContentCaptureSession(); 4720 session.notifyContentCaptureEvents(mAttachInfo.mContentCaptureEvents); 4721 } 4722 mAttachInfo.mContentCaptureEvents = null; 4723 } 4724 notifyHolderSurfaceDestroyed()4725 private void notifyHolderSurfaceDestroyed() { 4726 mSurfaceHolder.ungetCallbacks(); 4727 SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks(); 4728 if (callbacks != null) { 4729 for (SurfaceHolder.Callback c : callbacks) { 4730 c.surfaceDestroyed(mSurfaceHolder); 4731 } 4732 } 4733 } 4734 maybeHandleWindowMove(Rect frame)4735 private void maybeHandleWindowMove(Rect frame) { 4736 // TODO: Well, we are checking whether the frame has changed similarly 4737 // to how this is done for the insets. This is however incorrect since 4738 // the insets and the frame are translated. For example, the old frame 4739 // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new 4740 // reported frame is (2, 2 - 2, 2) which implies no change but this is not 4741 // true since we are comparing a not translated value to a translated one. 4742 // This scenario is rare but we may want to fix that. 4743 4744 final boolean windowMoved = mAttachInfo.mWindowLeft != frame.left 4745 || mAttachInfo.mWindowTop != frame.top; 4746 if (windowMoved) { 4747 mAttachInfo.mWindowLeft = frame.left; 4748 mAttachInfo.mWindowTop = frame.top; 4749 } 4750 if (windowMoved || mAttachInfo.mNeedsUpdateLightCenter) { 4751 // Update the light position for the new offsets. 4752 if (mAttachInfo.mThreadedRenderer != null) { 4753 mAttachInfo.mThreadedRenderer.setLightCenter(mAttachInfo); 4754 } 4755 mAttachInfo.mNeedsUpdateLightCenter = false; 4756 } 4757 } 4758 handleWindowFocusChanged()4759 private void handleWindowFocusChanged() { 4760 final boolean hasWindowFocus; 4761 synchronized (this) { 4762 if (!mWindowFocusChanged) { 4763 return; 4764 } 4765 mWindowFocusChanged = false; 4766 hasWindowFocus = mUpcomingWindowFocus; 4767 } 4768 if (hasWindowFocus) { 4769 mInsetsController.onWindowFocusGained( 4770 getFocusedViewOrNull() != null /* hasViewFocused */); 4771 } else { 4772 mInsetsController.onWindowFocusLost(); 4773 } 4774 4775 if (mAdded) { 4776 dispatchFocusEvent(hasWindowFocus, false /* fakeFocus */); 4777 // Note: must be done after the focus change callbacks, 4778 // so all of the view state is set up correctly. 4779 mImeFocusController.onPostWindowFocus( 4780 getFocusedViewOrNull(), hasWindowFocus, mWindowAttributes); 4781 4782 if (hasWindowFocus) { 4783 // Clear the forward bit. We can just do this directly, since 4784 // the window manager doesn't care about it. 4785 mWindowAttributes.softInputMode &= 4786 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; 4787 ((WindowManager.LayoutParams) mView.getLayoutParams()) 4788 .softInputMode &= 4789 ~WindowManager.LayoutParams 4790 .SOFT_INPUT_IS_FORWARD_NAVIGATION; 4791 4792 maybeFireAccessibilityWindowStateChangedEvent(); 4793 4794 // Refocusing a window that has a focused view should fire a 4795 // focus event for the view since the global focused view changed. 4796 fireAccessibilityFocusEventIfHasFocusedNode(); 4797 } else { 4798 if (mPointerCapture) { 4799 handlePointerCaptureChanged(false); 4800 } 4801 } 4802 } 4803 mFirstInputStage.onWindowFocusChanged(hasWindowFocus); 4804 4805 // NOTE: there's no view visibility (appeared / disapparead) events when the windows focus 4806 // is lost, so we don't need to to force a flush - there might be other events such as 4807 // text changes, but these should be flushed independently. 4808 if (hasWindowFocus) { 4809 handleContentCaptureFlush(); 4810 } 4811 } 4812 4813 /** 4814 * Send a fake focus event for unfocused apps in split screen as some game engines wait to 4815 * get focus before drawing the content of the app. This will be used so that apps do not get 4816 * blacked out when they are resumed and do not have focus yet. 4817 * 4818 * {@hide} 4819 */ 4820 // TODO(b/263094829): Investigate dispatching this for onPause as well dispatchCompatFakeFocus()4821 public void dispatchCompatFakeFocus() { 4822 boolean aboutToHaveFocus = false; 4823 synchronized (this) { 4824 aboutToHaveFocus = mWindowFocusChanged && mUpcomingWindowFocus; 4825 } 4826 final boolean alreadyHaveFocus = mAttachInfo.mHasWindowFocus; 4827 if (aboutToHaveFocus || alreadyHaveFocus) { 4828 // Do not need to toggle focus if app doesn't need it, or has focus. 4829 return; 4830 } 4831 EventLog.writeEvent(LOGTAG_INPUT_FOCUS, 4832 "Giving fake focus to " + mBasePackageName, "reason=unity bug workaround"); 4833 dispatchFocusEvent(true /* hasWindowFocus */, true /* fakeFocus */); 4834 EventLog.writeEvent(LOGTAG_INPUT_FOCUS, 4835 "Removing fake focus from " + mBasePackageName, "reason=timeout callback"); 4836 dispatchFocusEvent(false /* hasWindowFocus */, true /* fakeFocus */); 4837 } 4838 dispatchFocusEvent(boolean hasWindowFocus, boolean fakeFocus)4839 private void dispatchFocusEvent(boolean hasWindowFocus, boolean fakeFocus) { 4840 profileRendering(hasWindowFocus); 4841 if (hasWindowFocus && mAttachInfo.mThreadedRenderer != null && mSurface.isValid()) { 4842 mFullRedrawNeeded = true; 4843 try { 4844 final Rect surfaceInsets = mWindowAttributes.surfaceInsets; 4845 mAttachInfo.mThreadedRenderer.initializeIfNeeded( 4846 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets); 4847 } catch (OutOfResourcesException e) { 4848 Log.e(mTag, "OutOfResourcesException locking surface", e); 4849 try { 4850 if (!mWindowSession.outOfMemory(mWindow)) { 4851 Slog.w(mTag, "No processes killed for memory;" 4852 + " killing self"); 4853 Process.killProcess(Process.myPid()); 4854 } 4855 } catch (RemoteException ex) { 4856 } 4857 // Retry in a bit. 4858 mHandler.sendMessageDelayed(mHandler.obtainMessage( 4859 MSG_WINDOW_FOCUS_CHANGED), 500); 4860 return; 4861 } 4862 } 4863 4864 mAttachInfo.mHasWindowFocus = hasWindowFocus; 4865 4866 if (!fakeFocus) { 4867 mImeFocusController.onPreWindowFocus(hasWindowFocus, mWindowAttributes); 4868 } 4869 4870 if (mView != null) { 4871 mAttachInfo.mKeyDispatchState.reset(); 4872 mView.dispatchWindowFocusChanged(hasWindowFocus); 4873 mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus); 4874 if (mAttachInfo.mTooltipHost != null) { 4875 mAttachInfo.mTooltipHost.hideTooltip(); 4876 } 4877 } 4878 } 4879 handleWindowTouchModeChanged()4880 private void handleWindowTouchModeChanged() { 4881 final boolean inTouchMode; 4882 synchronized (this) { 4883 inTouchMode = mUpcomingInTouchMode; 4884 } 4885 ensureTouchModeLocally(inTouchMode); 4886 } 4887 maybeFireAccessibilityWindowStateChangedEvent()4888 private void maybeFireAccessibilityWindowStateChangedEvent() { 4889 // Toasts are presented as notifications - don't present them as windows as well. 4890 boolean isToast = mWindowAttributes != null && (mWindowAttributes.type == TYPE_TOAST); 4891 if (!isToast && mView != null) { 4892 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 4893 } 4894 } 4895 fireAccessibilityFocusEventIfHasFocusedNode()4896 private void fireAccessibilityFocusEventIfHasFocusedNode() { 4897 if (!mAccessibilityManager.isEnabled()) { 4898 return; 4899 } 4900 final View focusedView = mView.findFocus(); 4901 if (focusedView == null) { 4902 return; 4903 } 4904 final AccessibilityNodeProvider provider = focusedView.getAccessibilityNodeProvider(); 4905 if (provider == null) { 4906 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 4907 } else { 4908 final AccessibilityNodeInfo focusedNode = findFocusedVirtualNode(provider); 4909 if (focusedNode != null) { 4910 final int virtualId = AccessibilityNodeInfo.getVirtualDescendantId( 4911 focusedNode.getSourceNodeId()); 4912 // This is a best effort since clearing and setting the focus via the 4913 // provider APIs could have side effects. We don't have a provider API 4914 // similar to that on View to ask a given event to be fired. 4915 final AccessibilityEvent event = AccessibilityEvent.obtain( 4916 AccessibilityEvent.TYPE_VIEW_FOCUSED); 4917 event.setSource(focusedView, virtualId); 4918 event.setPackageName(focusedNode.getPackageName()); 4919 event.setChecked(focusedNode.isChecked()); 4920 event.setContentDescription(focusedNode.getContentDescription()); 4921 event.setPassword(focusedNode.isPassword()); 4922 event.getText().add(focusedNode.getText()); 4923 event.setEnabled(focusedNode.isEnabled()); 4924 focusedView.getParent().requestSendAccessibilityEvent(focusedView, event); 4925 focusedNode.recycle(); 4926 } 4927 } 4928 } 4929 findFocusedVirtualNode(AccessibilityNodeProvider provider)4930 private AccessibilityNodeInfo findFocusedVirtualNode(AccessibilityNodeProvider provider) { 4931 AccessibilityNodeInfo focusedNode = provider.findFocus( 4932 AccessibilityNodeInfo.FOCUS_INPUT); 4933 if (focusedNode != null) { 4934 return focusedNode; 4935 } 4936 4937 if (!mContext.isAutofillCompatibilityEnabled()) { 4938 return null; 4939 } 4940 4941 // Unfortunately some provider implementations don't properly 4942 // implement AccessibilityNodeProvider#findFocus 4943 AccessibilityNodeInfo current = provider.createAccessibilityNodeInfo( 4944 AccessibilityNodeProvider.HOST_VIEW_ID); 4945 if (current == null) { 4946 return null; 4947 } 4948 if (current.isFocused()) { 4949 return current; 4950 } 4951 4952 final Queue<AccessibilityNodeInfo> fringe = new ArrayDeque<>(); 4953 fringe.offer(current); 4954 4955 while (!fringe.isEmpty()) { 4956 current = fringe.poll(); 4957 final LongArray childNodeIds = current.getChildNodeIds(); 4958 if (childNodeIds== null || childNodeIds.size() <= 0) { 4959 continue; 4960 } 4961 final int childCount = childNodeIds.size(); 4962 for (int i = 0; i < childCount; i++) { 4963 final int virtualId = AccessibilityNodeInfo.getVirtualDescendantId( 4964 childNodeIds.get(i)); 4965 final AccessibilityNodeInfo child = provider.createAccessibilityNodeInfo(virtualId); 4966 if (child != null) { 4967 if (child.isFocused()) { 4968 return child; 4969 } 4970 fringe.offer(child); 4971 } 4972 } 4973 current.recycle(); 4974 } 4975 4976 return null; 4977 } 4978 handleOutOfResourcesException(Surface.OutOfResourcesException e)4979 private void handleOutOfResourcesException(Surface.OutOfResourcesException e) { 4980 Log.e(mTag, "OutOfResourcesException initializing HW surface", e); 4981 try { 4982 if (!mWindowSession.outOfMemory(mWindow) && 4983 Process.myUid() != Process.SYSTEM_UID) { 4984 Slog.w(mTag, "No processes killed for memory; killing self"); 4985 Process.killProcess(Process.myPid()); 4986 } 4987 } catch (RemoteException ex) { 4988 } 4989 mLayoutRequested = true; // ask wm for a new surface next time. 4990 } 4991 performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec)4992 private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) { 4993 if (mView == null) { 4994 return; 4995 } 4996 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure"); 4997 try { 4998 mView.measure(childWidthMeasureSpec, childHeightMeasureSpec); 4999 } finally { 5000 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 5001 } 5002 mMeasuredWidth = mView.getMeasuredWidth(); 5003 mMeasuredHeight = mView.getMeasuredHeight(); 5004 mViewMeasureDeferred = false; 5005 } 5006 5007 /** 5008 * Called by {@link android.view.View#isInLayout()} to determine whether the view hierarchy 5009 * is currently undergoing a layout pass. 5010 * 5011 * @return whether the view hierarchy is currently undergoing a layout pass 5012 */ isInLayout()5013 boolean isInLayout() { 5014 return mInLayout; 5015 } 5016 5017 /** 5018 * Called by {@link android.view.View#requestLayout()} if the view hierarchy is currently 5019 * undergoing a layout pass. requestLayout() should not generally be called during layout, 5020 * unless the container hierarchy knows what it is doing (i.e., it is fine as long as 5021 * all children in that container hierarchy are measured and laid out at the end of the layout 5022 * pass for that container). If requestLayout() is called anyway, we handle it correctly 5023 * by registering all requesters during a frame as it proceeds. At the end of the frame, 5024 * we check all of those views to see if any still have pending layout requests, which 5025 * indicates that they were not correctly handled by their container hierarchy. If that is 5026 * the case, we clear all such flags in the tree, to remove the buggy flag state that leads 5027 * to blank containers, and force a second request/measure/layout pass in this frame. If 5028 * more requestLayout() calls are received during that second layout pass, we post those 5029 * requests to the next frame to avoid possible infinite loops. 5030 * 5031 * <p>The return value from this method indicates whether the request should proceed 5032 * (if it is a request during the first layout pass) or should be skipped and posted to the 5033 * next frame (if it is a request during the second layout pass).</p> 5034 * 5035 * @param view the view that requested the layout. 5036 * 5037 * @return true if request should proceed, false otherwise. 5038 */ requestLayoutDuringLayout(final View view)5039 boolean requestLayoutDuringLayout(final View view) { 5040 if (view.mParent == null || view.mAttachInfo == null) { 5041 // Would not normally trigger another layout, so just let it pass through as usual 5042 return true; 5043 } 5044 if (!mLayoutRequesters.contains(view)) { 5045 mLayoutRequesters.add(view); 5046 } 5047 if (!mHandlingLayoutInLayoutRequest) { 5048 // Let the request proceed normally; it will be processed in a second layout pass 5049 // if necessary 5050 return true; 5051 } else { 5052 // Don't let the request proceed during the second layout pass. 5053 // It will post to the next frame instead. 5054 return false; 5055 } 5056 } 5057 performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, int desiredWindowHeight)5058 private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, 5059 int desiredWindowHeight) { 5060 mScrollMayChange = true; 5061 mInLayout = true; 5062 5063 final View host = mView; 5064 if (host == null) { 5065 return; 5066 } 5067 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) { 5068 Log.v(mTag, "Laying out " + host + " to (" + 5069 host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")"); 5070 } 5071 5072 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout"); 5073 try { 5074 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight()); 5075 5076 mInLayout = false; 5077 int numViewsRequestingLayout = mLayoutRequesters.size(); 5078 if (numViewsRequestingLayout > 0) { 5079 // requestLayout() was called during layout. 5080 // If no layout-request flags are set on the requesting views, there is no problem. 5081 // If some requests are still pending, then we need to clear those flags and do 5082 // a full request/measure/layout pass to handle this situation. 5083 ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, 5084 false); 5085 if (validLayoutRequesters != null) { 5086 // Set this flag to indicate that any further requests are happening during 5087 // the second pass, which may result in posting those requests to the next 5088 // frame instead 5089 mHandlingLayoutInLayoutRequest = true; 5090 5091 // Process fresh layout requests, then measure and layout 5092 int numValidRequests = validLayoutRequesters.size(); 5093 for (int i = 0; i < numValidRequests; ++i) { 5094 final View view = validLayoutRequesters.get(i); 5095 Log.w("View", "requestLayout() improperly called by " + view + 5096 " during layout: running second layout pass"); 5097 view.requestLayout(); 5098 } 5099 measureHierarchy(host, lp, mView.getContext().getResources(), 5100 desiredWindowWidth, desiredWindowHeight, false /* forRootSizeOnly */); 5101 mInLayout = true; 5102 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight()); 5103 5104 mHandlingLayoutInLayoutRequest = false; 5105 5106 // Check the valid requests again, this time without checking/clearing the 5107 // layout flags, since requests happening during the second pass get noop'd 5108 validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true); 5109 if (validLayoutRequesters != null) { 5110 final ArrayList<View> finalRequesters = validLayoutRequesters; 5111 // Post second-pass requests to the next frame 5112 getRunQueue().post(new Runnable() { 5113 @Override 5114 public void run() { 5115 int numValidRequests = finalRequesters.size(); 5116 for (int i = 0; i < numValidRequests; ++i) { 5117 final View view = finalRequesters.get(i); 5118 Log.w("View", "requestLayout() improperly called by " + view + 5119 " during second layout pass: posting in next frame"); 5120 view.requestLayout(); 5121 } 5122 } 5123 }); 5124 } 5125 } 5126 5127 } 5128 } finally { 5129 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 5130 } 5131 mInLayout = false; 5132 } 5133 5134 /** 5135 * This method is called during layout when there have been calls to requestLayout() during 5136 * layout. It walks through the list of views that requested layout to determine which ones 5137 * still need it, based on visibility in the hierarchy and whether they have already been 5138 * handled (as is usually the case with ListView children). 5139 * 5140 * @param layoutRequesters The list of views that requested layout during layout 5141 * @param secondLayoutRequests Whether the requests were issued during the second layout pass. 5142 * If so, the FORCE_LAYOUT flag was not set on requesters. 5143 * @return A list of the actual views that still need to be laid out. 5144 */ getValidLayoutRequesters(ArrayList<View> layoutRequesters, boolean secondLayoutRequests)5145 private ArrayList<View> getValidLayoutRequesters(ArrayList<View> layoutRequesters, 5146 boolean secondLayoutRequests) { 5147 5148 int numViewsRequestingLayout = layoutRequesters.size(); 5149 ArrayList<View> validLayoutRequesters = null; 5150 for (int i = 0; i < numViewsRequestingLayout; ++i) { 5151 View view = layoutRequesters.get(i); 5152 if (view != null && view.mAttachInfo != null && view.mParent != null && 5153 (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) == 5154 View.PFLAG_FORCE_LAYOUT)) { 5155 boolean gone = false; 5156 View parent = view; 5157 // Only trigger new requests for views in a non-GONE hierarchy 5158 while (parent != null) { 5159 if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) { 5160 gone = true; 5161 break; 5162 } 5163 if (parent.mParent instanceof View) { 5164 parent = (View) parent.mParent; 5165 } else { 5166 parent = null; 5167 } 5168 } 5169 if (!gone) { 5170 if (validLayoutRequesters == null) { 5171 validLayoutRequesters = new ArrayList<View>(); 5172 } 5173 validLayoutRequesters.add(view); 5174 } 5175 } 5176 } 5177 if (!secondLayoutRequests) { 5178 // If we're checking the layout flags, then we need to clean them up also 5179 for (int i = 0; i < numViewsRequestingLayout; ++i) { 5180 View view = layoutRequesters.get(i); 5181 while (view != null && 5182 (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) { 5183 view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT; 5184 if (view.mParent instanceof View) { 5185 view = (View) view.mParent; 5186 } else { 5187 view = null; 5188 } 5189 } 5190 } 5191 } 5192 layoutRequesters.clear(); 5193 return validLayoutRequesters; 5194 } 5195 5196 @Override requestTransparentRegion(View child)5197 public void requestTransparentRegion(View child) { 5198 // the test below should not fail unless someone is messing with us 5199 checkThread(); 5200 if (mView != child) { 5201 return; 5202 } 5203 5204 if ((mView.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) { 5205 mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS; 5206 // Need to make sure we re-evaluate the window attributes next 5207 // time around, to ensure the window has the correct format. 5208 mWindowAttributesChanged = true; 5209 } 5210 5211 // Always request layout to apply the latest transparent region. 5212 requestLayout(); 5213 } 5214 5215 /** 5216 * Figures out the measure spec for the root view in a window based on it's 5217 * layout params. 5218 * 5219 * @param windowSize The available width or height of the window. 5220 * @param measurement The layout width or height requested in the layout params. 5221 * @param privateFlags The private flags in the layout params of the window. 5222 * @return The measure spec to use to measure the root view. 5223 */ getRootMeasureSpec(int windowSize, int measurement, int privateFlags)5224 private static int getRootMeasureSpec(int windowSize, int measurement, int privateFlags) { 5225 int measureSpec; 5226 final int rootDimension = (privateFlags & PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT) != 0 5227 ? MATCH_PARENT : measurement; 5228 switch (rootDimension) { 5229 case ViewGroup.LayoutParams.MATCH_PARENT: 5230 // Window can't resize. Force root view to be windowSize. 5231 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY); 5232 break; 5233 case ViewGroup.LayoutParams.WRAP_CONTENT: 5234 // Window can resize. Set max size for root view. 5235 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST); 5236 break; 5237 default: 5238 // Window wants to be an exact size. Force root view to be that size. 5239 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY); 5240 break; 5241 } 5242 return measureSpec; 5243 } 5244 5245 int mHardwareXOffset; 5246 int mHardwareYOffset; 5247 5248 @Override onPreDraw(RecordingCanvas canvas)5249 public void onPreDraw(RecordingCanvas canvas) { 5250 // If mCurScrollY is not 0 then this influences the hardwareYOffset. The end result is we 5251 // can apply offsets that are not handled by anything else, resulting in underdraw as 5252 // the View is shifted (thus shifting the window background) exposing unpainted 5253 // content. To handle this with minimal glitches we just clear to BLACK if the window 5254 // is opaque. If it's not opaque then HWUI already internally does a glClear to 5255 // transparent, so there's no risk of underdraw on non-opaque surfaces. 5256 if (mCurScrollY != 0 && mHardwareYOffset != 0 && mAttachInfo.mThreadedRenderer.isOpaque()) { 5257 canvas.drawColor(Color.BLACK); 5258 } 5259 canvas.translate(-mHardwareXOffset, -mHardwareYOffset); 5260 } 5261 5262 @Override onPostDraw(RecordingCanvas canvas)5263 public void onPostDraw(RecordingCanvas canvas) { 5264 drawAccessibilityFocusedDrawableIfNeeded(canvas); 5265 if (mUseMTRenderer) { 5266 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { 5267 mWindowCallbacks.get(i).onPostDraw(canvas); 5268 } 5269 } 5270 } 5271 5272 /** 5273 * @hide 5274 */ outputDisplayList(View view)5275 void outputDisplayList(View view) { 5276 view.mRenderNode.output(); 5277 } 5278 5279 /** 5280 * @see #PROPERTY_PROFILE_RENDERING 5281 */ profileRendering(boolean enabled)5282 private void profileRendering(boolean enabled) { 5283 if (mProfileRendering) { 5284 mRenderProfilingEnabled = enabled; 5285 5286 if (mRenderProfiler != null) { 5287 mChoreographer.removeFrameCallback(mRenderProfiler); 5288 } 5289 if (mRenderProfilingEnabled) { 5290 if (mRenderProfiler == null) { 5291 mRenderProfiler = new Choreographer.FrameCallback() { 5292 @Override 5293 public void doFrame(long frameTimeNanos) { 5294 mDirty.set(0, 0, mWidth, mHeight); 5295 scheduleTraversals(); 5296 if (mRenderProfilingEnabled) { 5297 mChoreographer.postFrameCallback(mRenderProfiler); 5298 } 5299 } 5300 }; 5301 } 5302 mChoreographer.postFrameCallback(mRenderProfiler); 5303 } else { 5304 mRenderProfiler = null; 5305 } 5306 } 5307 } 5308 5309 /** 5310 * Called from draw() when DEBUG_FPS is enabled 5311 */ trackFPS()5312 private void trackFPS() { 5313 // Tracks frames per second drawn. First value in a series of draws may be bogus 5314 // because it down not account for the intervening idle time 5315 long nowTime = System.currentTimeMillis(); 5316 if (mFpsStartTime < 0) { 5317 mFpsStartTime = mFpsPrevTime = nowTime; 5318 mFpsNumFrames = 0; 5319 } else { 5320 ++mFpsNumFrames; 5321 String thisHash = Integer.toHexString(System.identityHashCode(this)); 5322 long frameTime = nowTime - mFpsPrevTime; 5323 long totalTime = nowTime - mFpsStartTime; 5324 Log.v(mTag, "0x" + thisHash + "\tFrame time:\t" + frameTime); 5325 mFpsPrevTime = nowTime; 5326 if (totalTime > 1000) { 5327 float fps = (float) mFpsNumFrames * 1000 / totalTime; 5328 Log.v(mTag, "0x" + thisHash + "\tFPS:\t" + fps); 5329 mFpsStartTime = nowTime; 5330 mFpsNumFrames = 0; 5331 } 5332 } 5333 } 5334 5335 /** 5336 * Called from draw() to collect metrics for frame rate decision. 5337 */ collectFrameRateDecisionMetrics()5338 private void collectFrameRateDecisionMetrics() { 5339 if (!Trace.isEnabled()) { 5340 if (mPreviousFrameDrawnTime > 0) mPreviousFrameDrawnTime = -1; 5341 return; 5342 } 5343 5344 if (mPreviousFrameDrawnTime < 0) { 5345 mPreviousFrameDrawnTime = mChoreographer.getExpectedPresentationTimeNanos(); 5346 return; 5347 } 5348 5349 long expectedDrawnTime = mChoreographer.getExpectedPresentationTimeNanos(); 5350 long timeDiff = expectedDrawnTime - mPreviousFrameDrawnTime; 5351 if (timeDiff <= 0) { 5352 return; 5353 } 5354 5355 long fps = NANOS_PER_SEC / timeDiff; 5356 Trace.setCounter(mFpsTraceName, fps); 5357 mPreviousFrameDrawnTime = expectedDrawnTime; 5358 5359 long percentage = (long) (mLargestChildPercentage * 100); 5360 Trace.setCounter(mLargestViewTraceName, percentage); 5361 mLargestChildPercentage = 0.0f; 5362 } 5363 reportDrawFinished(@ullable Transaction t, int seqId)5364 private void reportDrawFinished(@Nullable Transaction t, int seqId) { 5365 logAndTrace("reportDrawFinished seqId=" + seqId); 5366 try { 5367 mWindowSession.finishDrawing(mWindow, t, seqId); 5368 } catch (RemoteException e) { 5369 Log.e(mTag, "Unable to report draw finished", e); 5370 if (t != null) { 5371 t.apply(); 5372 } 5373 } finally { 5374 if (t != null) { 5375 t.clear(); 5376 } 5377 } 5378 } 5379 5380 /** 5381 * @hide 5382 */ isHardwareEnabled()5383 public boolean isHardwareEnabled() { 5384 return mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled(); 5385 } 5386 5387 /** 5388 * This VRI is currently in the middle of a sync request that was initiated by WMS. 5389 */ isInWMSRequestedSync()5390 public boolean isInWMSRequestedSync() { 5391 return mWmsRequestSyncGroup != null; 5392 } 5393 addFrameCommitCallbackIfNeeded()5394 private void addFrameCommitCallbackIfNeeded() { 5395 if (!isHardwareEnabled()) { 5396 return; 5397 } 5398 5399 ArrayList<Runnable> commitCallbacks = mAttachInfo.mTreeObserver 5400 .captureFrameCommitCallbacks(); 5401 final boolean needFrameCommitCallback = 5402 (commitCallbacks != null && commitCallbacks.size() > 0); 5403 if (!needFrameCommitCallback) { 5404 return; 5405 } 5406 5407 if (DEBUG_DRAW) { 5408 Log.d(mTag, "Creating frameCommitCallback" 5409 + " commitCallbacks size=" + commitCallbacks.size()); 5410 } 5411 mAttachInfo.mThreadedRenderer.setFrameCommitCallback(didProduceBuffer -> { 5412 if (DEBUG_DRAW) { 5413 Log.d(mTag, "Received frameCommitCallback didProduceBuffer=" + didProduceBuffer); 5414 } 5415 5416 mHandler.postAtFrontOfQueue(() -> { 5417 for (int i = 0; i < commitCallbacks.size(); i++) { 5418 commitCallbacks.get(i).run(); 5419 } 5420 }); 5421 }); 5422 } 5423 5424 /** 5425 * These callbacks check if the draw failed for any reason and apply 5426 * those transactions directly so they don't get stuck forever. 5427 */ registerCallbackForPendingTransactions()5428 private void registerCallbackForPendingTransactions() { 5429 Transaction t = new Transaction(); 5430 t.merge(mPendingTransaction); 5431 mHasPendingTransactions = false; 5432 5433 registerRtFrameCallback(new FrameDrawingCallback() { 5434 @Override 5435 public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) { 5436 mergeWithNextTransaction(t, frame); 5437 if ((syncResult 5438 & (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) { 5439 mBlastBufferQueue.applyPendingTransactions(frame); 5440 return null; 5441 } 5442 5443 return didProduceBuffer -> { 5444 if (!didProduceBuffer) { 5445 logAndTrace("Transaction not synced due to no frame drawn"); 5446 mBlastBufferQueue.applyPendingTransactions(frame); 5447 } 5448 }; 5449 5450 } 5451 5452 @Override 5453 public void onFrameDraw(long frame) { 5454 } 5455 }); 5456 } 5457 performDraw(@ullable SurfaceSyncGroup surfaceSyncGroup)5458 private boolean performDraw(@Nullable SurfaceSyncGroup surfaceSyncGroup) { 5459 mLastPerformDrawSkippedReason = null; 5460 if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) { 5461 mLastPerformDrawSkippedReason = "screen_off"; 5462 if (!mLastDrawScreenOff) { 5463 logAndTrace("Not drawing due to screen off"); 5464 } 5465 mLastDrawScreenOff = true; 5466 return false; 5467 } else if (mView == null) { 5468 mLastPerformDrawSkippedReason = "no_root_view"; 5469 return false; 5470 } 5471 5472 if (mLastDrawScreenOff) { 5473 logAndTrace("Resumed drawing after screen turned on"); 5474 mLastDrawScreenOff = false; 5475 } 5476 5477 final boolean fullRedrawNeeded = mFullRedrawNeeded || surfaceSyncGroup != null; 5478 mFullRedrawNeeded = false; 5479 5480 mIsDrawing = true; 5481 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw-" + mTag); 5482 5483 addFrameCommitCallbackIfNeeded(); 5484 5485 boolean usingAsyncReport; 5486 5487 try { 5488 usingAsyncReport = draw(fullRedrawNeeded, surfaceSyncGroup, mSyncBuffer); 5489 if (mAttachInfo.mThreadedRenderer != null && !usingAsyncReport) { 5490 mAttachInfo.mThreadedRenderer.setFrameCallback(null); 5491 } 5492 } finally { 5493 mIsDrawing = false; 5494 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 5495 } 5496 5497 // For whatever reason we didn't create a HardwareRenderer, end any 5498 // hardware animations that are now dangling 5499 if (mAttachInfo.mPendingAnimatingRenderNodes != null) { 5500 final int count = mAttachInfo.mPendingAnimatingRenderNodes.size(); 5501 for (int i = 0; i < count; i++) { 5502 mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators(); 5503 } 5504 mAttachInfo.mPendingAnimatingRenderNodes.clear(); 5505 } 5506 5507 final Transaction pendingTransaction; 5508 if (!usingAsyncReport && mHasPendingTransactions) { 5509 pendingTransaction = new Transaction(); 5510 pendingTransaction.merge(mPendingTransaction); 5511 mHasPendingTransactions = false; 5512 } else { 5513 pendingTransaction = null; 5514 } 5515 5516 if (mReportNextDraw) { 5517 // if we're using multi-thread renderer, wait for the window frame draws 5518 if (mWindowDrawCountDown != null) { 5519 try { 5520 mWindowDrawCountDown.await(); 5521 } catch (InterruptedException e) { 5522 Log.e(mTag, "Window redraw count down interrupted!"); 5523 } 5524 mWindowDrawCountDown = null; 5525 } 5526 5527 if (mAttachInfo.mThreadedRenderer != null) { 5528 mAttachInfo.mThreadedRenderer.setStopped(mStopped); 5529 } 5530 5531 if (LOCAL_LOGV) { 5532 Log.v(mTag, "FINISHED DRAWING: " + mWindowAttributes.getTitle()); 5533 } 5534 5535 if (mSurfaceHolder != null && mSurface.isValid()) { 5536 usingAsyncReport = true; 5537 SurfaceCallbackHelper sch = new SurfaceCallbackHelper(() -> { 5538 handleSyncRequestWhenNoAsyncDraw(surfaceSyncGroup, pendingTransaction != null, 5539 pendingTransaction, "SurfaceHolder"); 5540 }); 5541 5542 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); 5543 5544 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks); 5545 } else if (!usingAsyncReport) { 5546 if (mAttachInfo.mThreadedRenderer != null) { 5547 mAttachInfo.mThreadedRenderer.fence(); 5548 } 5549 } 5550 } 5551 5552 if (!usingAsyncReport) { 5553 handleSyncRequestWhenNoAsyncDraw(surfaceSyncGroup, pendingTransaction != null, 5554 pendingTransaction, "no async report"); 5555 } 5556 5557 if (mPerformContentCapture) { 5558 performContentCaptureInitialReport(); 5559 } 5560 return true; 5561 } 5562 handleSyncRequestWhenNoAsyncDraw(SurfaceSyncGroup surfaceSyncGroup, boolean hasPendingTransaction, @Nullable Transaction pendingTransaction, String logReason)5563 private void handleSyncRequestWhenNoAsyncDraw(SurfaceSyncGroup surfaceSyncGroup, 5564 boolean hasPendingTransaction, @Nullable Transaction pendingTransaction, 5565 String logReason) { 5566 if (surfaceSyncGroup != null) { 5567 if (hasPendingTransaction && pendingTransaction != null) { 5568 surfaceSyncGroup.addTransaction(pendingTransaction); 5569 } 5570 surfaceSyncGroup.markSyncReady(); 5571 } else if (hasPendingTransaction && pendingTransaction != null) { 5572 Trace.instant(Trace.TRACE_TAG_VIEW, 5573 "Transaction not synced due to " + logReason + "-" + mTag); 5574 if (DEBUG_BLAST) { 5575 Log.d(mTag, "Pending transaction will not be applied in sync with a draw due to " 5576 + logReason); 5577 } 5578 // apply immediately with bbq apply token 5579 mergeWithNextTransaction(pendingTransaction, 0); 5580 } 5581 } 5582 /** 5583 * Checks (and caches) if content capture is enabled for this context. 5584 */ isContentCaptureEnabled()5585 private boolean isContentCaptureEnabled() { 5586 switch (mContentCaptureEnabled) { 5587 case CONTENT_CAPTURE_ENABLED_TRUE: 5588 return true; 5589 case CONTENT_CAPTURE_ENABLED_FALSE: 5590 return false; 5591 case CONTENT_CAPTURE_ENABLED_NOT_CHECKED: 5592 final boolean reallyEnabled = isContentCaptureReallyEnabled(); 5593 mContentCaptureEnabled = reallyEnabled ? CONTENT_CAPTURE_ENABLED_TRUE 5594 : CONTENT_CAPTURE_ENABLED_FALSE; 5595 return reallyEnabled; 5596 default: 5597 Log.w(TAG, "isContentCaptureEnabled(): invalid state " + mContentCaptureEnabled); 5598 return false; 5599 } 5600 5601 } 5602 5603 /** 5604 * Checks (without caching) if content capture is enabled for this context. 5605 */ isContentCaptureReallyEnabled()5606 private boolean isContentCaptureReallyEnabled() { 5607 // First check if context supports it, so it saves a service lookup when it doesn't 5608 if (mContext.getContentCaptureOptions() == null) return false; 5609 5610 final ContentCaptureManager ccm = mAttachInfo.getContentCaptureManager(mContext); 5611 // Then check if it's enabled in the contex itself. 5612 if (ccm == null || !ccm.isContentCaptureEnabled()) return false; 5613 5614 return true; 5615 } 5616 performContentCaptureInitialReport()5617 private void performContentCaptureInitialReport() { 5618 mPerformContentCapture = false; // One-time offer! 5619 final View rootView = mView; 5620 if (DEBUG_CONTENT_CAPTURE) { 5621 Log.v(mTag, "performContentCaptureInitialReport() on " + rootView); 5622 } 5623 boolean traceDispatchCapture = false; 5624 try { 5625 if (!isContentCaptureEnabled()) return; 5626 5627 traceDispatchCapture = Trace.isTagEnabled(Trace.TRACE_TAG_VIEW); 5628 if (traceDispatchCapture) { 5629 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchContentCapture() for " 5630 + getClass().getSimpleName()); 5631 } 5632 5633 // Initial dispatch of window bounds to content capture 5634 if (mAttachInfo.mContentCaptureManager != null) { 5635 ContentCaptureSession session = 5636 mAttachInfo.mContentCaptureManager.getMainContentCaptureSession(); 5637 session.notifyWindowBoundsChanged(session.getId(), 5638 getConfiguration().windowConfiguration.getBounds()); 5639 } 5640 5641 // Content capture is a go! 5642 rootView.dispatchInitialProvideContentCaptureStructure(); 5643 } finally { 5644 if (traceDispatchCapture) { 5645 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 5646 } 5647 } 5648 } 5649 handleContentCaptureFlush()5650 private void handleContentCaptureFlush() { 5651 if (DEBUG_CONTENT_CAPTURE) { 5652 Log.v(mTag, "handleContentCaptureFlush()"); 5653 } 5654 boolean traceFlushContentCapture = false; 5655 try { 5656 if (!isContentCaptureEnabled()) return; 5657 5658 traceFlushContentCapture = Trace.isTagEnabled(Trace.TRACE_TAG_VIEW); 5659 if (traceFlushContentCapture) { 5660 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "flushContentCapture for " 5661 + getClass().getSimpleName()); 5662 } 5663 5664 final ContentCaptureManager ccm = mAttachInfo.mContentCaptureManager; 5665 if (ccm == null) { 5666 Log.w(TAG, "No ContentCapture on AttachInfo"); 5667 return; 5668 } 5669 ccm.flush(ContentCaptureSession.FLUSH_REASON_VIEW_ROOT_ENTERED); 5670 } finally { 5671 if (traceFlushContentCapture) { 5672 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 5673 } 5674 } 5675 } 5676 draw(boolean fullRedrawNeeded, @Nullable SurfaceSyncGroup activeSyncGroup, boolean syncBuffer)5677 private boolean draw(boolean fullRedrawNeeded, @Nullable SurfaceSyncGroup activeSyncGroup, 5678 boolean syncBuffer) { 5679 Surface surface = mSurface; 5680 if (!surface.isValid()) { 5681 return false; 5682 } 5683 5684 if (DEBUG_FPS) { 5685 trackFPS(); 5686 } 5687 5688 if (sToolkitMetricsForFrameRateDecisionFlagValue) { 5689 collectFrameRateDecisionMetrics(); 5690 } 5691 5692 if (!sFirstDrawComplete) { 5693 synchronized (sFirstDrawHandlers) { 5694 sFirstDrawComplete = true; 5695 final int count = sFirstDrawHandlers.size(); 5696 for (int i = 0; i< count; i++) { 5697 mHandler.post(sFirstDrawHandlers.get(i)); 5698 } 5699 } 5700 } 5701 5702 scrollToRectOrFocus(null, false); 5703 5704 if (mAttachInfo.mViewScrollChanged) { 5705 mAttachInfo.mViewScrollChanged = false; 5706 mAttachInfo.mTreeObserver.dispatchOnScrollChanged(); 5707 } 5708 5709 boolean animating = mScroller != null && mScroller.computeScrollOffset(); 5710 final int curScrollY; 5711 if (animating) { 5712 curScrollY = mScroller.getCurrY(); 5713 } else { 5714 curScrollY = mScrollY; 5715 } 5716 if (mCurScrollY != curScrollY) { 5717 mCurScrollY = curScrollY; 5718 fullRedrawNeeded = true; 5719 if (mView instanceof RootViewSurfaceTaker) { 5720 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY); 5721 } 5722 } 5723 5724 final float appScale = mAttachInfo.mApplicationScale; 5725 final boolean scalingRequired = mAttachInfo.mScalingRequired; 5726 5727 final Rect dirty = mDirty; 5728 if (mSurfaceHolder != null) { 5729 // The app owns the surface, we won't draw. 5730 dirty.setEmpty(); 5731 if (animating && mScroller != null) { 5732 mScroller.abortAnimation(); 5733 } 5734 return false; 5735 } 5736 5737 if (fullRedrawNeeded) { 5738 dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f)); 5739 } 5740 5741 if (DEBUG_ORIENTATION || DEBUG_DRAW) { 5742 Log.v(mTag, "Draw " + mView + "/" 5743 + mWindowAttributes.getTitle() 5744 + ": dirty={" + dirty.left + "," + dirty.top 5745 + "," + dirty.right + "," + dirty.bottom + "} surface=" 5746 + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" + 5747 appScale + ", width=" + mWidth + ", height=" + mHeight); 5748 } 5749 5750 mAttachInfo.mTreeObserver.dispatchOnDraw(); 5751 5752 int xOffset = -mCanvasOffsetX; 5753 int yOffset = -mCanvasOffsetY + curScrollY; 5754 final WindowManager.LayoutParams params = mWindowAttributes; 5755 final Rect surfaceInsets = params != null ? params.surfaceInsets : null; 5756 if (surfaceInsets != null) { 5757 xOffset -= surfaceInsets.left; 5758 yOffset -= surfaceInsets.top; 5759 5760 // Offset dirty rect for surface insets. 5761 dirty.offset(surfaceInsets.left, surfaceInsets.top); 5762 } 5763 5764 boolean accessibilityFocusDirty = isAccessibilityFocusDirty(); 5765 5766 // Force recalculation of transparent regions 5767 if (accessibilityFocusDirty) { 5768 final Rect bounds = mAttachInfo.mTmpInvalRect; 5769 if (getAccessibilityFocusedRect(bounds)) { 5770 requestLayout(); 5771 } 5772 } 5773 5774 mAttachInfo.mDrawingTime = 5775 mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS; 5776 5777 boolean useAsyncReport = false; 5778 if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) { 5779 if (isHardwareEnabled()) { 5780 // If accessibility focus moved, always invalidate the root. 5781 boolean invalidateRoot = accessibilityFocusDirty || mInvalidateRootRequested; 5782 mInvalidateRootRequested = false; 5783 5784 // Draw with hardware renderer. 5785 mIsAnimating = false; 5786 5787 if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) { 5788 mHardwareYOffset = yOffset; 5789 mHardwareXOffset = xOffset; 5790 invalidateRoot = true; 5791 } 5792 5793 if (invalidateRoot) { 5794 mAttachInfo.mThreadedRenderer.invalidateRoot(); 5795 } 5796 5797 dirty.setEmpty(); 5798 5799 // Stage the content drawn size now. It will be transferred to the renderer 5800 // shortly before the draw commands get send to the renderer. 5801 final boolean updated = updateContentDrawBounds(); 5802 5803 if (mReportNextDraw) { 5804 // report next draw overrides setStopped() 5805 // This value is re-sync'd to the value of mStopped 5806 // in the handling of mReportNextDraw post-draw. 5807 mAttachInfo.mThreadedRenderer.setStopped(false); 5808 } 5809 5810 if (updated) { 5811 requestDrawWindow(); 5812 } 5813 5814 useAsyncReport = true; 5815 5816 if (mHdrRenderState.updateForFrame(mAttachInfo.mDrawingTime)) { 5817 final float renderRatio = mHdrRenderState.getRenderHdrSdrRatio(); 5818 applyTransactionOnDraw(mTransaction.setExtendedRangeBrightness( 5819 getSurfaceControl(), renderRatio, 5820 mHdrRenderState.getDesiredHdrSdrRatio())); 5821 mAttachInfo.mThreadedRenderer.setTargetHdrSdrRatio(renderRatio); 5822 } 5823 5824 if (activeSyncGroup != null) { 5825 registerCallbacksForSync(syncBuffer, activeSyncGroup); 5826 if (syncBuffer) { 5827 mAttachInfo.mThreadedRenderer.forceDrawNextFrame(); 5828 } 5829 } else if (mHasPendingTransactions) { 5830 // Register a callback if there's no sync involved but there were calls to 5831 // applyTransactionOnDraw. If there is a sync involved, the sync callback will 5832 // handle merging the pending transaction. 5833 registerCallbackForPendingTransactions(); 5834 } 5835 5836 long timeNs = SystemClock.uptimeNanos(); 5837 mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this); 5838 5839 // Only trigger once per {@link ViewRootImpl} instance. 5840 if (mAppStartInfoTimestampsFlagValue && mRenderThreadDrawStartTimeNs == -1) { 5841 mRenderThreadDrawStartTimeNs = timeNs; 5842 } 5843 } else { 5844 // If we get here with a disabled & requested hardware renderer, something went 5845 // wrong (an invalidate posted right before we destroyed the hardware surface 5846 // for instance) so we should just bail out. Locking the surface with software 5847 // rendering at this point would lock it forever and prevent hardware renderer 5848 // from doing its job when it comes back. 5849 // Before we request a new frame we must however attempt to reinitiliaze the 5850 // hardware renderer if it's in requested state. This would happen after an 5851 // eglTerminate() for instance. 5852 if (mAttachInfo.mThreadedRenderer != null && 5853 !mAttachInfo.mThreadedRenderer.isEnabled() && 5854 mAttachInfo.mThreadedRenderer.isRequested() && 5855 mSurface.isValid()) { 5856 5857 try { 5858 mAttachInfo.mThreadedRenderer.initializeIfNeeded( 5859 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets); 5860 } catch (OutOfResourcesException e) { 5861 handleOutOfResourcesException(e); 5862 return false; 5863 } 5864 5865 mFullRedrawNeeded = true; 5866 scheduleTraversals(); 5867 return false; 5868 } 5869 5870 if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, 5871 scalingRequired, dirty, surfaceInsets)) { 5872 return false; 5873 } 5874 } 5875 } 5876 5877 if (animating) { 5878 mFullRedrawNeeded = true; 5879 scheduleTraversals(); 5880 } 5881 return useAsyncReport; 5882 } 5883 5884 /** 5885 * @return true if drawing was successful, false if an error occurred 5886 */ drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, boolean scalingRequired, Rect dirty, Rect surfaceInsets)5887 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, 5888 boolean scalingRequired, Rect dirty, Rect surfaceInsets) { 5889 5890 // Draw with software renderer. 5891 final Canvas canvas; 5892 5893 try { 5894 canvas = mSurface.lockCanvas(dirty); 5895 canvas.setDensity(mDensity); 5896 } catch (Surface.OutOfResourcesException e) { 5897 handleOutOfResourcesException(e); 5898 return false; 5899 } catch (IllegalArgumentException e) { 5900 Log.e(mTag, "Could not lock surface", e); 5901 // Don't assume this is due to out of memory, it could be 5902 // something else, and if it is something else then we could 5903 // kill stuff (or ourself) for no reason. 5904 mLayoutRequested = true; // ask wm for a new surface next time. 5905 return false; 5906 } 5907 5908 try { 5909 if (DEBUG_ORIENTATION || DEBUG_DRAW) { 5910 Log.v(mTag, "Surface " + surface + " drawing to bitmap w=" 5911 + canvas.getWidth() + ", h=" + canvas.getHeight() + ", dirty: " + dirty 5912 + ", xOff=" + xoff + ", yOff=" + yoff); 5913 //canvas.drawARGB(255, 255, 0, 0); 5914 } 5915 5916 // If this bitmap's format includes an alpha channel, we 5917 // need to clear it before drawing so that the child will 5918 // properly re-composite its drawing on a transparent 5919 // background. This automatically respects the clip/dirty region 5920 // or 5921 // If we are applying an offset, we need to clear the area 5922 // where the offset doesn't appear to avoid having garbage 5923 // left in the blank areas. 5924 if (!canvas.isOpaque() || yoff != 0 || xoff != 0) { 5925 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 5926 } 5927 5928 dirty.setEmpty(); 5929 mIsAnimating = false; 5930 mView.mPrivateFlags |= View.PFLAG_DRAWN; 5931 5932 if (DEBUG_DRAW) { 5933 Context cxt = mView.getContext(); 5934 Log.i(mTag, "Drawing: package:" + cxt.getPackageName() + 5935 ", metrics=" + cxt.getResources().getDisplayMetrics() + 5936 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo()); 5937 } 5938 canvas.translate(-xoff, -yoff); 5939 if (mTranslator != null) { 5940 mTranslator.translateCanvas(canvas); 5941 } 5942 canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0); 5943 5944 mView.draw(canvas); 5945 5946 drawAccessibilityFocusedDrawableIfNeeded(canvas); 5947 } finally { 5948 try { 5949 surface.unlockCanvasAndPost(canvas); 5950 } catch (IllegalArgumentException e) { 5951 Log.e(mTag, "Could not unlock surface", e); 5952 mLayoutRequested = true; // ask wm for a new surface next time. 5953 //noinspection ReturnInsideFinallyBlock 5954 return false; 5955 } 5956 5957 if (LOCAL_LOGV) { 5958 Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost"); 5959 } 5960 } 5961 return true; 5962 } 5963 5964 /** 5965 * We want to draw a highlight around the current accessibility focused. 5966 * Since adding a style for all possible view is not a viable option we 5967 * have this specialized drawing method. 5968 * 5969 * Note: We are doing this here to be able to draw the highlight for 5970 * virtual views in addition to real ones. 5971 * 5972 * Note: A round accessibility focus border is drawn on rounded watch 5973 * 5974 * Note: Need to set bounds of accessibility focused drawable before drawing on rounded watch, 5975 * so that when accessibility focus moved, root will be invalidated at 5976 * {@link #draw(boolean, SurfaceSyncGroup, boolean)} and accessibility focus border will be 5977 * updated. 5978 * 5979 * @param canvas The canvas on which to draw. 5980 */ drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas)5981 private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) { 5982 final Rect bounds = mAttachInfo.mTmpInvalRect; 5983 if (getAccessibilityFocusedRect(bounds)) { 5984 boolean isRoundWatch = mContext.getResources().getConfiguration().isScreenRound() 5985 && mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH); 5986 final Drawable drawable = getAccessibilityFocusedDrawable(); 5987 if (drawable != null) { 5988 drawable.setBounds(bounds); 5989 drawable.draw(canvas); 5990 if (mDisplay != null && isRoundWatch) { 5991 // Draw an extra round accessibility focus border on round watch 5992 drawAccessibilityFocusedBorderOnRoundDisplay(canvas, bounds, 5993 getRoundDisplayRadius(), getRoundDisplayAccessibilityHighlightPaint()); 5994 } 5995 } 5996 } else if (mAttachInfo.mAccessibilityFocusDrawable != null) { 5997 mAttachInfo.mAccessibilityFocusDrawable.setBounds(0, 0, 0, 0); 5998 } 5999 } 6000 getRoundDisplayRadius()6001 private int getRoundDisplayRadius() { 6002 Point displaySize = new Point(); 6003 mDisplay.getRealSize(displaySize); 6004 return displaySize.x / 2; 6005 } 6006 getRoundDisplayAccessibilityHighlightPaint()6007 private Paint getRoundDisplayAccessibilityHighlightPaint() { 6008 // Lazily create the round display accessibility highlight paint. 6009 if (mRoundDisplayAccessibilityHighlightPaint == null) { 6010 mRoundDisplayAccessibilityHighlightPaint = new Paint(); 6011 mRoundDisplayAccessibilityHighlightPaint.setStyle(Paint.Style.STROKE); 6012 mRoundDisplayAccessibilityHighlightPaint.setAntiAlias(true); 6013 } 6014 mRoundDisplayAccessibilityHighlightPaint.setStrokeWidth( 6015 mAccessibilityManager.getAccessibilityFocusStrokeWidth()); 6016 mRoundDisplayAccessibilityHighlightPaint.setColor( 6017 mAccessibilityManager.getAccessibilityFocusColor()); 6018 return mRoundDisplayAccessibilityHighlightPaint; 6019 } 6020 drawAccessibilityFocusedBorderOnRoundDisplay(Canvas canvas, Rect bounds, int roundDisplayRadius, Paint accessibilityFocusHighlightPaint)6021 private void drawAccessibilityFocusedBorderOnRoundDisplay(Canvas canvas, Rect bounds, 6022 int roundDisplayRadius, Paint accessibilityFocusHighlightPaint) { 6023 int saveCount = canvas.save(); 6024 canvas.clipRect(bounds); 6025 canvas.drawCircle(/* cx= */ roundDisplayRadius, 6026 /* cy= */ roundDisplayRadius, 6027 /* radius= */ roundDisplayRadius 6028 - mAccessibilityManager.getAccessibilityFocusStrokeWidth() / 2.0f, 6029 accessibilityFocusHighlightPaint); 6030 canvas.restoreToCount(saveCount); 6031 } 6032 getAccessibilityFocusedRect(Rect bounds)6033 private boolean getAccessibilityFocusedRect(Rect bounds) { 6034 if (mView == null) { 6035 Slog.w(TAG, "calling getAccessibilityFocusedRect() while the mView is null"); 6036 return false; 6037 } 6038 if (!mAccessibilityManager.isEnabled() 6039 || !mAccessibilityManager.isTouchExplorationEnabled()) { 6040 return false; 6041 } 6042 6043 final View host = mAccessibilityFocusedHost; 6044 if (host == null || host.mAttachInfo == null) { 6045 return false; 6046 } 6047 6048 final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider(); 6049 if (provider == null) { 6050 host.getBoundsOnScreen(bounds, true); 6051 } else if (mAccessibilityFocusedVirtualView != null) { 6052 mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds); 6053 } else { 6054 return false; 6055 } 6056 6057 // Transform the rect into window-relative coordinates. 6058 final AttachInfo attachInfo = mAttachInfo; 6059 bounds.offset(0, attachInfo.mViewRootImpl.mScrollY); 6060 bounds.offset(-attachInfo.mWindowLeft, -attachInfo.mWindowTop); 6061 if (!bounds.intersect(0, 0, attachInfo.mViewRootImpl.mWidth, 6062 attachInfo.mViewRootImpl.mHeight)) { 6063 // If no intersection, set bounds to empty. 6064 bounds.setEmpty(); 6065 } 6066 6067 if (bounds.isEmpty()) { 6068 return false; 6069 } 6070 6071 if (android.view.accessibility.Flags.focusRectMinSize()) { 6072 adjustAccessibilityFocusedRectBoundsIfNeeded(bounds); 6073 } 6074 6075 return true; 6076 } 6077 6078 /** 6079 * Adjusts accessibility focused rect bounds so that they are not invisible. 6080 * 6081 * <p>Focus bounds smaller than double the stroke width are very hard to see (or invisible). 6082 * Expand the focus bounds if necessary to at least double the stroke width. 6083 * @param bounds The bounds to adjust 6084 */ 6085 @VisibleForTesting adjustAccessibilityFocusedRectBoundsIfNeeded(Rect bounds)6086 public void adjustAccessibilityFocusedRectBoundsIfNeeded(Rect bounds) { 6087 final int minRectLength = mAccessibilityManager.getAccessibilityFocusStrokeWidth() * 2; 6088 if (bounds.width() < minRectLength || bounds.height() < minRectLength) { 6089 final float missingWidth = Math.max(0, minRectLength - bounds.width()); 6090 final float missingHeight = Math.max(0, minRectLength - bounds.height()); 6091 bounds.inset(-1 * (int) Math.ceil(missingWidth / 2), 6092 -1 * (int) Math.ceil(missingHeight / 2)); 6093 } 6094 } 6095 getAccessibilityFocusedDrawable()6096 private Drawable getAccessibilityFocusedDrawable() { 6097 // Lazily load the accessibility focus drawable. 6098 if (mAttachInfo.mAccessibilityFocusDrawable == null) { 6099 final TypedValue value = new TypedValue(); 6100 final boolean resolved = mView.mContext.getTheme().resolveAttribute( 6101 R.attr.accessibilityFocusedDrawable, value, true); 6102 if (resolved) { 6103 mAttachInfo.mAccessibilityFocusDrawable = 6104 mView.mContext.getDrawable(value.resourceId); 6105 } 6106 } 6107 // Sets the focus appearance data into the accessibility focus drawable. 6108 if (mAttachInfo.mAccessibilityFocusDrawable instanceof GradientDrawable) { 6109 final GradientDrawable drawable = 6110 (GradientDrawable) mAttachInfo.mAccessibilityFocusDrawable; 6111 drawable.setStroke(mAccessibilityManager.getAccessibilityFocusStrokeWidth(), 6112 mAccessibilityManager.getAccessibilityFocusColor()); 6113 } 6114 6115 return mAttachInfo.mAccessibilityFocusDrawable; 6116 } 6117 updateSystemGestureExclusionRectsForView(View view)6118 void updateSystemGestureExclusionRectsForView(View view) { 6119 boolean msgInQueue = reduceChangedExclusionRectsMsgs() 6120 && mGestureExclusionTracker.isWaitingForComputeChanges(); 6121 mGestureExclusionTracker.updateRectsForView(view); 6122 if (!msgInQueue) { 6123 mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED); 6124 } 6125 } 6126 systemGestureExclusionChanged()6127 void systemGestureExclusionChanged() { 6128 final List<Rect> rectsForWindowManager = mGestureExclusionTracker.computeChangedRects(); 6129 if (rectsForWindowManager != null && mView != null) { 6130 try { 6131 mWindowSession.reportSystemGestureExclusionChanged(mWindow, rectsForWindowManager); 6132 } catch (RemoteException e) { 6133 throw e.rethrowFromSystemServer(); 6134 } 6135 mAttachInfo.mTreeObserver 6136 .dispatchOnSystemGestureExclusionRectsChanged(rectsForWindowManager); 6137 } 6138 } 6139 6140 /** 6141 * Called from DecorView when gesture interception state has changed. 6142 * 6143 * @param intercepted If DecorView is intercepting touch events 6144 */ updateDecorViewGestureInterception(boolean intercepted)6145 public void updateDecorViewGestureInterception(boolean intercepted) { 6146 mHandler.sendMessage( 6147 mHandler.obtainMessage( 6148 MSG_DECOR_VIEW_GESTURE_INTERCEPTION, 6149 /* arg1= */ intercepted ? 1 : 0, 6150 /* arg2= */ 0)); 6151 } 6152 decorViewInterceptionChanged(boolean intercepted)6153 void decorViewInterceptionChanged(boolean intercepted) { 6154 if (mView != null) { 6155 try { 6156 mWindowSession.reportDecorViewGestureInterceptionChanged(mWindow, intercepted); 6157 } catch (RemoteException e) { 6158 throw e.rethrowFromSystemServer(); 6159 } 6160 } 6161 } 6162 6163 /** 6164 * Set the root-level system gesture exclusion rects. These are added to those provided by 6165 * the root's view hierarchy. 6166 */ setRootSystemGestureExclusionRects(@onNull List<Rect> rects)6167 public void setRootSystemGestureExclusionRects(@NonNull List<Rect> rects) { 6168 boolean msgInQueue = reduceChangedExclusionRectsMsgs() 6169 && mGestureExclusionTracker.isWaitingForComputeChanges(); 6170 mGestureExclusionTracker.setRootRects(rects); 6171 if (!msgInQueue) { 6172 mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED); 6173 } 6174 } 6175 6176 /** 6177 * Returns the root-level system gesture exclusion rects. These do not include those provided by 6178 * the root's view hierarchy. 6179 */ 6180 @NonNull getRootSystemGestureExclusionRects()6181 public List<Rect> getRootSystemGestureExclusionRects() { 6182 return mGestureExclusionTracker.getRootRects(); 6183 } 6184 6185 /** 6186 * Called from View when the position listener is triggered 6187 */ updateKeepClearRectsForView(View view)6188 void updateKeepClearRectsForView(View view) { 6189 mKeepClearRectsTracker.updateRectsForView(view); 6190 mUnrestrictedKeepClearRectsTracker.updateRectsForView(view); 6191 mHandler.sendEmptyMessage(MSG_KEEP_CLEAR_RECTS_CHANGED); 6192 } 6193 updateKeepClearForAccessibilityFocusRect()6194 private void updateKeepClearForAccessibilityFocusRect() { 6195 if (mViewConfiguration.isPreferKeepClearForFocusEnabled()) { 6196 if (mKeepClearAccessibilityFocusRect == null) { 6197 mKeepClearAccessibilityFocusRect = new Rect(); 6198 } 6199 boolean hasAccessibilityFocus = 6200 getAccessibilityFocusedRect(mKeepClearAccessibilityFocusRect); 6201 if (!hasAccessibilityFocus) { 6202 mKeepClearAccessibilityFocusRect.setEmpty(); 6203 } 6204 mHandler.obtainMessage(MSG_KEEP_CLEAR_RECTS_CHANGED, 1, 0).sendToTarget(); 6205 } 6206 } 6207 keepClearRectsChanged(boolean accessibilityFocusRectChanged)6208 void keepClearRectsChanged(boolean accessibilityFocusRectChanged) { 6209 boolean restrictedKeepClearRectsChanged = mKeepClearRectsTracker.computeChanges(); 6210 boolean unrestrictedKeepClearRectsChanged = 6211 mUnrestrictedKeepClearRectsTracker.computeChanges(); 6212 6213 if ((restrictedKeepClearRectsChanged || unrestrictedKeepClearRectsChanged 6214 || accessibilityFocusRectChanged) && mView != null) { 6215 mHasPendingKeepClearAreaChange = true; 6216 // Only report keep clear areas immediately if they have not been reported recently 6217 if (!mHandler.hasMessages(MSG_REPORT_KEEP_CLEAR_RECTS)) { 6218 mHandler.sendEmptyMessageDelayed(MSG_REPORT_KEEP_CLEAR_RECTS, 6219 KEEP_CLEAR_AREA_REPORT_RATE_MILLIS); 6220 reportKeepClearAreasChanged(); 6221 } 6222 } 6223 } 6224 reportKeepClearAreasChanged()6225 void reportKeepClearAreasChanged() { 6226 if (!mHasPendingKeepClearAreaChange || mView == null) { 6227 return; 6228 } 6229 mHasPendingKeepClearAreaChange = false; 6230 6231 List<Rect> restrictedKeepClearRects = mKeepClearRectsTracker.getLastComputedRects(); 6232 final List<Rect> unrestrictedKeepClearRects = 6233 mUnrestrictedKeepClearRectsTracker.getLastComputedRects(); 6234 6235 if (mKeepClearAccessibilityFocusRect != null 6236 && !mKeepClearAccessibilityFocusRect.isEmpty()) { 6237 restrictedKeepClearRects = new ArrayList<>(restrictedKeepClearRects); 6238 restrictedKeepClearRects.add(mKeepClearAccessibilityFocusRect); 6239 } 6240 6241 try { 6242 mWindowSession.reportKeepClearAreasChanged(mWindow, restrictedKeepClearRects, 6243 unrestrictedKeepClearRects); 6244 } catch (RemoteException e) { 6245 throw e.rethrowFromSystemServer(); 6246 } 6247 } 6248 6249 /** 6250 * Requests that the root render node is invalidated next time we perform a draw, such that 6251 * {@link WindowCallbacks#onPostDraw} gets called. 6252 */ requestInvalidateRootRenderNode()6253 public void requestInvalidateRootRenderNode() { 6254 mInvalidateRootRequested = true; 6255 } 6256 scrollToRectOrFocus(Rect rectangle, boolean immediate)6257 boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) { 6258 if (mImeBackAnimationController.isAnimationInProgress()) { 6259 // IME predictive back animation is currently in progress which means that scrollY is 6260 // currently controlled by ImeBackAnimationController. 6261 return false; 6262 } 6263 6264 final Rect ci = mAttachInfo.mContentInsets; 6265 final Rect vi = mAttachInfo.mVisibleInsets; 6266 int scrollY = 0; 6267 boolean handled = false; 6268 6269 if (vi.left > ci.left || vi.top > ci.top 6270 || vi.right > ci.right || vi.bottom > ci.bottom) { 6271 // We'll assume that we aren't going to change the scroll 6272 // offset, since we want to avoid that unless it is actually 6273 // going to make the focus visible... otherwise we scroll 6274 // all over the place. 6275 scrollY = mScrollY; 6276 // We can be called for two different situations: during a draw, 6277 // to update the scroll position if the focus has changed (in which 6278 // case 'rectangle' is null), or in response to a 6279 // requestChildRectangleOnScreen() call (in which case 'rectangle' 6280 // is non-null and we just want to scroll to whatever that 6281 // rectangle is). 6282 final View focus = mView.findFocus(); 6283 if (focus == null) { 6284 return false; 6285 } 6286 View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null; 6287 if (focus != lastScrolledFocus) { 6288 // If the focus has changed, then ignore any requests to scroll 6289 // to a rectangle; first we want to make sure the entire focus 6290 // view is visible. 6291 rectangle = null; 6292 } 6293 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Eval scroll: focus=" + focus 6294 + " rectangle=" + rectangle + " ci=" + ci 6295 + " vi=" + vi); 6296 if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) { 6297 // Optimization: if the focus hasn't changed since last 6298 // time, and no layout has happened, then just leave things 6299 // as they are. 6300 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Keeping scroll y=" 6301 + mScrollY + " vi=" + vi.toShortString()); 6302 } else { 6303 // We need to determine if the currently focused view is 6304 // within the visible part of the window and, if not, apply 6305 // a pan so it can be seen. 6306 mLastScrolledFocus = new WeakReference<View>(focus); 6307 mScrollMayChange = false; 6308 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Need to scroll?"); 6309 // Try to find the rectangle from the focus view. 6310 if (focus.getGlobalVisibleRect(mVisRect, null)) { 6311 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Root w=" 6312 + mView.getWidth() + " h=" + mView.getHeight() 6313 + " ci=" + ci.toShortString() 6314 + " vi=" + vi.toShortString()); 6315 if (rectangle == null) { 6316 focus.getFocusedRect(mTempRect); 6317 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Focus " + focus 6318 + ": focusRect=" + mTempRect.toShortString()); 6319 if (mView instanceof ViewGroup) { 6320 ((ViewGroup) mView).offsetDescendantRectToMyCoords( 6321 focus, mTempRect); 6322 } 6323 if (DEBUG_INPUT_RESIZE) Log.v(mTag, 6324 "Focus in window: focusRect=" 6325 + mTempRect.toShortString() 6326 + " visRect=" + mVisRect.toShortString()); 6327 } else { 6328 mTempRect.set(rectangle); 6329 if (DEBUG_INPUT_RESIZE) Log.v(mTag, 6330 "Request scroll to rect: " 6331 + mTempRect.toShortString() 6332 + " visRect=" + mVisRect.toShortString()); 6333 } 6334 if (mTempRect.intersect(mVisRect)) { 6335 if (DEBUG_INPUT_RESIZE) Log.v(mTag, 6336 "Focus window visible rect: " 6337 + mTempRect.toShortString()); 6338 if (mTempRect.height() > 6339 (mView.getHeight()-vi.top-vi.bottom)) { 6340 // If the focus simply is not going to fit, then 6341 // best is probably just to leave things as-is. 6342 if (DEBUG_INPUT_RESIZE) Log.v(mTag, 6343 "Too tall; leaving scrollY=" + scrollY); 6344 } 6345 // Next, check whether top or bottom is covered based on the non-scrolled 6346 // position, and calculate new scrollY (or set it to 0). 6347 // We can't keep using mScrollY here. For example mScrollY is non-zero 6348 // due to IME, then IME goes away. The current value of mScrollY leaves top 6349 // and bottom both visible, but we still need to scroll it back to 0. 6350 else if (mTempRect.top < vi.top) { 6351 scrollY = mTempRect.top - vi.top; 6352 if (DEBUG_INPUT_RESIZE) Log.v(mTag, 6353 "Top covered; scrollY=" + scrollY); 6354 } else if (mTempRect.bottom > (mView.getHeight()-vi.bottom)) { 6355 scrollY = mTempRect.bottom - (mView.getHeight()-vi.bottom); 6356 if (DEBUG_INPUT_RESIZE) Log.v(mTag, 6357 "Bottom covered; scrollY=" + scrollY); 6358 } else { 6359 scrollY = 0; 6360 } 6361 handled = true; 6362 } 6363 } 6364 } 6365 } 6366 6367 if (scrollY != mScrollY) { 6368 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Pan scroll changed: old=" 6369 + mScrollY + " , new=" + scrollY); 6370 if (!immediate) { 6371 if (mScroller == null) { 6372 mScroller = new Scroller(mView.getContext()); 6373 } 6374 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY); 6375 } else if (mScroller != null) { 6376 mScroller.abortAnimation(); 6377 } 6378 mScrollY = scrollY; 6379 } 6380 6381 return handled; 6382 } 6383 6384 @VisibleForTesting(visibility = PACKAGE) setScrollY(int scrollY)6385 public void setScrollY(int scrollY) { 6386 if (mScroller != null) { 6387 mScroller.abortAnimation(); 6388 } 6389 mScrollY = scrollY; 6390 } 6391 6392 @VisibleForTesting getScrollY()6393 public int getScrollY() { 6394 return mScrollY; 6395 } 6396 6397 /** 6398 * @hide 6399 */ 6400 @UnsupportedAppUsage getAccessibilityFocusedHost()6401 public View getAccessibilityFocusedHost() { 6402 return mAccessibilityFocusedHost; 6403 } 6404 6405 /** 6406 * Get accessibility-focused virtual view. The bounds and sourceNodeId of the returned node is 6407 * up-to-date while other fields may be stale. 6408 * 6409 * @hide 6410 */ 6411 @UnsupportedAppUsage getAccessibilityFocusedVirtualView()6412 public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() { 6413 return mAccessibilityFocusedVirtualView; 6414 } 6415 setAccessibilityFocus(View view, AccessibilityNodeInfo node)6416 void setAccessibilityFocus(View view, AccessibilityNodeInfo node) { 6417 // If we have a virtual view with accessibility focus we need 6418 // to clear the focus and invalidate the virtual view bounds. 6419 if (mAccessibilityFocusedVirtualView != null) { 6420 6421 AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView; 6422 View focusHost = mAccessibilityFocusedHost; 6423 6424 // Wipe the state of the current accessibility focus since 6425 // the call into the provider to clear accessibility focus 6426 // will fire an accessibility event which will end up calling 6427 // this method and we want to have clean state when this 6428 // invocation happens. 6429 mAccessibilityFocusedHost = null; 6430 mAccessibilityFocusedVirtualView = null; 6431 6432 // Clear accessibility focus on the host after clearing state since 6433 // this method may be reentrant. 6434 focusHost.clearAccessibilityFocusNoCallbacks( 6435 AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 6436 6437 AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider(); 6438 if (provider != null) { 6439 // Invalidate the area of the cleared accessibility focus. 6440 focusNode.getBoundsInParent(mTempRect); 6441 focusHost.invalidate(mTempRect); 6442 // Clear accessibility focus in the virtual node. 6443 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId( 6444 focusNode.getSourceNodeId()); 6445 provider.performAction(virtualNodeId, 6446 AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null); 6447 } 6448 focusNode.recycle(); 6449 } 6450 if ((mAccessibilityFocusedHost != null) && (mAccessibilityFocusedHost != view)) { 6451 // Clear accessibility focus in the view. 6452 mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks( 6453 AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 6454 } 6455 6456 // Set the new focus host and node. 6457 mAccessibilityFocusedHost = view; 6458 mAccessibilityFocusedVirtualView = node; 6459 updateKeepClearForAccessibilityFocusRect(); 6460 6461 requestInvalidateRootRenderNode(); 6462 if (isAccessibilityFocusDirty()) { 6463 scheduleTraversals(); 6464 } 6465 } 6466 hasPointerCapture()6467 boolean hasPointerCapture() { 6468 return mPointerCapture; 6469 } 6470 requestPointerCapture(boolean enabled)6471 void requestPointerCapture(boolean enabled) { 6472 final IBinder inputToken = getInputToken(); 6473 if (inputToken == null) { 6474 Log.e(mTag, "No input channel to request Pointer Capture."); 6475 return; 6476 } 6477 InputManagerGlobal 6478 .getInstance() 6479 .requestPointerCapture(inputToken, enabled); 6480 } 6481 handlePointerCaptureChanged(boolean hasCapture)6482 private void handlePointerCaptureChanged(boolean hasCapture) { 6483 if (mPointerCapture == hasCapture) { 6484 return; 6485 } 6486 mPointerCapture = hasCapture; 6487 if (mView != null) { 6488 mView.dispatchPointerCaptureChanged(hasCapture); 6489 } 6490 } 6491 updateColorModeIfNeeded(@ctivityInfo.ColorMode int colorMode, float desiredRatio)6492 private void updateColorModeIfNeeded(@ActivityInfo.ColorMode int colorMode, 6493 float desiredRatio) { 6494 if (mAttachInfo.mThreadedRenderer == null) { 6495 return; 6496 } 6497 6498 boolean isHdr = colorMode == ActivityInfo.COLOR_MODE_HDR 6499 || colorMode == ActivityInfo.COLOR_MODE_HDR10; 6500 if (isHdr && !mDisplay.isHdrSdrRatioAvailable()) { 6501 colorMode = ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT; 6502 isHdr = false; 6503 } 6504 // TODO: Centralize this sanitization? Why do we let setting bad modes? 6505 // Alternatively, can we just let HWUI figure it out? Do we need to care here? 6506 if (colorMode != ActivityInfo.COLOR_MODE_A8 6507 && !getConfiguration().isScreenWideColorGamut()) { 6508 colorMode = ActivityInfo.COLOR_MODE_DEFAULT; 6509 } 6510 6511 logColorMode(colorMode, false); 6512 6513 float automaticRatio = mAttachInfo.mThreadedRenderer.setColorMode(colorMode); 6514 if (desiredRatio == 0 || desiredRatio > automaticRatio) { 6515 desiredRatio = automaticRatio; 6516 } 6517 6518 mHdrRenderState.setDesiredHdrSdrRatio(isHdr, desiredRatio); 6519 } 6520 6521 @Override requestChildFocus(View child, View focused)6522 public void requestChildFocus(View child, View focused) { 6523 if (DEBUG_INPUT_RESIZE) { 6524 Log.v(mTag, "Request child focus: focus now " + focused); 6525 } 6526 checkThread(); 6527 scheduleTraversals(); 6528 } 6529 6530 @Override clearChildFocus(View child)6531 public void clearChildFocus(View child) { 6532 if (DEBUG_INPUT_RESIZE) { 6533 Log.v(mTag, "Clearing child focus"); 6534 } 6535 checkThread(); 6536 scheduleTraversals(); 6537 } 6538 6539 @Override getParentForAccessibility()6540 public ViewParent getParentForAccessibility() { 6541 return null; 6542 } 6543 6544 @Override focusableViewAvailable(View v)6545 public void focusableViewAvailable(View v) { 6546 checkThread(); 6547 if (mView != null) { 6548 if (!mView.hasFocus()) { 6549 if (sAlwaysAssignFocus || !mAttachInfo.mInTouchMode) { 6550 v.requestFocus(); 6551 } 6552 } else { 6553 // the one case where will transfer focus away from the current one 6554 // is if the current view is a view group that prefers to give focus 6555 // to its children first AND the view is a descendant of it. 6556 View focused = mView.findFocus(); 6557 if (focused instanceof ViewGroup) { 6558 ViewGroup group = (ViewGroup) focused; 6559 if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS 6560 && isViewDescendantOf(v, focused)) { 6561 v.requestFocus(); 6562 } 6563 } 6564 } 6565 } 6566 } 6567 6568 @Override recomputeViewAttributes(View child)6569 public void recomputeViewAttributes(View child) { 6570 checkThread(); 6571 if (mView == child) { 6572 mAttachInfo.mRecomputeGlobalAttributes = true; 6573 if (!mWillDrawSoon) { 6574 scheduleTraversals(); 6575 } 6576 } 6577 } 6578 dispatchDetachedFromWindow()6579 void dispatchDetachedFromWindow() { 6580 // Make sure we free-up insets resources if view never received onWindowFocusLost() 6581 // because of a die-signal 6582 mInsetsController.onWindowFocusLost(); 6583 mFirstInputStage.onDetachedFromWindow(); 6584 if (mView != null && mView.mAttachInfo != null) { 6585 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false); 6586 mView.dispatchDetachedFromWindow(); 6587 } 6588 6589 mAccessibilityInteractionConnectionManager.ensureNoConnection(); 6590 mAccessibilityInteractionConnectionManager.ensureNoDirectConnection(); 6591 removeSendWindowContentChangedCallback(); 6592 if (android.view.accessibility.Flags.preventLeakingViewrootimpl() 6593 && mAccessibilityInteractionController != null) { 6594 mAccessibilityInteractionController.destroy(); 6595 mAccessibilityInteractionController = null; 6596 } 6597 6598 destroyHardwareRenderer(); 6599 6600 setAccessibilityFocus(null, null); 6601 6602 mInsetsController.cancelExistingAnimations(); 6603 6604 mView.assignParent(null); 6605 mView = null; 6606 mAttachInfo.mRootView = null; 6607 6608 destroySurface(); 6609 6610 if (mInputQueueCallback != null && mInputQueue != null) { 6611 mInputQueueCallback.onInputQueueDestroyed(mInputQueue); 6612 mInputQueue.dispose(); 6613 mInputQueueCallback = null; 6614 mInputQueue = null; 6615 } 6616 try { 6617 mWindowSession.remove(mWindow.asBinder()); 6618 } catch (RemoteException e) { 6619 } 6620 // Dispose receiver would dispose client InputChannel, too. That could send out a socket 6621 // broken event, so we need to unregister the server InputChannel when removing window to 6622 // prevent server side receive the event and prompt error. 6623 if (mInputEventReceiver != null) { 6624 mInputEventReceiver.dispose(); 6625 mInputEventReceiver = null; 6626 } 6627 6628 unregisterListeners(); 6629 unscheduleTraversals(); 6630 } 6631 6632 /** 6633 * Notifies all callbacks that configuration and/or display has changed and updates internal 6634 * state. 6635 * @param mergedConfiguration New global and override config in {@link MergedConfiguration} 6636 * container. 6637 * @param force Flag indicating if we should force apply the config. 6638 * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} if not 6639 * changed. 6640 * @param activityWindowInfo New activity window info. {@code null} if it is non-app window, or 6641 * this is not a Configuration change to the activity window (global). 6642 */ performConfigurationChange(@onNull MergedConfiguration mergedConfiguration, boolean force, int newDisplayId, @Nullable ActivityWindowInfo activityWindowInfo)6643 private void performConfigurationChange(@NonNull MergedConfiguration mergedConfiguration, 6644 boolean force, int newDisplayId, @Nullable ActivityWindowInfo activityWindowInfo) { 6645 if (mergedConfiguration == null) { 6646 throw new IllegalArgumentException("No merged config provided."); 6647 } 6648 6649 final int lastRotation = mLastReportedMergedConfiguration.getMergedConfiguration() 6650 .windowConfiguration.getRotation(); 6651 final int newRotation = mergedConfiguration.getMergedConfiguration() 6652 .windowConfiguration.getRotation(); 6653 if (lastRotation != newRotation) { 6654 // Trigger ThreadedRenderer#updateSurface() if the surface control doesn't change. 6655 // Because even if the actual surface size is not changed, e.g. flip 180 degrees, 6656 // the buffers may still have content in previous rotation. And the next draw may 6657 // not update all regions, that causes some afterimages to flicker. 6658 mUpdateSurfaceNeeded = true; 6659 if (!mIsInTraversal) { 6660 mForceNextWindowRelayout = true; 6661 } 6662 } 6663 6664 Configuration globalConfig = mergedConfiguration.getGlobalConfiguration(); 6665 Configuration overrideConfig = mergedConfiguration.getOverrideConfiguration(); 6666 if (DEBUG_CONFIGURATION) Log.v(mTag, 6667 "Applying new config to window " + mWindowAttributes.getTitle() 6668 + ", globalConfig: " + globalConfig 6669 + ", overrideConfig: " + overrideConfig); 6670 6671 final CompatibilityInfo ci = mDisplay.getDisplayAdjustments().getCompatibilityInfo(); 6672 if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) { 6673 globalConfig = new Configuration(globalConfig); 6674 overrideConfig = new Configuration(overrideConfig); 6675 ci.applyToConfiguration(mNoncompatDensity, globalConfig); 6676 ci.applyToConfiguration(mNoncompatDensity, overrideConfig); 6677 } 6678 6679 synchronized (sConfigCallbacks) { 6680 for (int i=sConfigCallbacks.size()-1; i>=0; i--) { 6681 sConfigCallbacks.get(i).onConfigurationChanged(globalConfig); 6682 } 6683 } 6684 6685 mLastReportedMergedConfiguration.setConfiguration(globalConfig, overrideConfig); 6686 if (mLastReportedActivityWindowInfo != null && activityWindowInfo != null) { 6687 mLastReportedActivityWindowInfo.set(activityWindowInfo); 6688 } 6689 6690 mForceNextConfigUpdate = force; 6691 if (mActivityConfigCallback != null) { 6692 // An activity callback is set - notify it about override configuration update. 6693 // This basically initiates a round trip to ActivityThread and back, which will ensure 6694 // that corresponding activity and resources are updated before updating inner state of 6695 // ViewRootImpl. Eventually it will call #updateConfiguration(). 6696 mActivityConfigCallback.onConfigurationChanged(overrideConfig, newDisplayId, 6697 activityWindowInfo); 6698 } else { 6699 if (enableWindowContextResourcesUpdateOnConfigChange()) { 6700 // There is no activity callback - update resources for window token, if needed. 6701 final IBinder windowContextToken = mContext.getWindowContextToken(); 6702 if (windowContextToken instanceof WindowTokenClient) { 6703 WindowTokenClientController.getInstance().onWindowConfigurationChanged( 6704 windowContextToken, 6705 mLastReportedMergedConfiguration.getMergedConfiguration(), 6706 newDisplayId == INVALID_DISPLAY 6707 ? mDisplay.getDisplayId() 6708 : newDisplayId 6709 ); 6710 } 6711 } 6712 updateConfiguration(newDisplayId); 6713 } 6714 mForceNextConfigUpdate = false; 6715 } 6716 6717 /** 6718 * Update display and views if last applied merged configuration changed. 6719 * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} otherwise. 6720 */ updateConfiguration(int newDisplayId)6721 public void updateConfiguration(int newDisplayId) { 6722 if (mView == null) { 6723 return; 6724 } 6725 6726 // At this point the resources have been updated to 6727 // have the most recent config, whatever that is. Use 6728 // the one in them which may be newer. 6729 final Resources localResources = mView.getResources(); 6730 final Configuration config = localResources.getConfiguration(); 6731 6732 // Handle move to display. 6733 if (newDisplayId != INVALID_DISPLAY) { 6734 onMovedToDisplay(newDisplayId, config); 6735 } 6736 6737 // Handle configuration change. 6738 if (mForceNextConfigUpdate || mLastConfigurationFromResources.diff(config) != 0) { 6739 // Update the display with new DisplayAdjustments. 6740 updateInternalDisplay(mDisplay.getDisplayId(), localResources); 6741 6742 updateLastConfigurationFromResources(config); 6743 mView.dispatchConfigurationChanged(config); 6744 6745 // We could have gotten this {@link Configuration} update after we called 6746 // {@link #performTraversals} with an older {@link Configuration}. As a result, our 6747 // window frame may be stale. We must ensure the next pass of {@link #performTraversals} 6748 // catches this. 6749 mForceNextWindowRelayout = true; 6750 requestLayout(); 6751 } 6752 6753 updateForceDarkMode(); 6754 } 6755 updateLastConfigurationFromResources(Configuration resConfig)6756 private void updateLastConfigurationFromResources(Configuration resConfig) { 6757 final int lastLayoutDirection = mLastConfigurationFromResources.getLayoutDirection(); 6758 final int currentLayoutDirection = resConfig.getLayoutDirection(); 6759 mLastConfigurationFromResources.setTo(resConfig); 6760 // Update layout direction in case the language or screen layout is changed. 6761 if (lastLayoutDirection != currentLayoutDirection && mView != null 6762 && mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) { 6763 mView.setLayoutDirection(currentLayoutDirection); 6764 } 6765 } 6766 6767 /** 6768 * Return true if child is an ancestor of parent, (or equal to the parent). 6769 */ isViewDescendantOf(View child, View parent)6770 public static boolean isViewDescendantOf(View child, View parent) { 6771 if (child == parent) { 6772 return true; 6773 } 6774 6775 final ViewParent theParent = child.getParent(); 6776 return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent); 6777 } 6778 forceLayout(View view)6779 private static void forceLayout(View view) { 6780 view.forceLayout(); 6781 if (view instanceof ViewGroup) { 6782 ViewGroup group = (ViewGroup) view; 6783 final int count = group.getChildCount(); 6784 for (int i = 0; i < count; i++) { 6785 forceLayout(group.getChildAt(i)); 6786 } 6787 } 6788 } 6789 6790 private static final int MSG_INVALIDATE = 1; 6791 private static final int MSG_INVALIDATE_RECT = 2; 6792 private static final int MSG_DIE = 3; 6793 private static final int MSG_RESIZED = 4; 6794 private static final int MSG_RESIZED_REPORT = 5; 6795 private static final int MSG_WINDOW_FOCUS_CHANGED = 6; 6796 private static final int MSG_DISPATCH_INPUT_EVENT = 7; 6797 private static final int MSG_DISPATCH_APP_VISIBILITY = 8; 6798 private static final int MSG_DISPATCH_GET_NEW_SURFACE = 9; 6799 private static final int MSG_DISPATCH_KEY_FROM_IME = 11; 6800 private static final int MSG_DISPATCH_KEY_FROM_AUTOFILL = 12; 6801 private static final int MSG_CHECK_FOCUS = 13; 6802 private static final int MSG_CLOSE_SYSTEM_DIALOGS = 14; 6803 private static final int MSG_DISPATCH_DRAG_EVENT = 15; 6804 private static final int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16; 6805 private static final int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17; 6806 private static final int MSG_UPDATE_CONFIGURATION = 18; 6807 private static final int MSG_PROCESS_INPUT_EVENTS = 19; 6808 private static final int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21; 6809 private static final int MSG_INVALIDATE_WORLD = 22; 6810 private static final int MSG_WINDOW_MOVED = 23; 6811 private static final int MSG_SYNTHESIZE_INPUT_EVENT = 24; 6812 private static final int MSG_DISPATCH_WINDOW_SHOWN = 25; 6813 private static final int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26; 6814 private static final int MSG_POINTER_CAPTURE_CHANGED = 28; 6815 private static final int MSG_INSETS_CONTROL_CHANGED = 29; 6816 private static final int MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED = 30; 6817 private static final int MSG_SHOW_INSETS = 31; 6818 private static final int MSG_HIDE_INSETS = 32; 6819 private static final int MSG_REQUEST_SCROLL_CAPTURE = 33; 6820 private static final int MSG_WINDOW_TOUCH_MODE_CHANGED = 34; 6821 private static final int MSG_KEEP_CLEAR_RECTS_CHANGED = 35; 6822 private static final int MSG_REPORT_KEEP_CLEAR_RECTS = 36; 6823 private static final int MSG_PAUSED_FOR_SYNC_TIMEOUT = 37; 6824 private static final int MSG_DECOR_VIEW_GESTURE_INTERCEPTION = 38; 6825 private static final int MSG_TOUCH_BOOST_TIMEOUT = 39; 6826 private static final int MSG_CHECK_INVALIDATION_IDLE = 40; 6827 private static final int MSG_REFRESH_POINTER_ICON = 41; 6828 private static final int MSG_FRAME_RATE_SETTING = 42; 6829 private static final int MSG_SURFACE_REPLACED_TIMEOUT = 43; 6830 private static final int MSG_INITIAL_TOUCH_BOOST_TIMEOUT = 44; 6831 6832 final class ViewRootHandler extends Handler { 6833 @Override getMessageName(Message message)6834 public String getMessageName(Message message) { 6835 switch (message.what) { 6836 case MSG_INVALIDATE: 6837 return "MSG_INVALIDATE"; 6838 case MSG_INVALIDATE_RECT: 6839 return "MSG_INVALIDATE_RECT"; 6840 case MSG_DIE: 6841 return "MSG_DIE"; 6842 case MSG_RESIZED: 6843 return "MSG_RESIZED"; 6844 case MSG_RESIZED_REPORT: 6845 return "MSG_RESIZED_REPORT"; 6846 case MSG_WINDOW_FOCUS_CHANGED: 6847 return "MSG_WINDOW_FOCUS_CHANGED"; 6848 case MSG_DISPATCH_INPUT_EVENT: 6849 return "MSG_DISPATCH_INPUT_EVENT"; 6850 case MSG_DISPATCH_APP_VISIBILITY: 6851 return "MSG_DISPATCH_APP_VISIBILITY"; 6852 case MSG_DISPATCH_GET_NEW_SURFACE: 6853 return "MSG_DISPATCH_GET_NEW_SURFACE"; 6854 case MSG_DISPATCH_KEY_FROM_IME: 6855 return "MSG_DISPATCH_KEY_FROM_IME"; 6856 case MSG_DISPATCH_KEY_FROM_AUTOFILL: 6857 return "MSG_DISPATCH_KEY_FROM_AUTOFILL"; 6858 case MSG_CHECK_FOCUS: 6859 return "MSG_CHECK_FOCUS"; 6860 case MSG_CLOSE_SYSTEM_DIALOGS: 6861 return "MSG_CLOSE_SYSTEM_DIALOGS"; 6862 case MSG_DISPATCH_DRAG_EVENT: 6863 return "MSG_DISPATCH_DRAG_EVENT"; 6864 case MSG_DISPATCH_DRAG_LOCATION_EVENT: 6865 return "MSG_DISPATCH_DRAG_LOCATION_EVENT"; 6866 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: 6867 return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY"; 6868 case MSG_UPDATE_CONFIGURATION: 6869 return "MSG_UPDATE_CONFIGURATION"; 6870 case MSG_PROCESS_INPUT_EVENTS: 6871 return "MSG_PROCESS_INPUT_EVENTS"; 6872 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: 6873 return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST"; 6874 case MSG_WINDOW_MOVED: 6875 return "MSG_WINDOW_MOVED"; 6876 case MSG_SYNTHESIZE_INPUT_EVENT: 6877 return "MSG_SYNTHESIZE_INPUT_EVENT"; 6878 case MSG_DISPATCH_WINDOW_SHOWN: 6879 return "MSG_DISPATCH_WINDOW_SHOWN"; 6880 case MSG_POINTER_CAPTURE_CHANGED: 6881 return "MSG_POINTER_CAPTURE_CHANGED"; 6882 case MSG_INSETS_CONTROL_CHANGED: 6883 return "MSG_INSETS_CONTROL_CHANGED"; 6884 case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED: 6885 return "MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED"; 6886 case MSG_SHOW_INSETS: 6887 return "MSG_SHOW_INSETS"; 6888 case MSG_HIDE_INSETS: 6889 return "MSG_HIDE_INSETS"; 6890 case MSG_WINDOW_TOUCH_MODE_CHANGED: 6891 return "MSG_WINDOW_TOUCH_MODE_CHANGED"; 6892 case MSG_KEEP_CLEAR_RECTS_CHANGED: 6893 return "MSG_KEEP_CLEAR_RECTS_CHANGED"; 6894 case MSG_CHECK_INVALIDATION_IDLE: 6895 return "MSG_CHECK_INVALIDATION_IDLE"; 6896 case MSG_REFRESH_POINTER_ICON: 6897 return "MSG_REFRESH_POINTER_ICON"; 6898 case MSG_TOUCH_BOOST_TIMEOUT: 6899 return "MSG_TOUCH_BOOST_TIMEOUT"; 6900 case MSG_FRAME_RATE_SETTING: 6901 return "MSG_FRAME_RATE_SETTING"; 6902 case MSG_SURFACE_REPLACED_TIMEOUT: 6903 return "MSG_SURFACE_REPLACED_TIMEOUT"; 6904 case MSG_INITIAL_TOUCH_BOOST_TIMEOUT: 6905 return "MSG_INITIAL_TOUCH_BOOST_TIMEOUT"; 6906 } 6907 return super.getMessageName(message); 6908 } 6909 6910 @Override sendMessageAtTime(Message msg, long uptimeMillis)6911 public boolean sendMessageAtTime(Message msg, long uptimeMillis) { 6912 if (msg.what == MSG_REQUEST_KEYBOARD_SHORTCUTS && msg.obj == null) { 6913 // Debugging for b/27963013 6914 throw new NullPointerException( 6915 "Attempted to call MSG_REQUEST_KEYBOARD_SHORTCUTS with null receiver:"); 6916 } 6917 return super.sendMessageAtTime(msg, uptimeMillis); 6918 } 6919 6920 @Override handleMessage(Message msg)6921 public void handleMessage(Message msg) { 6922 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 6923 Trace.traceBegin(Trace.TRACE_TAG_VIEW, getMessageName(msg)); 6924 } 6925 try { 6926 handleMessageImpl(msg); 6927 } finally { 6928 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 6929 } 6930 } 6931 handleMessageImpl(Message msg)6932 private void handleMessageImpl(Message msg) { 6933 switch (msg.what) { 6934 case MSG_INVALIDATE: 6935 ((View) msg.obj).invalidate(); 6936 break; 6937 case MSG_INVALIDATE_RECT: 6938 final View.AttachInfo.InvalidateInfo info = 6939 (View.AttachInfo.InvalidateInfo) msg.obj; 6940 info.target.invalidate(info.left, info.top, info.right, info.bottom); 6941 info.recycle(); 6942 break; 6943 case MSG_PROCESS_INPUT_EVENTS: 6944 mProcessInputEventsScheduled = false; 6945 doProcessInputEvents(); 6946 break; 6947 case MSG_DISPATCH_APP_VISIBILITY: 6948 handleAppVisibility(msg.arg1 != 0); 6949 break; 6950 case MSG_DISPATCH_GET_NEW_SURFACE: 6951 handleGetNewSurface(); 6952 break; 6953 case MSG_RESIZED: 6954 case MSG_RESIZED_REPORT: { 6955 final SomeArgs args = (SomeArgs) msg.obj; 6956 final ClientWindowFrames frames = (ClientWindowFrames) args.arg1; 6957 final boolean reportDraw = msg.what == MSG_RESIZED_REPORT; 6958 final MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg2; 6959 final InsetsState insetsState = (InsetsState) args.arg3; 6960 final ActivityWindowInfo activityWindowInfo = (ActivityWindowInfo) args.arg4; 6961 final boolean forceLayout = args.argi1 != 0; 6962 final boolean alwaysConsumeSystemBars = args.argi2 != 0; 6963 final int displayId = args.argi3; 6964 final int syncSeqId = args.argi4; 6965 final boolean dragResizing = args.argi5 != 0; 6966 handleResized(frames, reportDraw, mergedConfiguration, insetsState, forceLayout, 6967 alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing, 6968 activityWindowInfo); 6969 args.recycle(); 6970 break; 6971 } 6972 case MSG_INSETS_CONTROL_CHANGED: { 6973 final SomeArgs args = (SomeArgs) msg.obj; 6974 final InsetsState insetsState = (InsetsState) args.arg1; 6975 final InsetsSourceControl.Array activeControls = 6976 (InsetsSourceControl.Array) args.arg2; 6977 handleInsetsControlChanged(insetsState, activeControls); 6978 args.recycle(); 6979 break; 6980 } 6981 case MSG_SHOW_INSETS: { 6982 final ImeTracker.Token statsToken = (ImeTracker.Token) msg.obj; 6983 ImeTracker.forLogging().onProgress(statsToken, 6984 ImeTracker.PHASE_CLIENT_HANDLE_SHOW_INSETS); 6985 if (mView == null) { 6986 Log.e(TAG, 6987 String.format("Calling showInsets(%d,%b) on window that no longer" 6988 + " has views.", msg.arg1, msg.arg2 == 1)); 6989 } 6990 clearLowProfileModeIfNeeded(msg.arg1, msg.arg2 == 1); 6991 mInsetsController.show(msg.arg1, msg.arg2 == 1, statsToken); 6992 break; 6993 } 6994 case MSG_HIDE_INSETS: { 6995 final ImeTracker.Token statsToken = (ImeTracker.Token) msg.obj; 6996 ImeTracker.forLogging().onProgress(statsToken, 6997 ImeTracker.PHASE_CLIENT_HANDLE_HIDE_INSETS); 6998 mInsetsController.hide(msg.arg1, msg.arg2 == 1, statsToken); 6999 break; 7000 } 7001 case MSG_WINDOW_MOVED: 7002 if (mAdded) { 7003 final int w = mWinFrame.width(); 7004 final int h = mWinFrame.height(); 7005 final int l = msg.arg1; 7006 final int t = msg.arg2; 7007 mTmpFrames.frame.left = l; 7008 mTmpFrames.frame.right = l + w; 7009 mTmpFrames.frame.top = t; 7010 mTmpFrames.frame.bottom = t + h; 7011 setFrame(mTmpFrames.frame, false /* withinRelayout */); 7012 maybeHandleWindowMove(mWinFrame); 7013 } 7014 break; 7015 case MSG_WINDOW_FOCUS_CHANGED: { 7016 handleWindowFocusChanged(); 7017 } break; 7018 case MSG_WINDOW_TOUCH_MODE_CHANGED: { 7019 handleWindowTouchModeChanged(); 7020 } break; 7021 case MSG_DIE: { 7022 doDie(); 7023 } break; 7024 case MSG_DISPATCH_INPUT_EVENT: { 7025 SomeArgs args = (SomeArgs) msg.obj; 7026 InputEvent event = (InputEvent) args.arg1; 7027 InputEventReceiver receiver = (InputEventReceiver) args.arg2; 7028 enqueueInputEvent(event, receiver, 0, true); 7029 args.recycle(); 7030 } break; 7031 case MSG_SYNTHESIZE_INPUT_EVENT: { 7032 InputEvent event = (InputEvent) msg.obj; 7033 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_UNHANDLED, true); 7034 } break; 7035 case MSG_DISPATCH_KEY_FROM_IME: { 7036 if (LOCAL_LOGV) { 7037 Log.v(TAG, "Dispatching key " + msg.obj + " from IME to " + mView); 7038 } 7039 KeyEvent event = (KeyEvent) msg.obj; 7040 if ((event.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) != 0) { 7041 // The IME is trying to say this event is from the 7042 // system! Bad bad bad! 7043 //noinspection UnusedAssignment 7044 event = KeyEvent.changeFlags(event, 7045 event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM); 7046 } 7047 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true); 7048 } break; 7049 case MSG_DISPATCH_KEY_FROM_AUTOFILL: { 7050 if (LOCAL_LOGV) { 7051 Log.v(TAG, "Dispatching key " + msg.obj + " from Autofill to " + mView); 7052 } 7053 KeyEvent event = (KeyEvent) msg.obj; 7054 enqueueInputEvent(event, null, 0, true); 7055 } break; 7056 case MSG_CHECK_FOCUS: { 7057 getImeFocusController().onScheduledCheckFocus(); 7058 } break; 7059 case MSG_CLOSE_SYSTEM_DIALOGS: { 7060 if (mView != null) { 7061 mView.onCloseSystemDialogs((String) msg.obj); 7062 } 7063 } break; 7064 case MSG_DISPATCH_DRAG_EVENT: { 7065 } // fall through 7066 case MSG_DISPATCH_DRAG_LOCATION_EVENT: { 7067 DragEvent event = (DragEvent) msg.obj; 7068 // only present when this app called startDrag() 7069 event.mLocalState = mLocalDragState; 7070 final boolean traceDragEvent = event.mAction != ACTION_DRAG_LOCATION; 7071 try { 7072 if (traceDragEvent) { 7073 Trace.traceBegin(TRACE_TAG_VIEW, 7074 "c#" + DragEvent.actionToString(event.mAction)); 7075 } 7076 handleDragEvent(event); 7077 } finally { 7078 if (traceDragEvent) { 7079 Trace.traceEnd(TRACE_TAG_VIEW); 7080 } 7081 } 7082 } break; 7083 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: { 7084 handleDispatchSystemUiVisibilityChanged(); 7085 } break; 7086 case MSG_UPDATE_CONFIGURATION: { 7087 Configuration config = (Configuration) msg.obj; 7088 if (config.isOtherSeqNewer( 7089 mLastReportedMergedConfiguration.getMergedConfiguration())) { 7090 // If we already have a newer merged config applied - use its global part. 7091 config = mLastReportedMergedConfiguration.getGlobalConfiguration(); 7092 } 7093 7094 // Use the newer global config and last reported override config. 7095 mPendingMergedConfiguration.setConfiguration(config, 7096 mLastReportedMergedConfiguration.getOverrideConfiguration()); 7097 if (mPendingActivityWindowInfo != null) { 7098 mPendingActivityWindowInfo.set(mLastReportedActivityWindowInfo); 7099 } 7100 7101 performConfigurationChange(new MergedConfiguration(mPendingMergedConfiguration), 7102 false /* force */, INVALID_DISPLAY /* same display */, 7103 mPendingActivityWindowInfo != null 7104 ? new ActivityWindowInfo(mPendingActivityWindowInfo) 7105 : null); 7106 } break; 7107 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: { 7108 setAccessibilityFocus(null, null); 7109 } break; 7110 case MSG_INVALIDATE_WORLD: { 7111 if (mView != null) { 7112 invalidateWorld(mView); 7113 } 7114 } break; 7115 case MSG_DISPATCH_WINDOW_SHOWN: { 7116 handleDispatchWindowShown(); 7117 } break; 7118 case MSG_REQUEST_KEYBOARD_SHORTCUTS: { 7119 final IResultReceiver receiver = (IResultReceiver) msg.obj; 7120 final int deviceId = msg.arg1; 7121 handleRequestKeyboardShortcuts(receiver, deviceId); 7122 } break; 7123 case MSG_POINTER_CAPTURE_CHANGED: { 7124 final boolean hasCapture = msg.arg1 != 0; 7125 handlePointerCaptureChanged(hasCapture); 7126 } break; 7127 case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED: { 7128 systemGestureExclusionChanged(); 7129 } break; 7130 case MSG_DECOR_VIEW_GESTURE_INTERCEPTION: { 7131 decorViewInterceptionChanged(/* intercepted= */ msg.arg1 == 1); 7132 } break; 7133 case MSG_KEEP_CLEAR_RECTS_CHANGED: { 7134 keepClearRectsChanged(/* accessibilityFocusRectChanged= */ msg.arg1 == 1); 7135 } break; 7136 case MSG_REPORT_KEEP_CLEAR_RECTS: { 7137 reportKeepClearAreasChanged(); 7138 } break; 7139 case MSG_REQUEST_SCROLL_CAPTURE: 7140 handleScrollCaptureRequest((IScrollCaptureResponseListener) msg.obj); 7141 break; 7142 case MSG_PAUSED_FOR_SYNC_TIMEOUT: 7143 resumeAfterSyncTimeout(); 7144 break; 7145 case MSG_CHECK_INVALIDATION_IDLE: { 7146 long delta; 7147 if (mIsTouchBoosting || mIsFrameRateBoosting || mInsetsAnimationRunning) { 7148 delta = 0; 7149 } else { 7150 delta = System.nanoTime() / NANOS_PER_MILLI - mLastUpdateTimeMillis; 7151 } 7152 if (delta >= IDLE_TIME_MILLIS) { 7153 mFrameRateCategoryHighCount = 0; 7154 mFrameRateCategoryHighHintCount = 0; 7155 mFrameRateCategoryNormalCount = 0; 7156 mFrameRateCategoryLowCount = 0; 7157 mPreferredFrameRate = 0; 7158 mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE; 7159 updateFrameRateFromThreadedRendererViews(); 7160 setPreferredFrameRate(mPreferredFrameRate); 7161 setPreferredFrameRateCategory(mPreferredFrameRateCategory); 7162 mInvalidationIdleMessagePosted = false; 7163 mIsPressedGesture = false; 7164 } else { 7165 mInvalidationIdleMessagePosted = true; 7166 mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE, 7167 IDLE_TIME_MILLIS - delta); 7168 } 7169 break; 7170 } 7171 case MSG_TOUCH_BOOST_TIMEOUT: 7172 /** 7173 * Lower the frame rate after the boosting period (FRAME_RATE_TOUCH_BOOST_TIME). 7174 */ 7175 mIsFrameRateBoosting = false; 7176 mIsTouchBoosting = false; 7177 if (!mDrawnThisFrame) { 7178 setPreferredFrameRateCategory(FRAME_RATE_CATEGORY_NO_PREFERENCE); 7179 } 7180 break; 7181 case MSG_INITIAL_TOUCH_BOOST_TIMEOUT: 7182 if (mTouchAndDrawn) { 7183 mHandler.removeMessages(MSG_TOUCH_BOOST_TIMEOUT); 7184 mHandler.sendEmptyMessageDelayed(MSG_TOUCH_BOOST_TIMEOUT, 7185 FRAME_RATE_TOUCH_BOOST_TIME); 7186 } else { 7187 mIsTouchBoosting = false; 7188 setPreferredFrameRateCategory(FRAME_RATE_CATEGORY_NO_PREFERENCE); 7189 } 7190 mTouchAndDrawn = false; 7191 break; 7192 case MSG_REFRESH_POINTER_ICON: 7193 if (mPointerIconEvent == null) { 7194 break; 7195 } 7196 updatePointerIcon(mPointerIconEvent); 7197 break; 7198 case MSG_FRAME_RATE_SETTING: 7199 mPreferredFrameRate = 0; 7200 mFrameRateCompatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; 7201 break; 7202 case MSG_SURFACE_REPLACED_TIMEOUT: 7203 mSurfaceReplaced = false; 7204 break; 7205 } 7206 } 7207 } 7208 7209 final ViewRootHandler mHandler = new ViewRootHandler(); 7210 final Executor mExecutor = (Runnable r) -> { 7211 mHandler.post(r); 7212 }; 7213 7214 /** 7215 * Something in the current window tells us we need to change the touch mode. For 7216 * example, we are not in touch mode, and the user touches the screen. 7217 * 7218 * If the touch mode has changed, tell the window manager, and handle it locally. 7219 * 7220 * @param inTouchMode Whether we want to be in touch mode. 7221 * @return True if the touch mode changed and focus changed was changed as a result 7222 */ 7223 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) ensureTouchMode(boolean inTouchMode)7224 boolean ensureTouchMode(boolean inTouchMode) { 7225 if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current " 7226 + "touch mode is " + mAttachInfo.mInTouchMode); 7227 if (mAttachInfo.mInTouchMode == inTouchMode) return false; 7228 7229 if (inTouchMode && mAttachInfo.mThreadedRenderer != null && mSendPerfHintOnTouch) { 7230 mAttachInfo.mThreadedRenderer.notifyExpensiveFrame(); 7231 } 7232 7233 // tell the window manager 7234 try { 7235 IWindowManager windowManager = WindowManagerGlobal.getWindowManagerService(); 7236 windowManager.setInTouchMode(inTouchMode, getDisplayId()); 7237 } catch (RemoteException e) { 7238 throw new RuntimeException(e); 7239 } 7240 7241 // handle the change 7242 return ensureTouchModeLocally(inTouchMode); 7243 } 7244 7245 /** 7246 * Ensure that the touch mode for this window is set, and if it is changing, 7247 * take the appropriate action. 7248 * @param inTouchMode Whether we want to be in touch mode. 7249 * @return True if the touch mode changed and focus changed was changed as a result 7250 */ ensureTouchModeLocally(boolean inTouchMode)7251 private boolean ensureTouchModeLocally(boolean inTouchMode) { 7252 if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current " 7253 + "touch mode is " + mAttachInfo.mInTouchMode); 7254 7255 if (mAttachInfo.mInTouchMode == inTouchMode) return false; 7256 7257 mAttachInfo.mInTouchMode = inTouchMode; 7258 mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode); 7259 7260 return (inTouchMode) ? enterTouchMode() : leaveTouchMode(); 7261 } 7262 enterTouchMode()7263 private boolean enterTouchMode() { 7264 if (mView != null && mView.hasFocus()) { 7265 // note: not relying on mFocusedView here because this could 7266 // be when the window is first being added, and mFocused isn't 7267 // set yet. 7268 final View focused = mView.findFocus(); 7269 if (focused != null && !focused.isFocusableInTouchMode()) { 7270 final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused); 7271 if (ancestorToTakeFocus != null) { 7272 // there is an ancestor that wants focus after its 7273 // descendants that is focusable in touch mode.. give it 7274 // focus 7275 return ancestorToTakeFocus.requestFocus(); 7276 } else { 7277 // There's nothing to focus. Clear and propagate through the 7278 // hierarchy, but don't attempt to place new focus. 7279 focused.clearFocusInternal(null, true, false); 7280 return true; 7281 } 7282 } 7283 } 7284 return false; 7285 } 7286 7287 /** 7288 * Find an ancestor of focused that wants focus after its descendants and is 7289 * focusable in touch mode. 7290 * @param focused The currently focused view. 7291 * @return An appropriate view, or null if no such view exists. 7292 */ findAncestorToTakeFocusInTouchMode(View focused)7293 private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) { 7294 ViewParent parent = focused.getParent(); 7295 while (parent instanceof ViewGroup) { 7296 final ViewGroup vgParent = (ViewGroup) parent; 7297 if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS 7298 && vgParent.isFocusableInTouchMode()) { 7299 return vgParent; 7300 } 7301 if (vgParent.isRootNamespace()) { 7302 return null; 7303 } else { 7304 parent = vgParent.getParent(); 7305 } 7306 } 7307 return null; 7308 } 7309 leaveTouchMode()7310 private boolean leaveTouchMode() { 7311 if (mView != null) { 7312 if (mView.hasFocus()) { 7313 View focusedView = mView.findFocus(); 7314 if (!(focusedView instanceof ViewGroup)) { 7315 // some view has focus, let it keep it 7316 return false; 7317 } else if (((ViewGroup) focusedView).getDescendantFocusability() != 7318 ViewGroup.FOCUS_AFTER_DESCENDANTS) { 7319 // some view group has focus, and doesn't prefer its children 7320 // over itself for focus, so let them keep it. 7321 return false; 7322 } 7323 } 7324 7325 // find the best view to give focus to in this brave new non-touch-mode 7326 // world 7327 return mView.restoreDefaultFocus(); 7328 } 7329 return false; 7330 } 7331 7332 /** 7333 * Base class for implementing a stage in the chain of responsibility 7334 * for processing input events. 7335 * <p> 7336 * Events are delivered to the stage by the {@link #deliver} method. The stage 7337 * then has the choice of finishing the event or forwarding it to the next stage. 7338 * </p> 7339 */ 7340 abstract class InputStage { 7341 private final InputStage mNext; 7342 7343 protected static final int FORWARD = 0; 7344 protected static final int FINISH_HANDLED = 1; 7345 protected static final int FINISH_NOT_HANDLED = 2; 7346 7347 private String mTracePrefix; 7348 7349 /** 7350 * Creates an input stage. 7351 * @param next The next stage to which events should be forwarded. 7352 */ InputStage(InputStage next)7353 public InputStage(InputStage next) { 7354 mNext = next; 7355 } 7356 7357 /** 7358 * Delivers an event to be processed. 7359 */ deliver(QueuedInputEvent q)7360 public final void deliver(QueuedInputEvent q) { 7361 if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) { 7362 forward(q); 7363 } else if (shouldDropInputEvent(q)) { 7364 finish(q, false); 7365 } else { 7366 traceEvent(q, Trace.TRACE_TAG_VIEW); 7367 final int result; 7368 try { 7369 result = onProcess(q); 7370 } finally { 7371 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 7372 } 7373 apply(q, result); 7374 } 7375 } 7376 7377 /** 7378 * Marks the input event as finished then forwards it to the next stage. 7379 */ finish(QueuedInputEvent q, boolean handled)7380 protected void finish(QueuedInputEvent q, boolean handled) { 7381 q.mFlags |= QueuedInputEvent.FLAG_FINISHED; 7382 if (handled) { 7383 q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED; 7384 } 7385 forward(q); 7386 } 7387 7388 /** 7389 * Forwards the event to the next stage. 7390 */ forward(QueuedInputEvent q)7391 protected void forward(QueuedInputEvent q) { 7392 onDeliverToNext(q); 7393 } 7394 7395 /** 7396 * Applies a result code from {@link #onProcess} to the specified event. 7397 */ apply(QueuedInputEvent q, int result)7398 protected void apply(QueuedInputEvent q, int result) { 7399 if (result == FORWARD) { 7400 forward(q); 7401 } else if (result == FINISH_HANDLED) { 7402 finish(q, true); 7403 } else if (result == FINISH_NOT_HANDLED) { 7404 finish(q, false); 7405 } else { 7406 throw new IllegalArgumentException("Invalid result: " + result); 7407 } 7408 } 7409 7410 /** 7411 * Called when an event is ready to be processed. 7412 * @return A result code indicating how the event was handled. 7413 */ onProcess(QueuedInputEvent q)7414 protected int onProcess(QueuedInputEvent q) { 7415 return FORWARD; 7416 } 7417 7418 /** 7419 * Called when an event is being delivered to the next stage. 7420 */ onDeliverToNext(QueuedInputEvent q)7421 protected void onDeliverToNext(QueuedInputEvent q) { 7422 if (DEBUG_INPUT_STAGES) { 7423 Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q); 7424 } 7425 if (mNext != null) { 7426 mNext.deliver(q); 7427 } else { 7428 finishInputEvent(q); 7429 } 7430 } 7431 onWindowFocusChanged(boolean hasWindowFocus)7432 protected void onWindowFocusChanged(boolean hasWindowFocus) { 7433 if (mNext != null) { 7434 mNext.onWindowFocusChanged(hasWindowFocus); 7435 } 7436 } 7437 onDetachedFromWindow()7438 protected void onDetachedFromWindow() { 7439 if (mNext != null) { 7440 mNext.onDetachedFromWindow(); 7441 } 7442 } 7443 shouldDropInputEvent(QueuedInputEvent q)7444 protected boolean shouldDropInputEvent(QueuedInputEvent q) { 7445 if (mView == null || !mAdded) { 7446 Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent); 7447 return true; 7448 } 7449 7450 // Find a reason for dropping or canceling the event. 7451 final String reason; 7452 // The embedded window is focused, allow this VRI to handle back key. 7453 if (!mAttachInfo.mHasWindowFocus && !isBack(q.mEvent) 7454 && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER) 7455 && !isAutofillUiShowing()) { 7456 // This is a non-pointer event and the window doesn't currently have input focus 7457 // This could be an event that came back from the previous stage 7458 // but the window has lost focus or stopped in the meantime. 7459 reason = "no window focus"; 7460 } else if (mStopped) { 7461 reason = "window is stopped"; 7462 } else if (mIsAmbientMode 7463 && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON)) { 7464 reason = "non-button event in ambient mode"; 7465 } else if (mPausedForTransition && !isBack(q.mEvent)) { 7466 reason = "paused for transition"; 7467 } else { 7468 // Most common path: no reason to drop or cancel the event 7469 return false; 7470 } 7471 7472 if (isTerminalInputEvent(q.mEvent)) { 7473 // Don't drop terminal input events, however mark them as canceled. 7474 q.mEvent.cancel(); 7475 Slog.w(mTag, "Cancelling event (" + reason + "):" + q.mEvent); 7476 return false; 7477 } 7478 7479 // Drop non-terminal input events. 7480 Slog.w(mTag, "Dropping event (" + reason + "):" + q.mEvent); 7481 return true; 7482 } 7483 dump(String prefix, PrintWriter writer)7484 void dump(String prefix, PrintWriter writer) { 7485 if (mNext != null) { 7486 mNext.dump(prefix, writer); 7487 } 7488 } 7489 isBack(InputEvent event)7490 boolean isBack(InputEvent event) { 7491 if (event instanceof KeyEvent) { 7492 return ((KeyEvent) event).getKeyCode() == KeyEvent.KEYCODE_BACK; 7493 } else { 7494 return false; 7495 } 7496 } 7497 traceEvent(QueuedInputEvent q, long traceTag)7498 private void traceEvent(QueuedInputEvent q, long traceTag) { 7499 if (!Trace.isTagEnabled(traceTag)) { 7500 return; 7501 } 7502 7503 if (mTracePrefix == null) { 7504 mTracePrefix = getClass().getSimpleName(); 7505 } 7506 Trace.traceBegin(traceTag, mTracePrefix + " id=0x" 7507 + Integer.toHexString(q.mEvent.getId())); 7508 } 7509 } 7510 7511 /** 7512 * Base class for implementing an input pipeline stage that supports 7513 * asynchronous and out-of-order processing of input events. 7514 * <p> 7515 * In addition to what a normal input stage can do, an asynchronous 7516 * input stage may also defer an input event that has been delivered to it 7517 * and finish or forward it later. 7518 * </p> 7519 */ 7520 abstract class AsyncInputStage extends InputStage { 7521 private final String mTraceCounter; 7522 7523 private QueuedInputEvent mQueueHead; 7524 private QueuedInputEvent mQueueTail; 7525 private int mQueueLength; 7526 7527 protected static final int DEFER = 3; 7528 7529 /** 7530 * Creates an asynchronous input stage. 7531 * @param next The next stage to which events should be forwarded. 7532 * @param traceCounter The name of a counter to record the size of 7533 * the queue of pending events. 7534 */ AsyncInputStage(InputStage next, String traceCounter)7535 public AsyncInputStage(InputStage next, String traceCounter) { 7536 super(next); 7537 mTraceCounter = traceCounter; 7538 } 7539 7540 /** 7541 * Marks the event as deferred, which is to say that it will be handled 7542 * asynchronously. The caller is responsible for calling {@link #forward} 7543 * or {@link #finish} later when it is done handling the event. 7544 */ defer(QueuedInputEvent q)7545 protected void defer(QueuedInputEvent q) { 7546 q.mFlags |= QueuedInputEvent.FLAG_DEFERRED; 7547 enqueue(q); 7548 } 7549 7550 @Override forward(QueuedInputEvent q)7551 protected void forward(QueuedInputEvent q) { 7552 // Clear the deferred flag. 7553 q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED; 7554 7555 // Fast path if the queue is empty. 7556 QueuedInputEvent curr = mQueueHead; 7557 if (curr == null) { 7558 super.forward(q); 7559 return; 7560 } 7561 7562 // Determine whether the event must be serialized behind any others 7563 // before it can be delivered to the next stage. This is done because 7564 // deferred events might be handled out of order by the stage. 7565 final int deviceId = q.mEvent.getDeviceId(); 7566 QueuedInputEvent prev = null; 7567 boolean blocked = false; 7568 while (curr != null && curr != q) { 7569 if (!blocked && deviceId == curr.mEvent.getDeviceId()) { 7570 blocked = true; 7571 } 7572 prev = curr; 7573 curr = curr.mNext; 7574 } 7575 7576 // If the event is blocked, then leave it in the queue to be delivered later. 7577 // Note that the event might not yet be in the queue if it was not previously 7578 // deferred so we will enqueue it if needed. 7579 if (blocked) { 7580 if (curr == null) { 7581 enqueue(q); 7582 } 7583 return; 7584 } 7585 7586 // The event is not blocked. Deliver it immediately. 7587 if (curr != null) { 7588 curr = curr.mNext; 7589 dequeue(q, prev); 7590 } 7591 super.forward(q); 7592 7593 // Dequeuing this event may have unblocked successors. Deliver them. 7594 while (curr != null) { 7595 if (deviceId == curr.mEvent.getDeviceId()) { 7596 if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) { 7597 break; 7598 } 7599 QueuedInputEvent next = curr.mNext; 7600 dequeue(curr, prev); 7601 super.forward(curr); 7602 curr = next; 7603 } else { 7604 prev = curr; 7605 curr = curr.mNext; 7606 } 7607 } 7608 } 7609 7610 @Override apply(QueuedInputEvent q, int result)7611 protected void apply(QueuedInputEvent q, int result) { 7612 if (result == DEFER) { 7613 defer(q); 7614 } else { 7615 super.apply(q, result); 7616 } 7617 } 7618 enqueue(QueuedInputEvent q)7619 private void enqueue(QueuedInputEvent q) { 7620 if (mQueueTail == null) { 7621 mQueueHead = q; 7622 mQueueTail = q; 7623 } else { 7624 mQueueTail.mNext = q; 7625 mQueueTail = q; 7626 } 7627 7628 mQueueLength += 1; 7629 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength); 7630 } 7631 dequeue(QueuedInputEvent q, QueuedInputEvent prev)7632 private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) { 7633 if (prev == null) { 7634 mQueueHead = q.mNext; 7635 } else { 7636 prev.mNext = q.mNext; 7637 } 7638 if (mQueueTail == q) { 7639 mQueueTail = prev; 7640 } 7641 q.mNext = null; 7642 7643 mQueueLength -= 1; 7644 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength); 7645 } 7646 7647 @Override dump(String prefix, PrintWriter writer)7648 void dump(String prefix, PrintWriter writer) { 7649 writer.print(prefix); 7650 writer.print(getClass().getName()); 7651 writer.print(": mQueueLength="); 7652 writer.println(mQueueLength); 7653 7654 super.dump(prefix, writer); 7655 } 7656 } 7657 7658 /** 7659 * Delivers pre-ime input events to a native activity. 7660 * Does not support pointer events. 7661 */ 7662 final class NativePreImeInputStage extends AsyncInputStage 7663 implements InputQueue.FinishedInputEventCallback { 7664 NativePreImeInputStage(InputStage next, String traceCounter)7665 public NativePreImeInputStage(InputStage next, String traceCounter) { 7666 super(next, traceCounter); 7667 } 7668 7669 @Override onProcess(QueuedInputEvent q)7670 protected int onProcess(QueuedInputEvent q) { 7671 if (q.forPreImeOnly()) { 7672 // this event is intended for the ViewPreImeInputStage only, let's forward 7673 return FORWARD; 7674 } 7675 if (q.mEvent instanceof KeyEvent) { 7676 final KeyEvent keyEvent = (KeyEvent) q.mEvent; 7677 7678 // If the new back dispatch is enabled, intercept KEYCODE_BACK before it reaches the 7679 // view tree or IME, and invoke the appropriate {@link OnBackInvokedCallback}. 7680 if (isBack(keyEvent)) { 7681 if (mWindowlessBackKeyCallback != null) { 7682 if (mWindowlessBackKeyCallback.test(keyEvent)) { 7683 return keyEvent.getAction() == KeyEvent.ACTION_UP 7684 && !keyEvent.isCanceled() 7685 ? FINISH_HANDLED : FINISH_NOT_HANDLED; 7686 } else { 7687 // Unable to forward the back key to host, forward to next stage. 7688 return FORWARD; 7689 } 7690 } else if (mContext != null 7691 && mOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled()) { 7692 return doOnBackKeyEvent(keyEvent); 7693 } 7694 } 7695 7696 if (mInputQueue != null) { 7697 mInputQueue.sendInputEvent(q.mEvent, q, true, this); 7698 return DEFER; 7699 } 7700 } 7701 return FORWARD; 7702 } 7703 doOnBackKeyEvent(KeyEvent keyEvent)7704 private int doOnBackKeyEvent(KeyEvent keyEvent) { 7705 WindowOnBackInvokedDispatcher dispatcher = getOnBackInvokedDispatcher(); 7706 OnBackInvokedCallback topCallback = dispatcher.getTopCallback(); 7707 if (dispatcher.isBackGestureInProgress()) { 7708 return FINISH_NOT_HANDLED; 7709 } 7710 if (topCallback instanceof OnBackAnimationCallback 7711 && !(topCallback instanceof ImeBackAnimationController)) { 7712 final OnBackAnimationCallback animationCallback = 7713 (OnBackAnimationCallback) topCallback; 7714 switch (keyEvent.getAction()) { 7715 case KeyEvent.ACTION_DOWN: 7716 // ACTION_DOWN is emitted twice: once when the user presses the button, 7717 // and again a few milliseconds later. 7718 // Based on the result of `keyEvent.getRepeatCount()` we have: 7719 // - 0 means the button was pressed. 7720 // - 1 means the button continues to be pressed (long press). 7721 if (keyEvent.getRepeatCount() == 0) { 7722 BackEvent backEvent; 7723 if (predictiveBackSwipeEdgeNoneApi()) { 7724 backEvent = new BackEvent(0, 0, 0f, BackEvent.EDGE_NONE); 7725 } else { 7726 backEvent = new BackEvent(0, 0, 0f, BackEvent.EDGE_LEFT); 7727 } 7728 animationCallback.onBackStarted(backEvent); 7729 } 7730 break; 7731 case KeyEvent.ACTION_UP: 7732 if (keyEvent.isCanceled()) { 7733 animationCallback.onBackCancelled(); 7734 } else { 7735 dispatcher.tryInvokeSystemNavigationObserverCallback(); 7736 topCallback.onBackInvoked(); 7737 } 7738 break; 7739 } 7740 } else if (topCallback != null) { 7741 if (keyEvent.getAction() == KeyEvent.ACTION_UP) { 7742 if (!keyEvent.isCanceled()) { 7743 dispatcher.tryInvokeSystemNavigationObserverCallback(); 7744 topCallback.onBackInvoked(); 7745 } else { 7746 Log.d(mTag, "Skip onBackInvoked(), reason: keyEvent.isCanceled=true"); 7747 } 7748 } 7749 } 7750 if (keyEvent.getAction() == KeyEvent.ACTION_UP) { 7751 // forward a cancelled event so that following stages cancel their back logic 7752 keyEvent.cancel(); 7753 } 7754 return FORWARD; 7755 } 7756 7757 @Override onFinishedInputEvent(Object token, boolean handled)7758 public void onFinishedInputEvent(Object token, boolean handled) { 7759 QueuedInputEvent q = (QueuedInputEvent)token; 7760 if (handled) { 7761 finish(q, true); 7762 return; 7763 } 7764 forward(q); 7765 } 7766 } 7767 7768 /** 7769 * Delivers pre-ime input events to the view hierarchy. 7770 * Does not support pointer events. 7771 */ 7772 final class ViewPreImeInputStage extends InputStage { ViewPreImeInputStage(InputStage next)7773 public ViewPreImeInputStage(InputStage next) { 7774 super(next); 7775 } 7776 7777 @Override onProcess(QueuedInputEvent q)7778 protected int onProcess(QueuedInputEvent q) { 7779 if (q.mEvent instanceof KeyEvent) { 7780 return processKeyEvent(q); 7781 } 7782 return FORWARD; 7783 } 7784 processKeyEvent(QueuedInputEvent q)7785 private int processKeyEvent(QueuedInputEvent q) { 7786 final KeyEvent event = (KeyEvent)q.mEvent; 7787 if (mView.dispatchKeyEventPreIme(event)) { 7788 return FINISH_HANDLED; 7789 } else if (q.forPreImeOnly()) { 7790 return FINISH_NOT_HANDLED; 7791 } 7792 return FORWARD; 7793 } 7794 } 7795 7796 /** 7797 * Delivers input events to the ime. 7798 * Does not support pointer events. 7799 */ 7800 final class ImeInputStage extends AsyncInputStage 7801 implements InputMethodManager.FinishedInputEventCallback { ImeInputStage(InputStage next, String traceCounter)7802 public ImeInputStage(InputStage next, String traceCounter) { 7803 super(next, traceCounter); 7804 } 7805 7806 @Override onProcess(QueuedInputEvent q)7807 protected int onProcess(QueuedInputEvent q) { 7808 final int result = mImeFocusController.onProcessImeInputStage( 7809 q, q.mEvent, mWindowAttributes, this); 7810 switch (result) { 7811 case InputMethodManager.DISPATCH_IN_PROGRESS: 7812 // callback will be invoked later 7813 return DEFER; 7814 case InputMethodManager.DISPATCH_NOT_HANDLED: 7815 // The IME could not handle it, so skip along to the next InputStage 7816 return FORWARD; 7817 case InputMethodManager.DISPATCH_HANDLED: 7818 return FINISH_HANDLED; 7819 default: 7820 throw new IllegalStateException("Unexpected result=" + result); 7821 } 7822 } 7823 7824 @Override onFinishedInputEvent(Object token, boolean handled)7825 public void onFinishedInputEvent(Object token, boolean handled) { 7826 QueuedInputEvent q = (QueuedInputEvent)token; 7827 if (handled) { 7828 finish(q, true); 7829 return; 7830 } 7831 forward(q); 7832 } 7833 } 7834 7835 /** 7836 * Performs early processing of post-ime input events. 7837 */ 7838 final class EarlyPostImeInputStage extends InputStage { EarlyPostImeInputStage(InputStage next)7839 public EarlyPostImeInputStage(InputStage next) { 7840 super(next); 7841 } 7842 7843 @Override onProcess(QueuedInputEvent q)7844 protected int onProcess(QueuedInputEvent q) { 7845 if (q.mEvent instanceof KeyEvent) { 7846 return processKeyEvent(q); 7847 } else if (q.mEvent instanceof MotionEvent) { 7848 return processMotionEvent(q); 7849 } 7850 return FORWARD; 7851 } 7852 processKeyEvent(QueuedInputEvent q)7853 private int processKeyEvent(QueuedInputEvent q) { 7854 final KeyEvent event = (KeyEvent)q.mEvent; 7855 7856 if (mAttachInfo.mTooltipHost != null) { 7857 mAttachInfo.mTooltipHost.handleTooltipKey(event); 7858 } 7859 7860 // If the key's purpose is to exit touch mode then we consume it 7861 // and consider it handled. 7862 if (checkForLeavingTouchModeAndConsume(event)) { 7863 return FINISH_HANDLED; 7864 } 7865 7866 // Make sure the fallback event policy sees all keys that will be 7867 // delivered to the view hierarchy. 7868 mFallbackEventHandler.preDispatchKeyEvent(event); 7869 7870 // Reset last tracked MotionEvent click toolType. 7871 if (event.getAction() == KeyEvent.ACTION_DOWN) { 7872 mLastClickToolType = MotionEvent.TOOL_TYPE_UNKNOWN; 7873 } 7874 7875 return FORWARD; 7876 } 7877 processMotionEvent(QueuedInputEvent q)7878 private int processMotionEvent(QueuedInputEvent q) { 7879 final MotionEvent event = (MotionEvent) q.mEvent; 7880 7881 if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 7882 return processPointerEvent(q); 7883 } 7884 7885 // If the motion event is from an absolute position device, exit touch mode 7886 final int action = event.getActionMasked(); 7887 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) { 7888 if (event.isFromSource(InputDevice.SOURCE_CLASS_POSITION)) { 7889 ensureTouchMode(false); 7890 } 7891 } 7892 return FORWARD; 7893 } 7894 processPointerEvent(QueuedInputEvent q)7895 private int processPointerEvent(QueuedInputEvent q) { 7896 final MotionEvent event = (MotionEvent)q.mEvent; 7897 7898 // Translate the pointer event for compatibility, if needed. 7899 if (mTranslator != null) { 7900 mTranslator.translateEventInScreenToAppWindow(event); 7901 } 7902 7903 // Enter touch mode on down or scroll from any type of a device. 7904 final int action = event.getAction(); 7905 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) { 7906 ensureTouchMode(true); 7907 } 7908 7909 if (action == MotionEvent.ACTION_DOWN) { 7910 // Upon motion event within app window, close autofill ui. 7911 AutofillManager afm = getAutofillManager(); 7912 if (afm != null) { 7913 afm.requestHideFillUi(); 7914 } 7915 } 7916 7917 if (action == MotionEvent.ACTION_DOWN && mAttachInfo.mTooltipHost != null) { 7918 mAttachInfo.mTooltipHost.hideTooltip(); 7919 } 7920 7921 // Offset the scroll position. 7922 if (mCurScrollY != 0) { 7923 event.offsetLocation(0, mCurScrollY); 7924 } 7925 7926 if (event.isTouchEvent()) { 7927 // Remember the touch position for possible drag-initiation. 7928 mLastTouchPoint.x = event.getRawX(); 7929 mLastTouchPoint.y = event.getRawY(); 7930 mLastTouchSource = event.getSource(); 7931 mLastTouchDeviceId = event.getDeviceId(); 7932 mLastTouchPointerId = event.getPointerId(0); 7933 7934 // Register last ACTION_UP. This will be propagated to IME. 7935 if (event.getActionMasked() == MotionEvent.ACTION_UP) { 7936 mLastClickToolType = event.getToolType(event.getActionIndex()); 7937 } 7938 } 7939 return FORWARD; 7940 } 7941 } 7942 7943 /** 7944 * Delivers post-ime input events to a native activity. 7945 */ 7946 final class NativePostImeInputStage extends AsyncInputStage 7947 implements InputQueue.FinishedInputEventCallback { NativePostImeInputStage(InputStage next, String traceCounter)7948 public NativePostImeInputStage(InputStage next, String traceCounter) { 7949 super(next, traceCounter); 7950 } 7951 7952 @Override onProcess(QueuedInputEvent q)7953 protected int onProcess(QueuedInputEvent q) { 7954 if (mInputQueue != null) { 7955 mInputQueue.sendInputEvent(q.mEvent, q, false, this); 7956 return DEFER; 7957 } 7958 return FORWARD; 7959 } 7960 7961 @Override onFinishedInputEvent(Object token, boolean handled)7962 public void onFinishedInputEvent(Object token, boolean handled) { 7963 QueuedInputEvent q = (QueuedInputEvent)token; 7964 if (handled) { 7965 finish(q, true); 7966 return; 7967 } 7968 forward(q); 7969 } 7970 } 7971 7972 /** 7973 * Delivers post-ime input events to the view hierarchy. 7974 */ 7975 final class ViewPostImeInputStage extends InputStage { ViewPostImeInputStage(InputStage next)7976 public ViewPostImeInputStage(InputStage next) { 7977 super(next); 7978 } 7979 7980 @Override onProcess(QueuedInputEvent q)7981 protected int onProcess(QueuedInputEvent q) { 7982 if (q.mEvent instanceof KeyEvent) { 7983 return processKeyEvent(q); 7984 } else { 7985 final int source = q.mEvent.getSource(); 7986 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 7987 return processPointerEvent(q); 7988 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { 7989 return processTrackballEvent(q); 7990 } else { 7991 return processGenericMotionEvent(q); 7992 } 7993 } 7994 } 7995 7996 @Override onDeliverToNext(QueuedInputEvent q)7997 protected void onDeliverToNext(QueuedInputEvent q) { 7998 if (mUnbufferedInputDispatch 7999 && q.mEvent instanceof MotionEvent 8000 && ((MotionEvent)q.mEvent).isTouchEvent() 8001 && isTerminalInputEvent(q.mEvent)) { 8002 mUnbufferedInputDispatch = false; 8003 scheduleConsumeBatchedInput(); 8004 } 8005 super.onDeliverToNext(q); 8006 } 8007 performFocusNavigation(KeyEvent event)8008 private boolean performFocusNavigation(KeyEvent event) { 8009 @FocusDirection int direction = 0; 8010 switch (event.getKeyCode()) { 8011 case KeyEvent.KEYCODE_DPAD_LEFT: 8012 if (event.hasNoModifiers()) { 8013 direction = View.FOCUS_LEFT; 8014 } 8015 break; 8016 case KeyEvent.KEYCODE_DPAD_RIGHT: 8017 if (event.hasNoModifiers()) { 8018 direction = View.FOCUS_RIGHT; 8019 } 8020 break; 8021 case KeyEvent.KEYCODE_DPAD_UP: 8022 if (event.hasNoModifiers()) { 8023 direction = View.FOCUS_UP; 8024 } 8025 break; 8026 case KeyEvent.KEYCODE_DPAD_DOWN: 8027 if (event.hasNoModifiers()) { 8028 direction = View.FOCUS_DOWN; 8029 } 8030 break; 8031 case KeyEvent.KEYCODE_TAB: 8032 if (event.hasNoModifiers()) { 8033 direction = View.FOCUS_FORWARD; 8034 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) { 8035 direction = View.FOCUS_BACKWARD; 8036 } 8037 break; 8038 } 8039 if (direction != 0) { 8040 View focused = mView.findFocus(); 8041 if (focused != null) { 8042 mAttachInfo.mNextFocusLooped = false; 8043 View v = focused.focusSearch(direction); 8044 if (v != null && v != focused) { 8045 if (mAttachInfo.mNextFocusLooped) { 8046 // The next focus is looped. Let's try to move the focus to the adjacent 8047 // window. Note: we still need to move the focus in this window 8048 // regardless of what moveFocusToAdjacentWindow returns, so the focus 8049 // can be looped back from the focus in the adjacent window to next 8050 // focus of this window. 8051 moveFocusToAdjacentWindow(direction); 8052 } 8053 8054 // do the math the get the interesting rect 8055 // of previous focused into the coord system of 8056 // newly focused view 8057 focused.getFocusedRect(mTempRect); 8058 if (mView instanceof ViewGroup) { 8059 ((ViewGroup) mView).offsetDescendantRectToMyCoords( 8060 focused, mTempRect); 8061 ((ViewGroup) mView).offsetRectIntoDescendantCoords( 8062 v, mTempRect); 8063 } 8064 if (v.requestFocus(direction, mTempRect)) { 8065 boolean isFastScrolling = event.getRepeatCount() > 0; 8066 playSoundEffect( 8067 SoundEffectConstants.getConstantForFocusDirection(direction, 8068 isFastScrolling)); 8069 return true; 8070 } 8071 } else if (moveFocusToAdjacentWindow(direction)) { 8072 return true; 8073 } 8074 8075 // Give the focused view a last chance to handle the dpad key. 8076 if (mView.dispatchUnhandledMove(focused, direction)) { 8077 return true; 8078 } 8079 } else { 8080 if (mView.restoreDefaultFocus()) { 8081 return true; 8082 } else if (moveFocusToAdjacentWindow(direction)) { 8083 return true; 8084 } 8085 } 8086 } 8087 return false; 8088 } 8089 moveFocusToAdjacentWindow(@ocusDirection int direction)8090 private boolean moveFocusToAdjacentWindow(@FocusDirection int direction) { 8091 final int windowingMode = getConfiguration().windowConfiguration.getWindowingMode(); 8092 if (windowingMode != WINDOWING_MODE_MULTI_WINDOW 8093 && windowingMode != WINDOWING_MODE_FREEFORM) { 8094 return false; 8095 } 8096 try { 8097 return mWindowSession.moveFocusToAdjacentWindow(mWindow, direction); 8098 } catch (RemoteException e) { 8099 return false; 8100 } 8101 } 8102 performKeyboardGroupNavigation(int direction)8103 private boolean performKeyboardGroupNavigation(int direction) { 8104 final View focused = mView.findFocus(); 8105 if (focused == null && mView.restoreDefaultFocus()) { 8106 return true; 8107 } 8108 View cluster = focused == null ? keyboardNavigationClusterSearch(null, direction) 8109 : focused.keyboardNavigationClusterSearch(null, direction); 8110 8111 // Since requestFocus only takes "real" focus directions (and therefore also 8112 // restoreFocusInCluster), convert forward/backward focus into FOCUS_DOWN. 8113 int realDirection = direction; 8114 if (direction == View.FOCUS_FORWARD || direction == View.FOCUS_BACKWARD) { 8115 realDirection = View.FOCUS_DOWN; 8116 } 8117 8118 if (cluster != null && cluster.isRootNamespace()) { 8119 // the default cluster. Try to find a non-clustered view to focus. 8120 if (cluster.restoreFocusNotInCluster()) { 8121 playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction)); 8122 return true; 8123 } 8124 // otherwise skip to next actual cluster 8125 cluster = keyboardNavigationClusterSearch(null, direction); 8126 } 8127 8128 if (cluster != null && cluster.restoreFocusInCluster(realDirection)) { 8129 playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction)); 8130 return true; 8131 } 8132 8133 return false; 8134 } 8135 processKeyEvent(QueuedInputEvent q)8136 private int processKeyEvent(QueuedInputEvent q) { 8137 final KeyEvent event = (KeyEvent)q.mEvent; 8138 8139 if (mUnhandledKeyManager.preViewDispatch(event)) { 8140 return FINISH_HANDLED; 8141 } 8142 8143 // Deliver the key to the view hierarchy. 8144 if (mView.dispatchKeyEvent(event)) { 8145 return FINISH_HANDLED; 8146 } 8147 8148 if (shouldDropInputEvent(q)) { 8149 return FINISH_NOT_HANDLED; 8150 } 8151 8152 // This dispatch is for windows that don't have a Window.Callback. Otherwise, 8153 // the Window.Callback usually will have already called this (see 8154 // DecorView.superDispatchKeyEvent) leaving this call a no-op. 8155 if (mUnhandledKeyManager.dispatch(mView, event)) { 8156 return FINISH_HANDLED; 8157 } 8158 8159 int groupNavigationDirection = 0; 8160 8161 if (event.getAction() == KeyEvent.ACTION_DOWN 8162 && event.getKeyCode() == KeyEvent.KEYCODE_TAB) { 8163 if (KeyEvent.metaStateHasModifiers(event.getMetaState(), KeyEvent.META_CTRL_ON)) { 8164 groupNavigationDirection = View.FOCUS_FORWARD; 8165 } else if (KeyEvent.metaStateHasModifiers(event.getMetaState(), 8166 KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)) { 8167 groupNavigationDirection = View.FOCUS_BACKWARD; 8168 } 8169 } 8170 8171 // If a modifier is held, try to interpret the key as a shortcut. 8172 if (event.getAction() == KeyEvent.ACTION_DOWN 8173 && !KeyEvent.metaStateHasNoModifiers(event.getMetaState()) 8174 && event.getRepeatCount() == 0 8175 && !KeyEvent.isModifierKey(event.getKeyCode()) 8176 && groupNavigationDirection == 0) { 8177 if (mView.dispatchKeyShortcutEvent(event)) { 8178 return FINISH_HANDLED; 8179 } 8180 if (shouldDropInputEvent(q)) { 8181 return FINISH_NOT_HANDLED; 8182 } 8183 } 8184 8185 // Apply the fallback event policy. 8186 if (mFallbackEventHandler.dispatchKeyEvent(event)) { 8187 return FINISH_HANDLED; 8188 } 8189 if (shouldDropInputEvent(q)) { 8190 return FINISH_NOT_HANDLED; 8191 } 8192 8193 // Handle automatic focus changes. 8194 if (event.getAction() == KeyEvent.ACTION_DOWN) { 8195 if (groupNavigationDirection != 0) { 8196 if (performKeyboardGroupNavigation(groupNavigationDirection)) { 8197 return FINISH_HANDLED; 8198 } 8199 } else { 8200 if (performFocusNavigation(event)) { 8201 return FINISH_HANDLED; 8202 } 8203 } 8204 } 8205 return FORWARD; 8206 } 8207 processPointerEvent(QueuedInputEvent q)8208 private int processPointerEvent(QueuedInputEvent q) { 8209 final MotionEvent event = (MotionEvent)q.mEvent; 8210 final int action = event.getAction(); 8211 if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { 8212 mIsPressedGesture = false; 8213 } 8214 boolean handled = false; 8215 if (!disableHandwritingInitiatorForIme() 8216 || mWindowAttributes.type != TYPE_INPUT_METHOD) { 8217 handled = mHandwritingInitiator.onTouchEvent(event); 8218 } 8219 if (handled) { 8220 // If handwriting is started, toolkit doesn't receive ACTION_UP. 8221 mLastClickToolType = event.getToolType(event.getActionIndex()); 8222 } 8223 8224 mAttachInfo.mUnbufferedDispatchRequested = false; 8225 mAttachInfo.mHandlingPointerEvent = true; 8226 // If the event was fully handled by the handwriting initiator, then don't dispatch it 8227 // to the view tree. 8228 handled = handled || mView.dispatchPointerEvent(event); 8229 maybeUpdatePointerIcon(event); 8230 maybeUpdateTooltip(event); 8231 mAttachInfo.mHandlingPointerEvent = false; 8232 if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) { 8233 mUnbufferedInputDispatch = true; 8234 if (mConsumeBatchedInputScheduled) { 8235 scheduleConsumeBatchedInputImmediately(); 8236 } 8237 } 8238 8239 // For the variable refresh rate project 8240 if (handled && shouldTouchBoost(action & MotionEvent.ACTION_MASK, 8241 mWindowAttributes.type)) { 8242 // set the frame rate to the maximum value. 8243 mIsTouchBoosting = true; 8244 if (action == MotionEvent.ACTION_DOWN) { 8245 mIsPressedGesture = true; 8246 } 8247 setPreferredFrameRateCategory(mLastPreferredFrameRateCategory); 8248 } 8249 /** 8250 * We want to lower the refresh rate when MotionEvent.ACTION_UP, 8251 * MotionEvent.ACTION_CANCEL is detected. 8252 * Not using ACTION_MOVE to avoid checking and sending messages too frequently. 8253 */ 8254 if (mIsTouchBoosting && (action == MotionEvent.ACTION_UP 8255 || action == MotionEvent.ACTION_CANCEL)) { 8256 8257 if (sToolkitInitialTouchBoostFlagValue) { 8258 mHandler.removeMessages(MSG_INITIAL_TOUCH_BOOST_TIMEOUT); 8259 mHandler.sendEmptyMessageDelayed(MSG_INITIAL_TOUCH_BOOST_TIMEOUT, 8260 FRAME_RATE_INITIAL_TOUCH_BOOST_TIME); 8261 } else { 8262 mHandler.removeMessages(MSG_TOUCH_BOOST_TIMEOUT); 8263 mHandler.sendEmptyMessageDelayed(MSG_TOUCH_BOOST_TIMEOUT, 8264 FRAME_RATE_TOUCH_BOOST_TIME); 8265 } 8266 } 8267 return handled ? FINISH_HANDLED : FORWARD; 8268 } 8269 maybeUpdatePointerIcon(MotionEvent event)8270 private void maybeUpdatePointerIcon(MotionEvent event) { 8271 if (event.getPointerCount() != 1) { 8272 return; 8273 } 8274 final int action = event.getActionMasked(); 8275 final boolean needsStylusPointerIcon = event.isStylusPointer() 8276 && event.isHoverEvent() 8277 && mIsStylusPointerIconEnabled; 8278 if (!needsStylusPointerIcon && !event.isFromSource(InputDevice.SOURCE_MOUSE)) { 8279 return; 8280 } 8281 8282 if (action == MotionEvent.ACTION_HOVER_ENTER 8283 || action == MotionEvent.ACTION_HOVER_EXIT) { 8284 // Other apps or the window manager may change the icon type outside of 8285 // this app, therefore the icon type has to be reset on enter/exit event. 8286 mResolvedPointerIcon = null; 8287 } 8288 8289 if (action != MotionEvent.ACTION_HOVER_EXIT) { 8290 // Resolve the pointer icon 8291 if (!updatePointerIcon(event) && action == MotionEvent.ACTION_HOVER_MOVE) { 8292 mResolvedPointerIcon = null; 8293 } 8294 } 8295 8296 // Keep track of the newest event used to resolve the pointer icon. 8297 switch (action) { 8298 case MotionEvent.ACTION_HOVER_EXIT: 8299 case MotionEvent.ACTION_UP: 8300 case MotionEvent.ACTION_POINTER_UP: 8301 case MotionEvent.ACTION_CANCEL: 8302 if (mPointerIconEvent != null) { 8303 mPointerIconEvent.recycle(); 8304 } 8305 mPointerIconEvent = null; 8306 break; 8307 default: 8308 mPointerIconEvent = MotionEvent.obtain(event); 8309 break; 8310 } 8311 } 8312 processTrackballEvent(QueuedInputEvent q)8313 private int processTrackballEvent(QueuedInputEvent q) { 8314 final MotionEvent event = (MotionEvent)q.mEvent; 8315 8316 if (event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) { 8317 if (!hasPointerCapture() || mView.dispatchCapturedPointerEvent(event)) { 8318 return FINISH_HANDLED; 8319 } 8320 } 8321 8322 if (mView.dispatchTrackballEvent(event)) { 8323 return FINISH_HANDLED; 8324 } 8325 return FORWARD; 8326 } 8327 processGenericMotionEvent(QueuedInputEvent q)8328 private int processGenericMotionEvent(QueuedInputEvent q) { 8329 final MotionEvent event = (MotionEvent)q.mEvent; 8330 8331 if (event.isFromSource(InputDevice.SOURCE_TOUCHPAD)) { 8332 if (hasPointerCapture() && mView.dispatchCapturedPointerEvent(event)) { 8333 return FINISH_HANDLED; 8334 } 8335 } 8336 8337 // Deliver the event to the view. 8338 if (mView.dispatchGenericMotionEvent(event)) { 8339 return FINISH_HANDLED; 8340 } 8341 return FORWARD; 8342 } 8343 } 8344 8345 /** 8346 * Returns whether this view is currently handling a pointer event. 8347 * 8348 * @hide 8349 */ isHandlingPointerEvent()8350 public boolean isHandlingPointerEvent() { 8351 return mAttachInfo.mHandlingPointerEvent; 8352 } 8353 8354 8355 /** 8356 * If there is pointer that is showing a PointerIcon in this window, refresh the icon for that 8357 * pointer. This will resolve the PointerIcon through the view hierarchy. 8358 */ refreshPointerIcon()8359 public void refreshPointerIcon() { 8360 mHandler.removeMessages(MSG_REFRESH_POINTER_ICON); 8361 mHandler.sendEmptyMessage(MSG_REFRESH_POINTER_ICON); 8362 } 8363 updatePointerIcon(MotionEvent event)8364 private boolean updatePointerIcon(MotionEvent event) { 8365 final int pointerIndex = 0; 8366 final float x = event.getX(pointerIndex); 8367 final float y = event.getY(pointerIndex); 8368 if (mView == null) { 8369 // E.g. click outside a popup to dismiss it 8370 Slog.d(mTag, "updatePointerIcon called after view was removed"); 8371 return false; 8372 } 8373 if (x < 0 || x >= mView.getWidth() || y < 0 || y >= mView.getHeight()) { 8374 // E.g. when moving window divider with mouse 8375 Slog.d(mTag, "updatePointerIcon called with position out of bounds"); 8376 return false; 8377 } 8378 8379 PointerIcon pointerIcon = null; 8380 if (event.isStylusPointer() && mIsStylusPointerIconEnabled 8381 && (!disableHandwritingInitiatorForIme() 8382 || mWindowAttributes.type != TYPE_INPUT_METHOD)) { 8383 pointerIcon = mHandwritingInitiator.onResolvePointerIcon(mContext, event); 8384 } 8385 if (pointerIcon == null) { 8386 pointerIcon = mView.onResolvePointerIcon(event, pointerIndex); 8387 } 8388 if (pointerIcon == null) { 8389 pointerIcon = PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_NOT_SPECIFIED); 8390 } 8391 if (Objects.equals(mResolvedPointerIcon, pointerIcon)) { 8392 return true; 8393 } 8394 mResolvedPointerIcon = pointerIcon; 8395 8396 InputManagerGlobal.getInstance() 8397 .setPointerIcon(pointerIcon, event.getDisplayId(), 8398 event.getDeviceId(), event.getPointerId(0), getInputToken()); 8399 return true; 8400 } 8401 maybeUpdateTooltip(MotionEvent event)8402 private void maybeUpdateTooltip(MotionEvent event) { 8403 if (event.getPointerCount() != 1) { 8404 return; 8405 } 8406 final int action = event.getActionMasked(); 8407 if (action != MotionEvent.ACTION_HOVER_ENTER 8408 && action != MotionEvent.ACTION_HOVER_MOVE 8409 && action != MotionEvent.ACTION_HOVER_EXIT) { 8410 return; 8411 } 8412 if (mAccessibilityManager.isEnabled() 8413 && mAccessibilityManager.isTouchExplorationEnabled()) { 8414 return; 8415 } 8416 if (mView == null) { 8417 Slog.d(mTag, "maybeUpdateTooltip called after view was removed"); 8418 return; 8419 } 8420 mView.dispatchTooltipHoverEvent(event); 8421 } 8422 8423 @Nullable getFocusedViewOrNull()8424 private View getFocusedViewOrNull() { 8425 return mView != null ? mView.findFocus() : null; 8426 } 8427 8428 /** 8429 * Performs synthesis of new input events from unhandled input events. 8430 */ 8431 final class SyntheticInputStage extends InputStage { 8432 private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler(); 8433 private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler(); 8434 private final SyntheticTouchNavigationHandler mTouchNavigation = 8435 new SyntheticTouchNavigationHandler(); 8436 private final SyntheticKeyboardHandler mKeyboard = new SyntheticKeyboardHandler(); 8437 SyntheticInputStage()8438 public SyntheticInputStage() { 8439 super(null); 8440 } 8441 8442 @Override onProcess(QueuedInputEvent q)8443 protected int onProcess(QueuedInputEvent q) { 8444 q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED; 8445 if (q.mEvent instanceof MotionEvent) { 8446 final MotionEvent event = (MotionEvent)q.mEvent; 8447 final int source = event.getSource(); 8448 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { 8449 // Do not synthesize events for relative mouse movement. If apps opt into 8450 // relative mouse movement they must be prepared to handle the events. 8451 if (!event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) { 8452 mTrackball.process(event); 8453 } 8454 return FINISH_HANDLED; 8455 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { 8456 mJoystick.process(event); 8457 return FINISH_HANDLED; 8458 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION) 8459 == InputDevice.SOURCE_TOUCH_NAVIGATION) { 8460 mTouchNavigation.process(event); 8461 return FINISH_HANDLED; 8462 } 8463 } else if ((q.mFlags & QueuedInputEvent.FLAG_UNHANDLED) != 0) { 8464 mKeyboard.process((KeyEvent)q.mEvent); 8465 return FINISH_HANDLED; 8466 } 8467 8468 return FORWARD; 8469 } 8470 8471 @Override onDeliverToNext(QueuedInputEvent q)8472 protected void onDeliverToNext(QueuedInputEvent q) { 8473 if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) { 8474 // Cancel related synthetic events if any prior stage has handled the event. 8475 if (q.mEvent instanceof MotionEvent) { 8476 final MotionEvent event = (MotionEvent)q.mEvent; 8477 final int source = event.getSource(); 8478 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { 8479 mTrackball.cancel(); 8480 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { 8481 mJoystick.cancel(); 8482 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION) 8483 == InputDevice.SOURCE_TOUCH_NAVIGATION) { 8484 // Touch navigation events cannot be cancelled since they are dispatched 8485 // immediately. 8486 } 8487 } 8488 } 8489 super.onDeliverToNext(q); 8490 } 8491 8492 @Override onWindowFocusChanged(boolean hasWindowFocus)8493 protected void onWindowFocusChanged(boolean hasWindowFocus) { 8494 if (!hasWindowFocus) { 8495 mJoystick.cancel(); 8496 } 8497 } 8498 8499 @Override onDetachedFromWindow()8500 protected void onDetachedFromWindow() { 8501 mJoystick.cancel(); 8502 } 8503 } 8504 8505 /** 8506 * Creates dpad events from unhandled trackball movements. 8507 */ 8508 final class SyntheticTrackballHandler { 8509 private final TrackballAxis mX = new TrackballAxis(); 8510 private final TrackballAxis mY = new TrackballAxis(); 8511 private long mLastTime; 8512 process(MotionEvent event)8513 public void process(MotionEvent event) { 8514 // Translate the trackball event into DPAD keys and try to deliver those. 8515 long curTime = SystemClock.uptimeMillis(); 8516 if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) { 8517 // It has been too long since the last movement, 8518 // so restart at the beginning. 8519 mX.reset(0); 8520 mY.reset(0); 8521 mLastTime = curTime; 8522 } 8523 8524 final int action = event.getAction(); 8525 final int metaState = event.getMetaState(); 8526 switch (action) { 8527 case MotionEvent.ACTION_DOWN: 8528 mX.reset(2); 8529 mY.reset(2); 8530 enqueueInputEvent(new KeyEvent(curTime, curTime, 8531 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState, 8532 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, 8533 InputDevice.SOURCE_KEYBOARD)); 8534 break; 8535 case MotionEvent.ACTION_UP: 8536 mX.reset(2); 8537 mY.reset(2); 8538 enqueueInputEvent(new KeyEvent(curTime, curTime, 8539 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState, 8540 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, 8541 InputDevice.SOURCE_KEYBOARD)); 8542 break; 8543 } 8544 8545 if (DEBUG_TRACKBALL) Log.v(mTag, "TB X=" + mX.position + " step=" 8546 + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration 8547 + " move=" + event.getX() 8548 + " / Y=" + mY.position + " step=" 8549 + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration 8550 + " move=" + event.getY()); 8551 final float xOff = mX.collect(event.getX(), event.getEventTime(), "X"); 8552 final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y"); 8553 8554 // Generate DPAD events based on the trackball movement. 8555 // We pick the axis that has moved the most as the direction of 8556 // the DPAD. When we generate DPAD events for one axis, then the 8557 // other axis is reset -- we don't want to perform DPAD jumps due 8558 // to slight movements in the trackball when making major movements 8559 // along the other axis. 8560 int keycode = 0; 8561 int movement = 0; 8562 float accel = 1; 8563 if (xOff > yOff) { 8564 movement = mX.generate(); 8565 if (movement != 0) { 8566 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT 8567 : KeyEvent.KEYCODE_DPAD_LEFT; 8568 accel = mX.acceleration; 8569 mY.reset(2); 8570 } 8571 } else if (yOff > 0) { 8572 movement = mY.generate(); 8573 if (movement != 0) { 8574 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN 8575 : KeyEvent.KEYCODE_DPAD_UP; 8576 accel = mY.acceleration; 8577 mX.reset(2); 8578 } 8579 } 8580 8581 if (keycode != 0) { 8582 if (movement < 0) movement = -movement; 8583 int accelMovement = (int)(movement * accel); 8584 if (DEBUG_TRACKBALL) Log.v(mTag, "Move: movement=" + movement 8585 + " accelMovement=" + accelMovement 8586 + " accel=" + accel); 8587 if (accelMovement > movement) { 8588 if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: " 8589 + keycode); 8590 movement--; 8591 int repeatCount = accelMovement - movement; 8592 enqueueInputEvent(new KeyEvent(curTime, curTime, 8593 KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState, 8594 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, 8595 InputDevice.SOURCE_KEYBOARD)); 8596 } 8597 while (movement > 0) { 8598 if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: " 8599 + keycode); 8600 movement--; 8601 curTime = SystemClock.uptimeMillis(); 8602 enqueueInputEvent(new KeyEvent(curTime, curTime, 8603 KeyEvent.ACTION_DOWN, keycode, 0, metaState, 8604 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, 8605 InputDevice.SOURCE_KEYBOARD)); 8606 enqueueInputEvent(new KeyEvent(curTime, curTime, 8607 KeyEvent.ACTION_UP, keycode, 0, metaState, 8608 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, 8609 InputDevice.SOURCE_KEYBOARD)); 8610 } 8611 mLastTime = curTime; 8612 } 8613 } 8614 cancel()8615 public void cancel() { 8616 mLastTime = Integer.MIN_VALUE; 8617 8618 // If we reach this, we consumed a trackball event. 8619 // Because we will not translate the trackball event into a key event, 8620 // touch mode will not exit, so we exit touch mode here. 8621 if (mView != null && mAdded) { 8622 ensureTouchMode(false); 8623 } 8624 } 8625 } 8626 8627 /** 8628 * Maintains state information for a single trackball axis, generating 8629 * discrete (DPAD) movements based on raw trackball motion. 8630 */ 8631 static final class TrackballAxis { 8632 /** 8633 * The maximum amount of acceleration we will apply. 8634 */ 8635 static final float MAX_ACCELERATION = 20; 8636 8637 /** 8638 * The maximum amount of time (in milliseconds) between events in order 8639 * for us to consider the user to be doing fast trackball movements, 8640 * and thus apply an acceleration. 8641 */ 8642 static final long FAST_MOVE_TIME = 150; 8643 8644 /** 8645 * Scaling factor to the time (in milliseconds) between events to how 8646 * much to multiple/divide the current acceleration. When movement 8647 * is < FAST_MOVE_TIME this multiplies the acceleration; when > 8648 * FAST_MOVE_TIME it divides it. 8649 */ 8650 static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40); 8651 8652 static final float FIRST_MOVEMENT_THRESHOLD = 0.5f; 8653 static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f; 8654 static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f; 8655 8656 float position; 8657 float acceleration = 1; 8658 long lastMoveTime = 0; 8659 int step; 8660 int dir; 8661 int nonAccelMovement; 8662 reset(int _step)8663 void reset(int _step) { 8664 position = 0; 8665 acceleration = 1; 8666 lastMoveTime = 0; 8667 step = _step; 8668 dir = 0; 8669 } 8670 8671 /** 8672 * Add trackball movement into the state. If the direction of movement 8673 * has been reversed, the state is reset before adding the 8674 * movement (so that you don't have to compensate for any previously 8675 * collected movement before see the result of the movement in the 8676 * new direction). 8677 * 8678 * @return Returns the absolute value of the amount of movement 8679 * collected so far. 8680 */ collect(float off, long time, String axis)8681 float collect(float off, long time, String axis) { 8682 long normTime; 8683 if (off > 0) { 8684 normTime = (long)(off * FAST_MOVE_TIME); 8685 if (dir < 0) { 8686 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!"); 8687 position = 0; 8688 step = 0; 8689 acceleration = 1; 8690 lastMoveTime = 0; 8691 } 8692 dir = 1; 8693 } else if (off < 0) { 8694 normTime = (long)((-off) * FAST_MOVE_TIME); 8695 if (dir > 0) { 8696 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!"); 8697 position = 0; 8698 step = 0; 8699 acceleration = 1; 8700 lastMoveTime = 0; 8701 } 8702 dir = -1; 8703 } else { 8704 normTime = 0; 8705 } 8706 8707 // The number of milliseconds between each movement that is 8708 // considered "normal" and will not result in any acceleration 8709 // or deceleration, scaled by the offset we have here. 8710 if (normTime > 0) { 8711 long delta = time - lastMoveTime; 8712 lastMoveTime = time; 8713 float acc = acceleration; 8714 if (delta < normTime) { 8715 // The user is scrolling rapidly, so increase acceleration. 8716 float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR; 8717 if (scale > 1) acc *= scale; 8718 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off=" 8719 + off + " normTime=" + normTime + " delta=" + delta 8720 + " scale=" + scale + " acc=" + acc); 8721 acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION; 8722 } else { 8723 // The user is scrolling slowly, so decrease acceleration. 8724 float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR; 8725 if (scale > 1) acc /= scale; 8726 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off=" 8727 + off + " normTime=" + normTime + " delta=" + delta 8728 + " scale=" + scale + " acc=" + acc); 8729 acceleration = acc > 1 ? acc : 1; 8730 } 8731 } 8732 position += off; 8733 return Math.abs(position); 8734 } 8735 8736 /** 8737 * Generate the number of discrete movement events appropriate for 8738 * the currently collected trackball movement. 8739 * 8740 * @return Returns the number of discrete movements, either positive 8741 * or negative, or 0 if there is not enough trackball movement yet 8742 * for a discrete movement. 8743 */ generate()8744 int generate() { 8745 int movement = 0; 8746 nonAccelMovement = 0; 8747 do { 8748 final int dir = position >= 0 ? 1 : -1; 8749 switch (step) { 8750 // If we are going to execute the first step, then we want 8751 // to do this as soon as possible instead of waiting for 8752 // a full movement, in order to make things look responsive. 8753 case 0: 8754 if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) { 8755 return movement; 8756 } 8757 movement += dir; 8758 nonAccelMovement += dir; 8759 step = 1; 8760 break; 8761 // If we have generated the first movement, then we need 8762 // to wait for the second complete trackball motion before 8763 // generating the second discrete movement. 8764 case 1: 8765 if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) { 8766 return movement; 8767 } 8768 movement += dir; 8769 nonAccelMovement += dir; 8770 position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir; 8771 step = 2; 8772 break; 8773 // After the first two, we generate discrete movements 8774 // consistently with the trackball, applying an acceleration 8775 // if the trackball is moving quickly. This is a simple 8776 // acceleration on top of what we already compute based 8777 // on how quickly the wheel is being turned, to apply 8778 // a longer increasing acceleration to continuous movement 8779 // in one direction. 8780 default: 8781 if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) { 8782 return movement; 8783 } 8784 movement += dir; 8785 position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD; 8786 float acc = acceleration; 8787 acc *= 1.1f; 8788 acceleration = acc < MAX_ACCELERATION ? acc : acceleration; 8789 break; 8790 } 8791 } while (true); 8792 } 8793 } 8794 8795 /** 8796 * Creates dpad events from unhandled joystick movements. 8797 */ 8798 final class SyntheticJoystickHandler extends Handler { 8799 private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1; 8800 private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2; 8801 8802 private final JoystickAxesState mJoystickAxesState = new JoystickAxesState(); 8803 private final SparseArray<KeyEvent> mDeviceKeyEvents = new SparseArray<>(); 8804 8805 public SyntheticJoystickHandler() { 8806 super(true); 8807 } 8808 8809 @Override 8810 public void handleMessage(Message msg) { 8811 switch (msg.what) { 8812 case MSG_ENQUEUE_X_AXIS_KEY_REPEAT: 8813 case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: { 8814 if (mAttachInfo.mHasWindowFocus) { 8815 KeyEvent oldEvent = (KeyEvent) msg.obj; 8816 KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent, 8817 SystemClock.uptimeMillis(), oldEvent.getRepeatCount() + 1); 8818 enqueueInputEvent(e); 8819 Message m = obtainMessage(msg.what, e); 8820 m.setAsynchronous(true); 8821 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay()); 8822 } 8823 } break; 8824 } 8825 } 8826 8827 public void process(MotionEvent event) { 8828 switch(event.getActionMasked()) { 8829 case MotionEvent.ACTION_CANCEL: 8830 cancel(); 8831 break; 8832 case MotionEvent.ACTION_MOVE: 8833 update(event); 8834 break; 8835 default: 8836 Log.w(mTag, "Unexpected action: " + event.getActionMasked()); 8837 } 8838 } 8839 8840 private void cancel() { 8841 removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT); 8842 removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT); 8843 for (int i = 0; i < mDeviceKeyEvents.size(); i++) { 8844 final KeyEvent keyEvent = mDeviceKeyEvents.valueAt(i); 8845 if (keyEvent != null) { 8846 enqueueInputEvent(KeyEvent.changeTimeRepeat(keyEvent, 8847 SystemClock.uptimeMillis(), 0)); 8848 } 8849 } 8850 mDeviceKeyEvents.clear(); 8851 mJoystickAxesState.resetState(); 8852 } 8853 8854 private void update(MotionEvent event) { 8855 final int historySize = event.getHistorySize(); 8856 for (int h = 0; h < historySize; h++) { 8857 final long time = event.getHistoricalEventTime(h); 8858 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X, 8859 event.getHistoricalAxisValue(MotionEvent.AXIS_X, 0, h)); 8860 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y, 8861 event.getHistoricalAxisValue(MotionEvent.AXIS_Y, 0, h)); 8862 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X, 8863 event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_X, 0, h)); 8864 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y, 8865 event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_Y, 0, h)); 8866 } 8867 final long time = event.getEventTime(); 8868 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X, 8869 event.getAxisValue(MotionEvent.AXIS_X)); 8870 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y, 8871 event.getAxisValue(MotionEvent.AXIS_Y)); 8872 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X, 8873 event.getAxisValue(MotionEvent.AXIS_HAT_X)); 8874 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y, 8875 event.getAxisValue(MotionEvent.AXIS_HAT_Y)); 8876 } 8877 8878 final class JoystickAxesState { 8879 // State machine: from neutral state (no button press) can go into 8880 // button STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state, emitting an ACTION_DOWN event. 8881 // From STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state can go into neutral state, 8882 // emitting an ACTION_UP event. 8883 private static final int STATE_UP_OR_LEFT = -1; 8884 private static final int STATE_NEUTRAL = 0; 8885 private static final int STATE_DOWN_OR_RIGHT = 1; 8886 8887 final int[] mAxisStatesHat = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_HAT_X, AXIS_HAT_Y} 8888 final int[] mAxisStatesStick = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_X, AXIS_Y} 8889 8890 void resetState() { 8891 mAxisStatesHat[0] = STATE_NEUTRAL; 8892 mAxisStatesHat[1] = STATE_NEUTRAL; 8893 mAxisStatesStick[0] = STATE_NEUTRAL; 8894 mAxisStatesStick[1] = STATE_NEUTRAL; 8895 } 8896 8897 void updateStateForAxis(MotionEvent event, long time, int axis, float value) { 8898 // Emit KeyEvent if necessary 8899 // axis can be AXIS_X, AXIS_Y, AXIS_HAT_X, AXIS_HAT_Y 8900 final int axisStateIndex; 8901 final int repeatMessage; 8902 if (isXAxis(axis)) { 8903 axisStateIndex = 0; 8904 repeatMessage = MSG_ENQUEUE_X_AXIS_KEY_REPEAT; 8905 } else if (isYAxis(axis)) { 8906 axisStateIndex = 1; 8907 repeatMessage = MSG_ENQUEUE_Y_AXIS_KEY_REPEAT; 8908 } else { 8909 Log.e(mTag, "Unexpected axis " + axis + " in updateStateForAxis!"); 8910 return; 8911 } 8912 final int newState = joystickAxisValueToState(value); 8913 8914 final int currentState; 8915 if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) { 8916 currentState = mAxisStatesStick[axisStateIndex]; 8917 } else { 8918 currentState = mAxisStatesHat[axisStateIndex]; 8919 } 8920 8921 if (currentState == newState) { 8922 return; 8923 } 8924 8925 final int metaState = event.getMetaState(); 8926 final int deviceId = event.getDeviceId(); 8927 final int source = event.getSource(); 8928 8929 if (currentState == STATE_DOWN_OR_RIGHT || currentState == STATE_UP_OR_LEFT) { 8930 // send a button release event 8931 final int keyCode = joystickAxisAndStateToKeycode(axis, currentState); 8932 if (keyCode != KeyEvent.KEYCODE_UNKNOWN) { 8933 enqueueInputEvent(new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode, 8934 0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source)); 8935 // remove the corresponding pending UP event if focus lost/view detached 8936 mDeviceKeyEvents.put(deviceId, null); 8937 } 8938 removeMessages(repeatMessage); 8939 } 8940 8941 if (newState == STATE_DOWN_OR_RIGHT || newState == STATE_UP_OR_LEFT) { 8942 // send a button down event 8943 final int keyCode = joystickAxisAndStateToKeycode(axis, newState); 8944 if (keyCode != KeyEvent.KEYCODE_UNKNOWN) { 8945 KeyEvent keyEvent = new KeyEvent(time, time, KeyEvent.ACTION_DOWN, keyCode, 8946 0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source); 8947 enqueueInputEvent(keyEvent); 8948 Message m = obtainMessage(repeatMessage, keyEvent); 8949 m.setAsynchronous(true); 8950 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout()); 8951 // store the corresponding ACTION_UP event so that it can be sent 8952 // if focus is lost or root view is removed 8953 mDeviceKeyEvents.put(deviceId, 8954 new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode, 8955 0, metaState, deviceId, 0, 8956 KeyEvent.FLAG_FALLBACK | KeyEvent.FLAG_CANCELED, 8957 source)); 8958 } 8959 } 8960 if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) { 8961 mAxisStatesStick[axisStateIndex] = newState; 8962 } else { 8963 mAxisStatesHat[axisStateIndex] = newState; 8964 } 8965 } 8966 8967 private boolean isXAxis(int axis) { 8968 return axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_HAT_X; 8969 } 8970 private boolean isYAxis(int axis) { 8971 return axis == MotionEvent.AXIS_Y || axis == MotionEvent.AXIS_HAT_Y; 8972 } 8973 8974 private int joystickAxisAndStateToKeycode(int axis, int state) { 8975 if (isXAxis(axis) && state == STATE_UP_OR_LEFT) { 8976 return KeyEvent.KEYCODE_DPAD_LEFT; 8977 } 8978 if (isXAxis(axis) && state == STATE_DOWN_OR_RIGHT) { 8979 return KeyEvent.KEYCODE_DPAD_RIGHT; 8980 } 8981 if (isYAxis(axis) && state == STATE_UP_OR_LEFT) { 8982 return KeyEvent.KEYCODE_DPAD_UP; 8983 } 8984 if (isYAxis(axis) && state == STATE_DOWN_OR_RIGHT) { 8985 return KeyEvent.KEYCODE_DPAD_DOWN; 8986 } 8987 Log.e(mTag, "Unknown axis " + axis + " or direction " + state); 8988 return KeyEvent.KEYCODE_UNKNOWN; // should never happen 8989 } 8990 8991 private int joystickAxisValueToState(float value) { 8992 if (value >= 0.5f) { 8993 return STATE_DOWN_OR_RIGHT; 8994 } else if (value <= -0.5f) { 8995 return STATE_UP_OR_LEFT; 8996 } else { 8997 return STATE_NEUTRAL; 8998 } 8999 } 9000 } 9001 } 9002 9003 /** 9004 * Creates DPAD events from unhandled touch navigation movements. 9005 */ 9006 final class SyntheticTouchNavigationHandler extends Handler { 9007 private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler"; 9008 9009 // The id of the input device that is being tracked. 9010 private int mCurrentDeviceId = -1; 9011 private int mCurrentSource; 9012 9013 private int mPendingKeyMetaState; 9014 9015 private final GestureDetector mGestureDetector; 9016 9017 SyntheticTouchNavigationHandler() { 9018 super(true); 9019 mGestureDetector = new GestureDetector(mContext, 9020 new GestureDetector.OnGestureListener() { 9021 @Override 9022 public boolean onDown(@NonNull MotionEvent e) { 9023 // This can be ignored since it's not clear what KeyEvent this will 9024 // belong to. 9025 return true; 9026 } 9027 9028 @Override 9029 public void onShowPress(@NonNull MotionEvent e) { 9030 } 9031 9032 @Override 9033 public boolean onSingleTapUp(@NonNull MotionEvent e) { 9034 dispatchTap(e.getEventTime()); 9035 return true; 9036 } 9037 9038 @Override 9039 public boolean onScroll(@Nullable MotionEvent e1, @NonNull MotionEvent e2, 9040 float distanceX, float distanceY) { 9041 // Scroll doesn't translate to DPAD events so should be ignored. 9042 return true; 9043 } 9044 9045 @Override 9046 public void onLongPress(@NonNull MotionEvent e) { 9047 // Long presses don't translate to DPAD events so should be ignored. 9048 } 9049 9050 @Override 9051 public boolean onFling(@Nullable MotionEvent e1, @NonNull MotionEvent e2, 9052 float velocityX, float velocityY) { 9053 dispatchFling(velocityX, velocityY, e2.getEventTime()); 9054 return true; 9055 } 9056 }, 9057 /* handler= */ null, 9058 VelocityTracker.VELOCITY_TRACKER_STRATEGY_IMPULSE); 9059 } 9060 9061 public void process(MotionEvent event) { 9062 if (event.getDevice() == null) { 9063 // The current device is not supported. 9064 if (DEBUG_TOUCH_NAVIGATION) { 9065 Log.d(LOCAL_TAG, 9066 "Current device not supported so motion event is not processed"); 9067 } 9068 return; 9069 } 9070 mPendingKeyMetaState = event.getMetaState(); 9071 // Update the current device information. 9072 final int deviceId = event.getDeviceId(); 9073 final int source = event.getSource(); 9074 if (mCurrentDeviceId != deviceId || mCurrentSource != source) { 9075 mCurrentDeviceId = deviceId; 9076 mCurrentSource = source; 9077 } 9078 9079 // Interpret the event. 9080 mGestureDetector.onTouchEvent(event); 9081 } 9082 9083 private void dispatchTap(long time) { 9084 dispatchEvent(time, KeyEvent.KEYCODE_DPAD_CENTER); 9085 } 9086 9087 private void dispatchFling(float x, float y, long time) { 9088 if (Math.abs(x) > Math.abs(y)) { 9089 dispatchEvent(time, 9090 x > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT); 9091 } else { 9092 dispatchEvent(time, y > 0 ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP); 9093 } 9094 } 9095 dispatchEvent(long time, int keyCode)9096 private void dispatchEvent(long time, int keyCode) { 9097 if (DEBUG_TOUCH_NAVIGATION) { 9098 Log.d(LOCAL_TAG, "Dispatching DPAD events DOWN and UP with keycode " + keyCode); 9099 } 9100 enqueueInputEvent(new KeyEvent(time, time, 9101 KeyEvent.ACTION_DOWN, keyCode, /* repeat= */ 0, mPendingKeyMetaState, 9102 mCurrentDeviceId, /* scancode= */ 0, KeyEvent.FLAG_FALLBACK, 9103 mCurrentSource)); 9104 enqueueInputEvent(new KeyEvent(time, time, 9105 KeyEvent.ACTION_UP, keyCode, /* repeat= */ 0, mPendingKeyMetaState, 9106 mCurrentDeviceId, /* scancode= */ 0, KeyEvent.FLAG_FALLBACK, 9107 mCurrentSource)); 9108 } 9109 } 9110 9111 final class SyntheticKeyboardHandler { process(KeyEvent event)9112 public void process(KeyEvent event) { 9113 if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) { 9114 return; 9115 } 9116 9117 final KeyCharacterMap kcm = event.getKeyCharacterMap(); 9118 final int keyCode = event.getKeyCode(); 9119 final int metaState = event.getMetaState(); 9120 9121 // Check for fallback actions specified by the key character map. 9122 KeyCharacterMap.FallbackAction fallbackAction = 9123 kcm.getFallbackAction(keyCode, metaState); 9124 if (fallbackAction != null) { 9125 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK; 9126 KeyEvent fallbackEvent = KeyEvent.obtain( 9127 event.getDownTime(), event.getEventTime(), 9128 event.getAction(), fallbackAction.keyCode, 9129 event.getRepeatCount(), fallbackAction.metaState, 9130 event.getDeviceId(), event.getScanCode(), 9131 flags, event.getSource(), null); 9132 fallbackAction.recycle(); 9133 enqueueInputEvent(fallbackEvent); 9134 } 9135 } 9136 } 9137 9138 /** 9139 * Returns true if the key is used for keyboard navigation. 9140 * @param keyEvent The key event. 9141 * @return True if the key is used for keyboard navigation. 9142 */ isNavigationKey(KeyEvent keyEvent)9143 private static boolean isNavigationKey(KeyEvent keyEvent) { 9144 switch (keyEvent.getKeyCode()) { 9145 case KeyEvent.KEYCODE_DPAD_LEFT: 9146 case KeyEvent.KEYCODE_DPAD_RIGHT: 9147 case KeyEvent.KEYCODE_DPAD_UP: 9148 case KeyEvent.KEYCODE_DPAD_DOWN: 9149 case KeyEvent.KEYCODE_DPAD_CENTER: 9150 case KeyEvent.KEYCODE_PAGE_UP: 9151 case KeyEvent.KEYCODE_PAGE_DOWN: 9152 case KeyEvent.KEYCODE_MOVE_HOME: 9153 case KeyEvent.KEYCODE_MOVE_END: 9154 case KeyEvent.KEYCODE_TAB: 9155 case KeyEvent.KEYCODE_SPACE: 9156 case KeyEvent.KEYCODE_ENTER: 9157 return true; 9158 } 9159 return false; 9160 } 9161 9162 /** 9163 * Returns true if the key is used for typing. 9164 * @param keyEvent The key event. 9165 * @return True if the key is used for typing. 9166 */ isTypingKey(KeyEvent keyEvent)9167 private static boolean isTypingKey(KeyEvent keyEvent) { 9168 return keyEvent.getUnicodeChar() > 0; 9169 } 9170 9171 /** 9172 * See if the key event means we should leave touch mode (and leave touch mode if so). 9173 * @param event The key event. 9174 * @return Whether this key event should be consumed (meaning the act of 9175 * leaving touch mode alone is considered the event). 9176 */ checkForLeavingTouchModeAndConsume(KeyEvent event)9177 private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) { 9178 // Only relevant in touch mode. 9179 if (!mAttachInfo.mInTouchMode) { 9180 return false; 9181 } 9182 9183 // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP. 9184 final int action = event.getAction(); 9185 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) { 9186 return false; 9187 } 9188 9189 // Don't leave touch mode if the IME told us not to. 9190 if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) { 9191 return false; 9192 } 9193 9194 // If the key can be used for keyboard navigation then leave touch mode 9195 // and select a focused view if needed (in ensureTouchMode). 9196 // When a new focused view is selected, we consume the navigation key because 9197 // navigation doesn't make much sense unless a view already has focus so 9198 // the key's purpose is to set focus. 9199 if (event.hasNoModifiers() && isNavigationKey(event)) { 9200 return ensureTouchMode(false); 9201 } 9202 9203 // If the key can be used for typing then leave touch mode 9204 // and select a focused view if needed (in ensureTouchMode). 9205 // Always allow the view to process the typing key. 9206 if (isTypingKey(event)) { 9207 ensureTouchMode(false); 9208 return false; 9209 } 9210 9211 return false; 9212 } 9213 9214 /* drag/drop */ 9215 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setLocalDragState(Object obj)9216 void setLocalDragState(Object obj) { 9217 mLocalDragState = obj; 9218 } 9219 handleDragEvent(DragEvent event)9220 private void handleDragEvent(DragEvent event) { 9221 // From the root, only drag start/end/location are dispatched. entered/exited 9222 // are determined and dispatched by the viewgroup hierarchy, who then report 9223 // that back here for ultimate reporting back to the framework. 9224 if (mView != null && mAdded) { 9225 final int what = event.mAction; 9226 9227 // Cache the drag description when the operation starts, then fill it in 9228 // on subsequent calls as a convenience 9229 if (what == DragEvent.ACTION_DRAG_STARTED) { 9230 mCurrentDragView = null; // Start the current-recipient tracking 9231 mDragDescription = event.mClipDescription; 9232 if (mStartedDragViewForA11y != null) { 9233 // Send a drag started a11y event 9234 mStartedDragViewForA11y.sendWindowContentChangedAccessibilityEvent( 9235 AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_STARTED); 9236 } 9237 } else { 9238 if (what == DragEvent.ACTION_DRAG_ENDED) { 9239 mDragDescription = null; 9240 } 9241 event.mClipDescription = mDragDescription; 9242 } 9243 9244 if (what == DragEvent.ACTION_DRAG_EXITED) { 9245 // A direct EXITED event means that the window manager knows we've just crossed 9246 // a window boundary, so the current drag target within this one must have 9247 // just been exited. Send the EXITED notification to the current drag view, if any. 9248 if (View.sCascadedDragDrop) { 9249 mView.dispatchDragEnterExitInPreN(event); 9250 } 9251 setDragFocus(null, event); 9252 } else { 9253 // For events with a [screen] location, translate into window coordinates 9254 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) { 9255 mDragPoint.set(event.mX, event.mY); 9256 if (mTranslator != null) { 9257 mTranslator.translatePointInScreenToAppWindow(mDragPoint); 9258 } 9259 9260 if (mCurScrollY != 0) { 9261 mDragPoint.offset(0, mCurScrollY); 9262 } 9263 9264 event.mX = mDragPoint.x; 9265 event.mY = mDragPoint.y; 9266 } 9267 9268 // Remember who the current drag target is pre-dispatch 9269 final View prevDragView = mCurrentDragView; 9270 9271 if (what == DragEvent.ACTION_DROP && event.mClipData != null) { 9272 event.mClipData.prepareToEnterProcess( 9273 mView.getContext().getAttributionSource()); 9274 } 9275 9276 // Now dispatch the drag/drop event 9277 boolean result = mView.dispatchDragEvent(event); 9278 9279 if (what == DragEvent.ACTION_DRAG_LOCATION && !event.mEventHandlerWasCalled) { 9280 // If the LOCATION event wasn't delivered to any handler, no view now has a drag 9281 // focus. 9282 setDragFocus(null, event); 9283 } 9284 9285 // If we changed apparent drag target, tell the OS about it 9286 if (prevDragView != mCurrentDragView) { 9287 try { 9288 if (prevDragView != null) { 9289 mWindowSession.dragRecipientExited(mWindow); 9290 } 9291 if (mCurrentDragView != null) { 9292 mWindowSession.dragRecipientEntered(mWindow); 9293 } 9294 } catch (RemoteException e) { 9295 Slog.e(mTag, "Unable to note drag target change"); 9296 } 9297 } 9298 9299 // Report the drop result when we're done 9300 if (what == DragEvent.ACTION_DROP) { 9301 try { 9302 Log.i(mTag, "Reporting drop result: " + result); 9303 mWindowSession.reportDropResult(mWindow, result); 9304 } catch (RemoteException e) { 9305 Log.e(mTag, "Unable to report drop result"); 9306 } 9307 } 9308 9309 // When the drag operation ends, reset drag-related state 9310 if (what == DragEvent.ACTION_DRAG_ENDED) { 9311 if (mStartedDragViewForA11y != null) { 9312 // If the drag failed, send a cancelled event from the source. Otherwise, 9313 // the View that accepted the drop sends CONTENT_CHANGE_TYPE_DRAG_DROPPED 9314 if (!event.getResult()) { 9315 mStartedDragViewForA11y.sendWindowContentChangedAccessibilityEvent( 9316 AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_CANCELLED); 9317 } 9318 mStartedDragViewForA11y.setAccessibilityDragStarted(false); 9319 } 9320 mStartedDragViewForA11y = null; 9321 mCurrentDragView = null; 9322 setLocalDragState(null); 9323 mAttachInfo.mDragToken = null; 9324 if (mAttachInfo.mDragSurface != null) { 9325 mAttachInfo.mDragSurface.release(); 9326 mAttachInfo.mDragSurface = null; 9327 } 9328 if (mAttachInfo.mDragData != null) { 9329 View.cleanUpPendingIntents(mAttachInfo.mDragData); 9330 mAttachInfo.mDragData = null; 9331 } 9332 } 9333 } 9334 } 9335 event.recycle(); 9336 } 9337 9338 /** 9339 * Notify that the window title changed 9340 */ onWindowTitleChanged()9341 public void onWindowTitleChanged() { 9342 mAttachInfo.mForceReportNewAttributes = true; 9343 } 9344 handleDispatchWindowShown()9345 public void handleDispatchWindowShown() { 9346 mAttachInfo.mTreeObserver.dispatchOnWindowShown(); 9347 } 9348 handleRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId)9349 public void handleRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) { 9350 Bundle data = new Bundle(); 9351 ArrayList<KeyboardShortcutGroup> list = new ArrayList<>(); 9352 if (mView != null) { 9353 mView.requestKeyboardShortcuts(list, deviceId); 9354 } 9355 int numGroups = list.size(); 9356 for (int i = 0; i < numGroups; ++i) { 9357 final KeyboardShortcutGroup group = list.get(i); 9358 group.setPackageName(mBasePackageName); 9359 9360 } 9361 data.putParcelableArrayList(WindowManager.PARCEL_KEY_SHORTCUTS_ARRAY, list); 9362 try { 9363 receiver.send(0, data); 9364 } catch (RemoteException e) { 9365 } 9366 } 9367 9368 @UnsupportedAppUsage getLastTouchPoint(Point outLocation)9369 public void getLastTouchPoint(Point outLocation) { 9370 outLocation.x = (int) mLastTouchPoint.x; 9371 outLocation.y = (int) mLastTouchPoint.y; 9372 } 9373 getLastTouchSource()9374 public int getLastTouchSource() { 9375 return mLastTouchSource; 9376 } 9377 getLastTouchDeviceId()9378 public int getLastTouchDeviceId() { 9379 return mLastTouchDeviceId; 9380 } 9381 getLastTouchPointerId()9382 public int getLastTouchPointerId() { 9383 return mLastTouchPointerId; 9384 } 9385 9386 /** 9387 * Used by InputMethodManager. 9388 * @hide 9389 */ getLastClickToolType()9390 public int getLastClickToolType() { 9391 return mLastClickToolType; 9392 } 9393 setDragFocus(View newDragTarget, DragEvent event)9394 public void setDragFocus(View newDragTarget, DragEvent event) { 9395 if (mCurrentDragView != newDragTarget && !View.sCascadedDragDrop) { 9396 // Send EXITED and ENTERED notifications to the old and new drag focus views. 9397 9398 final float tx = event.mX; 9399 final float ty = event.mY; 9400 final int action = event.mAction; 9401 final ClipData td = event.mClipData; 9402 // Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED. 9403 event.mX = 0; 9404 event.mY = 0; 9405 event.mClipData = null; 9406 9407 if (mCurrentDragView != null) { 9408 event.mAction = DragEvent.ACTION_DRAG_EXITED; 9409 mCurrentDragView.callDragEventHandler(event); 9410 } 9411 9412 if (newDragTarget != null) { 9413 event.mAction = DragEvent.ACTION_DRAG_ENTERED; 9414 newDragTarget.callDragEventHandler(event); 9415 } 9416 9417 event.mAction = action; 9418 event.mX = tx; 9419 event.mY = ty; 9420 event.mClipData = td; 9421 } 9422 9423 mCurrentDragView = newDragTarget; 9424 } 9425 9426 /** Sets the view that started drag and drop for the purpose of sending AccessibilityEvents */ setDragStartedViewForAccessibility(View view)9427 void setDragStartedViewForAccessibility(View view) { 9428 if (mStartedDragViewForA11y == null) { 9429 mStartedDragViewForA11y = view; 9430 } 9431 } 9432 getAudioManager()9433 private AudioManager getAudioManager() { 9434 if (mView == null) { 9435 throw new IllegalStateException("getAudioManager called when there is no mView"); 9436 } 9437 if (mAudioManager == null) { 9438 mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE); 9439 mFastScrollSoundEffectsEnabled = mAudioManager.areNavigationRepeatSoundEffectsEnabled(); 9440 } 9441 return mAudioManager; 9442 } 9443 getSystemVibrator()9444 private Vibrator getSystemVibrator() { 9445 if (mVibrator == null) { 9446 mVibrator = mContext.getSystemService(Vibrator.class); 9447 } 9448 return mVibrator; 9449 } 9450 9451 /** 9452 * Clears the system vibrator. 9453 * 9454 * <p>This method releases the reference to the system vibrator. It's crucial to call this 9455 * method when the vibrator is no longer needed to prevent any potential memory leaks. 9456 */ clearSystemVibrator()9457 public void clearSystemVibrator() { 9458 mVibrator = null; 9459 } 9460 getAutofillManager()9461 private @Nullable AutofillManager getAutofillManager() { 9462 if (mView instanceof ViewGroup) { 9463 ViewGroup decorView = (ViewGroup) mView; 9464 if (decorView.getChildCount() > 0) { 9465 // We cannot use decorView's Context for querying AutofillManager: DecorView's 9466 // context is based on Application Context, it would allocate a different 9467 // AutofillManager instance. 9468 return decorView.getChildAt(0).getContext() 9469 .getSystemService(AutofillManager.class); 9470 } 9471 } 9472 return null; 9473 } 9474 isAutofillUiShowing()9475 private boolean isAutofillUiShowing() { 9476 AutofillManager afm = getAutofillManager(); 9477 if (afm == null) { 9478 return false; 9479 } 9480 return afm.isAutofillUiShowing(); 9481 } 9482 getAccessibilityInteractionController()9483 public AccessibilityInteractionController getAccessibilityInteractionController() { 9484 if (mView == null) { 9485 throw new IllegalStateException("getAccessibilityInteractionController" 9486 + " called when there is no mView"); 9487 } 9488 if (mAccessibilityInteractionController == null) { 9489 mAccessibilityInteractionController = new AccessibilityInteractionController(this); 9490 } 9491 return mAccessibilityInteractionController; 9492 } 9493 relayoutWindow(WindowManager.LayoutParams params, int viewVisibility, boolean insetsPending)9494 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility, 9495 boolean insetsPending) throws RemoteException { 9496 final WindowConfiguration winConfigFromAm = getConfiguration().windowConfiguration; 9497 final WindowConfiguration winConfigFromWm = 9498 mLastReportedMergedConfiguration.getMergedConfiguration().windowConfiguration; 9499 final WindowConfiguration winConfig = getCompatWindowConfiguration(); 9500 final int measuredWidth = mMeasuredWidth; 9501 final int measuredHeight = mMeasuredHeight; 9502 final boolean relayoutAsync; 9503 if ((mViewFrameInfo.flags & FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED) == 0 9504 && mWindowAttributes.type != TYPE_APPLICATION_STARTING 9505 && mSyncSeqId <= mLastSyncSeqId 9506 && winConfigFromAm.diff(winConfigFromWm, false /* compareUndefined */) == 0) { 9507 final InsetsState state = mInsetsController.getState(); 9508 final Rect displayCutoutSafe = mTempRect; 9509 state.getDisplayCutoutSafe(displayCutoutSafe); 9510 mWindowLayout.computeFrames(mWindowAttributes.forRotation(winConfig.getRotation()), 9511 state, displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(), 9512 measuredWidth, measuredHeight, mInsetsController.getRequestedVisibleTypes(), 9513 1f /* compatScale */, mTmpFrames); 9514 mWinFrameInScreen.set(mTmpFrames.frame); 9515 if (mTranslator != null) { 9516 mTranslator.translateRectInAppWindowToScreen(mWinFrameInScreen); 9517 } 9518 9519 // If the position and the size of the frame are both changed, it will trigger a BLAST 9520 // sync, and we still need to call relayout to obtain the syncSeqId. Otherwise, we just 9521 // need to send attributes via relayoutAsync. 9522 final Rect oldFrame = mLastLayoutFrame; 9523 final Rect newFrame = mTmpFrames.frame; 9524 final boolean positionChanged = 9525 newFrame.top != oldFrame.top || newFrame.left != oldFrame.left; 9526 final boolean sizeChanged = 9527 newFrame.width() != oldFrame.width() || newFrame.height() != oldFrame.height(); 9528 relayoutAsync = !positionChanged || !sizeChanged; 9529 } else { 9530 relayoutAsync = false; 9531 } 9532 9533 float appScale = mAttachInfo.mApplicationScale; 9534 boolean restore = false; 9535 if (params != null && mTranslator != null) { 9536 restore = true; 9537 params.backup(); 9538 mTranslator.translateWindowLayout(params); 9539 } 9540 9541 if (params != null) { 9542 if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params); 9543 9544 if (mOrigWindowType != params.type) { 9545 // For compatibility with old apps, don't crash here. 9546 if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 9547 Slog.w(mTag, "Window type can not be changed after " 9548 + "the window is added; ignoring change of " + mView); 9549 params.type = mOrigWindowType; 9550 } 9551 } 9552 } 9553 9554 final int requestedWidth = (int) (measuredWidth * appScale + 0.5f); 9555 final int requestedHeight = (int) (measuredHeight * appScale + 0.5f); 9556 int relayoutResult = 0; 9557 mRelayoutSeq++; 9558 if (relayoutAsync) { 9559 mWindowSession.relayoutAsync(mWindow, params, 9560 requestedWidth, requestedHeight, viewVisibility, 9561 insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mRelayoutSeq, 9562 mLastSyncSeqId); 9563 } else { 9564 relayoutResult = mWindowSession.relayout(mWindow, params, 9565 requestedWidth, requestedHeight, viewVisibility, 9566 insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, 9567 mRelayoutSeq, mLastSyncSeqId, mRelayoutResult); 9568 mRelayoutRequested = true; 9569 9570 onClientWindowFramesChanged(mTmpFrames); 9571 9572 if (mPendingActivityWindowInfo != null) { 9573 final ActivityWindowInfo outInfo = mRelayoutResult.activityWindowInfo; 9574 if (outInfo != null) { 9575 mPendingActivityWindowInfo.set(outInfo); 9576 } 9577 } 9578 final int maybeSyncSeqId = mRelayoutResult.syncSeqId; 9579 if (maybeSyncSeqId > 0) { 9580 mSyncSeqId = maybeSyncSeqId; 9581 } 9582 9583 mWinFrameInScreen.set(mTmpFrames.frame); 9584 if (mTranslator != null) { 9585 mTranslator.translateRectInScreenToAppWindow(mTmpFrames.frame); 9586 mTranslator.translateRectInScreenToAppWindow(mTmpFrames.displayFrame); 9587 mTranslator.translateRectInScreenToAppWindow(mTmpFrames.attachedFrame); 9588 } 9589 mInvCompatScale = 1f / mTmpFrames.compatScale; 9590 CompatibilityInfo.applyOverrideIfNeeded(mPendingMergedConfiguration); 9591 handleInsetsControlChanged(mTempInsets, mTempControls); 9592 9593 mPendingAlwaysConsumeSystemBars = 9594 (relayoutResult & RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS) != 0; 9595 } 9596 9597 final int transformHint = SurfaceControl.rotationToBufferTransform( 9598 (mDisplay.getInstallOrientation() + mDisplay.getRotation()) % 4); 9599 final boolean transformHintChanged = transformHint != mPreviousTransformHint; 9600 mPreviousTransformHint = transformHint; 9601 mSurfaceControl.setTransformHint(transformHint); 9602 9603 WindowLayout.computeSurfaceSize(mWindowAttributes, winConfig.getMaxBounds(), requestedWidth, 9604 requestedHeight, mWinFrameInScreen, mPendingDragResizing, mSurfaceSize); 9605 9606 final boolean sizeChanged = !mLastSurfaceSize.equals(mSurfaceSize); 9607 final boolean surfaceControlChanged = 9608 (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED) == RELAYOUT_RES_SURFACE_CHANGED; 9609 if (mAttachInfo.mThreadedRenderer != null && 9610 (transformHintChanged || sizeChanged || surfaceControlChanged)) { 9611 if (mAttachInfo.mThreadedRenderer.pause()) { 9612 // Animations were running so we need to push a frame 9613 // to resume them 9614 mDirty.set(0, 0, mWidth, mHeight); 9615 } 9616 } 9617 9618 if (mSurfaceControl.isValid()) { 9619 if (mPendingDragResizing && !mSurfaceSize.equals( 9620 mWinFrameInScreen.width(), mWinFrameInScreen.height())) { 9621 // During drag-resize, a single fullscreen-sized surface is reused for optimization. 9622 // Crop to the content size instead of the surface size to avoid exposing garbage 9623 // content that is still on the surface from previous re-layouts (e.g. when 9624 // resizing to a larger size). 9625 mTransaction.setWindowCrop(mSurfaceControl, 9626 mWinFrameInScreen.width(), mWinFrameInScreen.height()); 9627 } else if (!HardwareRenderer.isDrawingEnabled()) { 9628 // When drawing is disabled the window layer won't have a valid buffer. 9629 // Set a window crop so input can get delivered to the window. 9630 mTransaction.setWindowCrop(mSurfaceControl, mSurfaceSize.x, mSurfaceSize.y).apply(); 9631 } 9632 } 9633 9634 if (mAttachInfo.mContentCaptureManager != null) { 9635 ContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager 9636 .getMainContentCaptureSession(); 9637 mainSession.notifyWindowBoundsChanged(mainSession.getId(), 9638 getConfiguration().windowConfiguration.getBounds()); 9639 } 9640 9641 if (mSurfaceControl.isValid()) { 9642 updateBlastSurfaceIfNeeded(); 9643 if (mAttachInfo.mThreadedRenderer != null) { 9644 mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue); 9645 } 9646 mHdrRenderState.forceUpdateHdrSdrRatio(); 9647 if (transformHintChanged) { 9648 dispatchTransformHintChanged(transformHint); 9649 } 9650 } else { 9651 if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.pause()) { 9652 mDirty.set(0, 0, mWidth, mHeight); 9653 } 9654 destroySurface(); 9655 } 9656 9657 if (restore) { 9658 params.restore(); 9659 } 9660 9661 setFrame(mTmpFrames.frame, true /* withinRelayout */); 9662 return relayoutResult; 9663 } 9664 updateOpacity(WindowManager.LayoutParams params, boolean dragResizing, boolean forceUpdate)9665 private void updateOpacity(WindowManager.LayoutParams params, boolean dragResizing, 9666 boolean forceUpdate) { 9667 boolean opaque = false; 9668 9669 if (!PixelFormat.formatHasAlpha(params.format) 9670 // Don't make surface with surfaceInsets opaque as they display a 9671 // translucent shadow. 9672 && params.surfaceInsets.left == 0 9673 && params.surfaceInsets.top == 0 9674 && params.surfaceInsets.right == 0 9675 && params.surfaceInsets.bottom == 0 9676 // Don't make surface opaque when resizing to reduce the amount of 9677 // artifacts shown in areas the app isn't drawing content to. 9678 && !dragResizing) { 9679 opaque = true; 9680 } 9681 9682 if (!forceUpdate && mIsSurfaceOpaque == opaque) { 9683 return; 9684 } 9685 9686 final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer; 9687 if (renderer != null && renderer.rendererOwnsSurfaceControlOpacity()) { 9688 opaque = renderer.setSurfaceControlOpaque(opaque); 9689 } else { 9690 mTransaction.setOpaque(mSurfaceControl, opaque).apply(); 9691 } 9692 9693 mIsSurfaceOpaque = opaque; 9694 } 9695 9696 /** 9697 * Set the mWinFrame of this window. 9698 * @param frame the new frame of this window. 9699 * @param withinRelayout {@code true} if this setting is within the relayout, or is the initial 9700 * setting. That will make sure in the relayout process, we always compare 9701 * the window frame with the last processed window frame. 9702 */ setFrame(Rect frame, boolean withinRelayout)9703 private void setFrame(Rect frame, boolean withinRelayout) { 9704 mWinFrame.set(frame); 9705 if (withinRelayout) { 9706 mLastLayoutFrame.set(frame); 9707 } 9708 9709 final WindowConfiguration winConfig = getCompatWindowConfiguration(); 9710 mPendingBackDropFrame.set(mPendingDragResizing && !winConfig.useWindowFrameForBackdrop() 9711 ? winConfig.getMaxBounds() 9712 : frame); 9713 // Surface position is now inherited from parent, and BackdropFrameRenderer uses backdrop 9714 // frame to position content. Thus, we just keep the size of backdrop frame, and remove the 9715 // offset to avoid double offset from display origin. 9716 mPendingBackDropFrame.offsetTo(0, 0); 9717 9718 mInsetsController.onFrameChanged(mOverrideInsetsFrame != null ? 9719 mOverrideInsetsFrame : frame); 9720 } 9721 9722 /** 9723 * In the normal course of operations we compute insets relative to 9724 * the frame returned from relayout window. In the case of 9725 * SurfaceControlViewHost, this frame is in local coordinates 9726 * instead of global coordinates. We support this override 9727 * frame so we can allow SurfaceControlViewHost to set a frame 9728 * to be used to calculate insets, without disturbing the main 9729 * mFrame. 9730 */ setOverrideInsetsFrame(Rect frame)9731 void setOverrideInsetsFrame(Rect frame) { 9732 mOverrideInsetsFrame = new Rect(frame); 9733 mInsetsController.onFrameChanged(mOverrideInsetsFrame); 9734 } 9735 9736 /** 9737 * Gets the current display size in which the window is being laid out, accounting for screen 9738 * decorations around it. 9739 */ getDisplayFrame(Rect outFrame)9740 void getDisplayFrame(Rect outFrame) { 9741 outFrame.set(mTmpFrames.displayFrame); 9742 // Apply sandboxing here (in getter) due to possible layout updates on the client after 9743 // mTmpFrames.displayFrame is received from the server. 9744 applyViewBoundsSandboxingIfNeeded(outFrame); 9745 } 9746 9747 /** 9748 * Gets the current display size in which the window is being laid out, accounting for screen 9749 * decorations around it. 9750 */ getWindowVisibleDisplayFrame(Rect outFrame)9751 void getWindowVisibleDisplayFrame(Rect outFrame) { 9752 outFrame.set(mTmpFrames.displayFrame); 9753 // XXX This is really broken, and probably all needs to be done 9754 // in the window manager, and we need to know more about whether 9755 // we want the area behind or in front of the IME. 9756 final Rect insets = mAttachInfo.mVisibleInsets; 9757 outFrame.left += insets.left; 9758 outFrame.top += insets.top; 9759 outFrame.right -= insets.right; 9760 outFrame.bottom -= insets.bottom; 9761 // Apply sandboxing here (in getter) due to possible layout updates on the client after 9762 // mTmpFrames.displayFrame is received from the server. 9763 applyViewBoundsSandboxingIfNeeded(outFrame); 9764 } 9765 9766 /** 9767 * Offset outRect to make it sandboxed within Window's bounds. 9768 * 9769 * <p>This is used by {@link android.view.View#getBoundsOnScreen}, 9770 * {@link android.view.ViewRootImpl#getDisplayFrame} and 9771 * {@link android.view.ViewRootImpl#getWindowVisibleDisplayFrame}, which are invoked by 9772 * {@link android.view.View#getWindowDisplayFrame} and 9773 * {@link android.view.View#getWindowVisibleDisplayFrame}, as well as 9774 * {@link android.view.ViewDebug#captureLayers} for debugging. 9775 */ applyViewBoundsSandboxingIfNeeded(final Rect inOutRect)9776 void applyViewBoundsSandboxingIfNeeded(final Rect inOutRect) { 9777 if (mViewBoundsSandboxingEnabled) { 9778 final Rect bounds = getConfiguration().windowConfiguration.getBounds(); 9779 inOutRect.offset(-bounds.left, -bounds.top); 9780 } 9781 } 9782 9783 /** 9784 * Offset outLocation to make it sandboxed within Window's bounds. 9785 * 9786 * <p>This is used by {@link android.view.View#getLocationOnScreen(int[])} 9787 */ applyViewLocationSandboxingIfNeeded(@ize2) int[] outLocation)9788 public void applyViewLocationSandboxingIfNeeded(@Size(2) int[] outLocation) { 9789 if (mViewBoundsSandboxingEnabled) { 9790 final Rect bounds = getConfiguration().windowConfiguration.getBounds(); 9791 outLocation[0] -= bounds.left; 9792 outLocation[1] -= bounds.top; 9793 } 9794 } 9795 getViewBoundsSandboxingEnabled()9796 private boolean getViewBoundsSandboxingEnabled() { 9797 // System dialogs (e.g. ANR) can be created within System process, so handleBindApplication 9798 // may be never called. This results into all app compat changes being enabled 9799 // (see b/268007823) because AppCompatCallbacks.install() is never called with non-empty 9800 // array. 9801 // With ActivityThread.isSystem we verify that it is not the system process, 9802 // then this CompatChange can take effect. 9803 if (ActivityThread.isSystem() 9804 || !CompatChanges.isChangeEnabled(OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS)) { 9805 // It is a system process or OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS change-id is disabled. 9806 return false; 9807 } 9808 9809 // OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS is enabled by the device manufacturer. 9810 try { 9811 final List<PackageManager.Property> properties = mContext.getPackageManager() 9812 .queryApplicationProperty(PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS); 9813 9814 final boolean isOptedOut = !properties.isEmpty() && !properties.get(0).getBoolean(); 9815 if (isOptedOut) { 9816 // PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS is disabled by the app devs. 9817 return false; 9818 } 9819 } catch (RuntimeException e) { 9820 // remote exception. 9821 } 9822 9823 return true; 9824 } 9825 9826 /** 9827 * {@inheritDoc} 9828 */ 9829 @Override playSoundEffect(@oundEffectConstants.SoundEffect int effectId)9830 public void playSoundEffect(@SoundEffectConstants.SoundEffect int effectId) { 9831 if ((mDisplay.getFlags() & Display.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) { 9832 return; 9833 } 9834 9835 checkThread(); 9836 9837 try { 9838 final AudioManager audioManager = getAudioManager(); 9839 9840 if (mFastScrollSoundEffectsEnabled 9841 && SoundEffectConstants.isNavigationRepeat(effectId)) { 9842 audioManager.playSoundEffect( 9843 SoundEffectConstants.nextNavigationRepeatSoundEffectId()); 9844 return; 9845 } 9846 9847 switch (effectId) { 9848 case SoundEffectConstants.CLICK: 9849 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK); 9850 return; 9851 case SoundEffectConstants.NAVIGATION_DOWN: 9852 case SoundEffectConstants.NAVIGATION_REPEAT_DOWN: 9853 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN); 9854 return; 9855 case SoundEffectConstants.NAVIGATION_LEFT: 9856 case SoundEffectConstants.NAVIGATION_REPEAT_LEFT: 9857 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT); 9858 return; 9859 case SoundEffectConstants.NAVIGATION_RIGHT: 9860 case SoundEffectConstants.NAVIGATION_REPEAT_RIGHT: 9861 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT); 9862 return; 9863 case SoundEffectConstants.NAVIGATION_UP: 9864 case SoundEffectConstants.NAVIGATION_REPEAT_UP: 9865 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP); 9866 return; 9867 default: 9868 throw new IllegalArgumentException("unknown effect id " + effectId + 9869 " not defined in " + SoundEffectConstants.class.getCanonicalName()); 9870 } 9871 } catch (IllegalStateException e) { 9872 // Exception thrown by getAudioManager() when mView is null 9873 Log.e(mTag, "FATAL EXCEPTION when attempting to play sound effect: " + e); 9874 e.printStackTrace(); 9875 } 9876 } 9877 9878 /** 9879 * {@inheritDoc} 9880 */ 9881 @Override performHapticFeedback(int effectId, int flags, int privFlags)9882 public boolean performHapticFeedback(int effectId, int flags, int privFlags) { 9883 if ((mDisplay.getFlags() & Display.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) { 9884 return false; 9885 } 9886 9887 getSystemVibrator().performHapticFeedback( 9888 effectId, "ViewRootImpl#performHapticFeedback", flags, privFlags); 9889 return true; 9890 } 9891 9892 @Override performHapticFeedbackForInputDevice(int effectId, int inputDeviceId, int inputSource, @HapticFeedbackConstants.Flags int flags, @HapticFeedbackConstants.PrivateFlags int privFlags)9893 public void performHapticFeedbackForInputDevice(int effectId, 9894 int inputDeviceId, int inputSource, 9895 @HapticFeedbackConstants.Flags int flags, 9896 @HapticFeedbackConstants.PrivateFlags int privFlags) { 9897 if ((mDisplay.getFlags() & Display.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) { 9898 return; 9899 } 9900 9901 getSystemVibrator().performHapticFeedbackForInputDevice(effectId, 9902 inputDeviceId, inputSource, "ViewRootImpl#performHapticFeedbackForInputDevice", 9903 flags, privFlags); 9904 } 9905 9906 /** 9907 * {@inheritDoc} 9908 */ 9909 @Override focusSearch(View focused, int direction)9910 public View focusSearch(View focused, int direction) { 9911 checkThread(); 9912 if (!(mView instanceof ViewGroup)) { 9913 return null; 9914 } 9915 return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction); 9916 } 9917 9918 /** 9919 * {@inheritDoc} 9920 */ 9921 @Override keyboardNavigationClusterSearch(View currentCluster, @FocusDirection int direction)9922 public View keyboardNavigationClusterSearch(View currentCluster, 9923 @FocusDirection int direction) { 9924 checkThread(); 9925 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( 9926 mView, currentCluster, direction); 9927 } 9928 debug()9929 public void debug() { 9930 mView.debug(); 9931 } 9932 9933 /** 9934 * Export the state of {@link ViewRootImpl} and other relevant classes into a protocol buffer 9935 * output stream. 9936 * 9937 * @param proto Stream to write the state to 9938 * @param fieldId FieldId of ViewRootImpl as defined in the parent message 9939 */ 9940 @GuardedBy("this") dumpDebug(ProtoOutputStream proto, long fieldId)9941 public void dumpDebug(ProtoOutputStream proto, long fieldId) { 9942 final long token = proto.start(fieldId); 9943 proto.write(VIEW, Objects.toString(mView)); 9944 proto.write(DISPLAY_ID, mDisplay.getDisplayId()); 9945 proto.write(APP_VISIBLE, mAppVisible); 9946 proto.write(HEIGHT, mHeight); 9947 proto.write(WIDTH, mWidth); 9948 proto.write(IS_ANIMATING, mIsAnimating); 9949 mVisRect.dumpDebug(proto, VISIBLE_RECT); 9950 proto.write(IS_DRAWING, mIsDrawing); 9951 proto.write(ADDED, mAdded); 9952 mWinFrame.dumpDebug(proto, WIN_FRAME); 9953 proto.write(LAST_WINDOW_INSETS, Objects.toString(mLastWindowInsets)); 9954 proto.write(SOFT_INPUT_MODE, InputMethodDebug.softInputModeToString(mSoftInputMode)); 9955 proto.write(SCROLL_Y, mScrollY); 9956 proto.write(CUR_SCROLL_Y, mCurScrollY); 9957 proto.write(REMOVED, mRemoved); 9958 mWindowAttributes.dumpDebug(proto, WINDOW_ATTRIBUTES); 9959 proto.end(token); 9960 mInsetsController.dumpDebug(proto, INSETS_CONTROLLER); 9961 mImeFocusController.dumpDebug(proto, IME_FOCUS_CONTROLLER); 9962 } 9963 9964 /** 9965 * Dump information about this ViewRootImpl 9966 * @param prefix the prefix that will be prepended to each line of the produced output 9967 * @param writer the writer that will receive the resulting text 9968 */ dump(String prefix, PrintWriter writer)9969 public void dump(String prefix, PrintWriter writer) { 9970 String innerPrefix = prefix + " "; 9971 writer.println(prefix + "ViewRoot:"); 9972 writer.println(innerPrefix + "mAdded=" + mAdded); 9973 writer.println(innerPrefix + "mRemoved=" + mRemoved); 9974 writer.println(innerPrefix + "mStopped=" + mStopped); 9975 writer.println(innerPrefix + "mPausedForTransition=" + mPausedForTransition); 9976 writer.println(innerPrefix + "mConsumeBatchedInputScheduled=" 9977 + mConsumeBatchedInputScheduled); 9978 writer.println(innerPrefix + "mConsumeBatchedInputImmediatelyScheduled=" 9979 + mConsumeBatchedInputImmediatelyScheduled); 9980 writer.println(innerPrefix + "mPendingInputEventCount=" + mPendingInputEventCount); 9981 writer.println(innerPrefix + "mProcessInputEventsScheduled=" 9982 + mProcessInputEventsScheduled); 9983 writer.println(innerPrefix + "mTraversalScheduled=" + mTraversalScheduled); 9984 if (mTraversalScheduled) { 9985 writer.println(innerPrefix + " (barrier=" + mTraversalBarrier + ")"); 9986 } 9987 writer.println(innerPrefix + "mReportNextDraw=" + mReportNextDraw); 9988 if (mReportNextDraw) { 9989 writer.println(innerPrefix + " (reason=" + mLastReportNextDrawReason + ")"); 9990 } 9991 if (mLastPerformTraversalsSkipDrawReason != null) { 9992 writer.println(innerPrefix + "mLastPerformTraversalsFailedReason=" 9993 + mLastPerformTraversalsSkipDrawReason); 9994 } 9995 if (mLastPerformDrawSkippedReason != null) { 9996 writer.println(innerPrefix + "mLastPerformDrawFailedReason=" 9997 + mLastPerformDrawSkippedReason); 9998 } 9999 if (mWmsRequestSyncGroupState != WMS_SYNC_NONE) { 10000 writer.println(innerPrefix + "mWmsRequestSyncGroupState=" + mWmsRequestSyncGroupState); 10001 } 10002 writer.println(innerPrefix + "mLastReportedMergedConfiguration=" 10003 + mLastReportedMergedConfiguration); 10004 writer.println(innerPrefix + "mLastConfigurationFromResources=" 10005 + mLastConfigurationFromResources); 10006 if (mLastReportedActivityWindowInfo != null) { 10007 writer.println(innerPrefix + "mLastReportedActivityWindowInfo=" 10008 + mLastReportedActivityWindowInfo); 10009 } 10010 writer.println(innerPrefix + "mIsAmbientMode=" + mIsAmbientMode); 10011 writer.println(innerPrefix + "mUnbufferedInputSource=" 10012 + Integer.toHexString(mUnbufferedInputSource)); 10013 if (mAttachInfo != null) { 10014 writer.print(innerPrefix + "mAttachInfo= "); 10015 mAttachInfo.dump(innerPrefix, writer); 10016 } else { 10017 writer.println(innerPrefix + "mAttachInfo=<null>"); 10018 } 10019 10020 mFirstInputStage.dump(innerPrefix, writer); 10021 10022 if (mInputEventReceiver != null) { 10023 mInputEventReceiver.dump(innerPrefix, writer); 10024 } 10025 10026 mChoreographer.dump(prefix, writer); 10027 10028 mInsetsController.dump(prefix, writer); 10029 10030 mOnBackInvokedDispatcher.dump(prefix, writer); 10031 10032 mImeBackAnimationController.dump(prefix, writer); 10033 10034 writer.println(prefix + "View Hierarchy:"); 10035 dumpViewHierarchy(innerPrefix, writer, mView); 10036 } 10037 dumpViewHierarchy(String prefix, PrintWriter writer, View view)10038 private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) { 10039 writer.print(prefix); 10040 if (view == null) { 10041 writer.println("null"); 10042 return; 10043 } 10044 writer.println(view.toString()); 10045 if (!(view instanceof ViewGroup)) { 10046 return; 10047 } 10048 ViewGroup grp = (ViewGroup)view; 10049 final int N = grp.getChildCount(); 10050 if (N <= 0) { 10051 return; 10052 } 10053 prefix = prefix + " "; 10054 for (int i=0; i<N; i++) { 10055 dumpViewHierarchy(prefix, writer, grp.getChildAt(i)); 10056 } 10057 } 10058 10059 static final class GfxInfo { 10060 public int viewCount; 10061 public long renderNodeMemoryUsage; 10062 public long renderNodeMemoryAllocated; 10063 add(GfxInfo other)10064 void add(GfxInfo other) { 10065 viewCount += other.viewCount; 10066 renderNodeMemoryUsage += other.renderNodeMemoryUsage; 10067 renderNodeMemoryAllocated += other.renderNodeMemoryAllocated; 10068 } 10069 } 10070 getGfxInfo()10071 GfxInfo getGfxInfo() { 10072 GfxInfo info = new GfxInfo(); 10073 if (mView != null) { 10074 appendGfxInfo(mView, info); 10075 } 10076 return info; 10077 } 10078 computeRenderNodeUsage(RenderNode node, GfxInfo info)10079 private static void computeRenderNodeUsage(RenderNode node, GfxInfo info) { 10080 if (node == null) return; 10081 info.renderNodeMemoryUsage += node.computeApproximateMemoryUsage(); 10082 info.renderNodeMemoryAllocated += node.computeApproximateMemoryAllocated(); 10083 } 10084 appendGfxInfo(View view, GfxInfo info)10085 private static void appendGfxInfo(View view, GfxInfo info) { 10086 info.viewCount++; 10087 computeRenderNodeUsage(view.mRenderNode, info); 10088 computeRenderNodeUsage(view.mBackgroundRenderNode, info); 10089 if (view instanceof ViewGroup) { 10090 ViewGroup group = (ViewGroup) view; 10091 10092 int count = group.getChildCount(); 10093 for (int i = 0; i < count; i++) { 10094 appendGfxInfo(group.getChildAt(i), info); 10095 } 10096 } 10097 } 10098 10099 /** 10100 * @param immediate True, do now if not in traversal. False, put on queue and do later. 10101 * @return True, request has been queued. False, request has been completed. 10102 */ die(boolean immediate)10103 boolean die(boolean immediate) { 10104 // Make sure we do execute immediately if we are in the middle of a traversal or the damage 10105 // done by dispatchDetachedFromWindow will cause havoc on return. 10106 if (immediate && !mIsInTraversal) { 10107 doDie(); 10108 return false; 10109 } 10110 10111 if (!com.android.graphics.hwui.flags.Flags.removeVriSketchyDestroy()) { 10112 if (!mIsDrawing) { 10113 destroyHardwareRenderer(); 10114 } else { 10115 Log.e(mTag, "Attempting to destroy the window while drawing!\n" 10116 + " window=" + this + ", title=" + mWindowAttributes.getTitle()); 10117 } 10118 } 10119 mHandler.sendEmptyMessage(MSG_DIE); 10120 return true; 10121 } 10122 doDie()10123 void doDie() { 10124 checkThread(); 10125 if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface); 10126 synchronized (this) { 10127 if (mRemoved) { 10128 return; 10129 } 10130 mRemoved = true; 10131 mOnBackInvokedDispatcher.detachFromWindow(); 10132 removeVrrMessages(); 10133 10134 if (mAdded) { 10135 dispatchDetachedFromWindow(); 10136 } 10137 10138 destroyHardwareRenderer(); 10139 10140 if (mAdded && !mFirst) { 10141 if (mView != null) { 10142 int viewVisibility = mView.getVisibility(); 10143 boolean viewVisibilityChanged = mViewVisibility != viewVisibility; 10144 if (mWindowAttributesChanged || viewVisibilityChanged) { 10145 // If layout params have been changed, first give them 10146 // to the window manager to make sure it has the correct 10147 // animation info. 10148 try { 10149 if ((relayoutWindow(mWindowAttributes, viewVisibility, false) 10150 & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { 10151 mWindowSession.finishDrawing( 10152 mWindow, null /* postDrawTransaction */, Integer.MAX_VALUE); 10153 } 10154 } catch (RemoteException e) { 10155 } 10156 } 10157 10158 destroySurface(); 10159 } 10160 } 10161 10162 // If our window is removed, we might not get notified about losing control. 10163 // Invoking this can release the leashes as soon as possible instead of relying on GC. 10164 mInsetsController.onControlsChanged(null); 10165 10166 mAdded = false; 10167 AnimationHandler.removeRequestor(this); 10168 } 10169 handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions, 10170 mPendingTransaction, "shutting down VRI"); 10171 mHasPendingTransactions = false; 10172 WindowManagerGlobal.getInstance().doRemoveView(this); 10173 } 10174 requestUpdateConfiguration(Configuration config)10175 public void requestUpdateConfiguration(Configuration config) { 10176 Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config); 10177 mHandler.sendMessage(msg); 10178 } 10179 loadSystemProperties()10180 public void loadSystemProperties() { 10181 mHandler.post(new Runnable() { 10182 @Override 10183 public void run() { 10184 // Profiling 10185 mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false); 10186 profileRendering(mAttachInfo.mHasWindowFocus); 10187 10188 // Hardware rendering 10189 if (mAttachInfo.mThreadedRenderer != null) { 10190 if (mAttachInfo.mThreadedRenderer.loadSystemProperties()) { 10191 invalidate(); 10192 } 10193 } 10194 10195 // Layout debugging 10196 boolean layout = DisplayProperties.debug_layout().orElse(false); 10197 if (layout != mAttachInfo.mDebugLayout) { 10198 mAttachInfo.mDebugLayout = layout; 10199 if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) { 10200 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200); 10201 } 10202 } 10203 } 10204 }); 10205 } 10206 destroyHardwareRenderer()10207 private void destroyHardwareRenderer() { 10208 ThreadedRenderer hardwareRenderer = mAttachInfo.mThreadedRenderer; 10209 10210 mHdrRenderState.stopListening(); 10211 10212 if (hardwareRenderer != null) { 10213 if (mHardwareRendererObserver != null) { 10214 hardwareRenderer.removeObserver(mHardwareRendererObserver); 10215 } 10216 if (mView != null) { 10217 hardwareRenderer.destroyHardwareResources(mView); 10218 } 10219 hardwareRenderer.destroy(); 10220 hardwareRenderer.setRequested(false); 10221 10222 mAttachInfo.mThreadedRenderer = null; 10223 mAttachInfo.mHardwareAccelerated = false; 10224 logColorMode(mCurrentColorMode, true); 10225 } 10226 } 10227 10228 @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, @Nullable ActivityWindowInfo activityWindowInfo)10229 private void dispatchResized(ClientWindowFrames frames, boolean reportDraw, 10230 MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout, 10231 boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing, 10232 @Nullable ActivityWindowInfo activityWindowInfo) { 10233 Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED); 10234 SomeArgs args = SomeArgs.obtain(); 10235 args.arg1 = frames; 10236 args.arg2 = mergedConfiguration; 10237 args.arg3 = insetsState; 10238 args.arg4 = activityWindowInfo; 10239 args.argi1 = forceLayout ? 1 : 0; 10240 args.argi2 = alwaysConsumeSystemBars ? 1 : 0; 10241 args.argi3 = displayId; 10242 args.argi4 = syncSeqId; 10243 args.argi5 = dragResizing ? 1 : 0; 10244 10245 msg.obj = args; 10246 mHandler.sendMessage(msg); 10247 } 10248 dispatchInsetsControlChanged(@onNull InsetsState insetsState, @NonNull InsetsSourceControl.Array activeControls)10249 private void dispatchInsetsControlChanged(@NonNull InsetsState insetsState, 10250 @NonNull InsetsSourceControl.Array activeControls) { 10251 final SomeArgs args = SomeArgs.obtain(); 10252 args.arg1 = insetsState; 10253 args.arg2 = activeControls; 10254 mHandler.obtainMessage(MSG_INSETS_CONTROL_CHANGED, args).sendToTarget(); 10255 } 10256 showInsets(@nsetsType int types, boolean fromIme, @Nullable ImeTracker.Token statsToken)10257 private void showInsets(@InsetsType int types, boolean fromIme, 10258 @Nullable ImeTracker.Token statsToken) { 10259 mHandler.obtainMessage(MSG_SHOW_INSETS, types, fromIme ? 1 : 0, statsToken).sendToTarget(); 10260 } 10261 hideInsets(@nsetsType int types, boolean fromIme, @Nullable ImeTracker.Token statsToken)10262 private void hideInsets(@InsetsType int types, boolean fromIme, 10263 @Nullable ImeTracker.Token statsToken) { 10264 mHandler.obtainMessage(MSG_HIDE_INSETS, types, fromIme ? 1 : 0, statsToken).sendToTarget(); 10265 } 10266 dispatchMoved(int newX, int newY)10267 public void dispatchMoved(int newX, int newY) { 10268 if (DEBUG_LAYOUT) Log.v(mTag, "Window moved " + this + ": newX=" + newX + " newY=" + newY); 10269 if (mTranslator != null) { 10270 PointF point = new PointF(newX, newY); 10271 mTranslator.translatePointInScreenToAppWindow(point); 10272 newX = (int) (point.x + 0.5); 10273 newY = (int) (point.y + 0.5); 10274 } 10275 Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY); 10276 mHandler.sendMessage(msg); 10277 } 10278 10279 /** 10280 * Dispatches the statsToken and IME visibility to the ImeInsetsSourceProvider. 10281 * 10282 * @param visible {@code true} if it became visible, {@code false} otherwise. 10283 * @param statsToken the token tracking the current IME request. 10284 * 10285 * @hide 10286 */ notifyImeVisibilityChanged(boolean visible, @NonNull ImeTracker.Token statsToken)10287 public void notifyImeVisibilityChanged(boolean visible, @NonNull ImeTracker.Token statsToken) { 10288 ImeTracker.forLogging().onProgress(statsToken, 10289 ImeTracker.PHASE_CLIENT_NOTIFY_IME_VISIBILITY_CHANGED); 10290 try { 10291 mWindowSession.notifyImeWindowVisibilityChangedFromClient(mWindow, visible, statsToken); 10292 } catch (RemoteException e) { 10293 ImeTracker.forLogging().onFailed(statsToken, 10294 ImeTracker.PHASE_CLIENT_NOTIFY_IME_VISIBILITY_CHANGED); 10295 e.rethrowFromSystemServer(); 10296 } 10297 } 10298 10299 /** 10300 * Represents a pending input event that is waiting in a queue. 10301 * 10302 * Input events are processed in serial order by the timestamp specified by 10303 * {@link InputEvent#getEventTimeNanos()}. In general, the input dispatcher delivers 10304 * one input event to the application at a time and waits for the application 10305 * to finish handling it before delivering the next one. 10306 * 10307 * However, because the application or IME can synthesize and inject multiple 10308 * key events at a time without going through the input dispatcher, we end up 10309 * needing a queue on the application's side. 10310 */ 10311 private static final class QueuedInputEvent { 10312 public static final int FLAG_DELIVER_POST_IME = 1 << 0; 10313 public static final int FLAG_DEFERRED = 1 << 1; 10314 public static final int FLAG_FINISHED = 1 << 2; 10315 public static final int FLAG_FINISHED_HANDLED = 1 << 3; 10316 public static final int FLAG_RESYNTHESIZED = 1 << 4; 10317 public static final int FLAG_UNHANDLED = 1 << 5; 10318 public static final int FLAG_MODIFIED_FOR_COMPATIBILITY = 1 << 6; 10319 public static final int FLAG_PRE_IME_ONLY = 1 << 7; 10320 10321 public QueuedInputEvent mNext; 10322 10323 public InputEvent mEvent; 10324 public InputEventReceiver mReceiver; 10325 public int mFlags; 10326 forPreImeOnly()10327 public boolean forPreImeOnly() { 10328 if ((mFlags & FLAG_PRE_IME_ONLY) != 0) { 10329 return true; 10330 } 10331 return false; 10332 } 10333 shouldSkipIme()10334 public boolean shouldSkipIme() { 10335 if ((mFlags & FLAG_DELIVER_POST_IME) != 0) { 10336 return true; 10337 } 10338 return mEvent instanceof MotionEvent 10339 && (mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)); 10340 } 10341 shouldSendToSynthesizer()10342 public boolean shouldSendToSynthesizer() { 10343 if ((mFlags & FLAG_UNHANDLED) != 0) { 10344 return true; 10345 } 10346 10347 return false; 10348 } 10349 10350 @Override toString()10351 public String toString() { 10352 StringBuilder sb = new StringBuilder("QueuedInputEvent{flags="); 10353 boolean hasPrevious = false; 10354 hasPrevious = flagToString("DELIVER_POST_IME", FLAG_DELIVER_POST_IME, hasPrevious, sb); 10355 hasPrevious = flagToString("DEFERRED", FLAG_DEFERRED, hasPrevious, sb); 10356 hasPrevious = flagToString("FINISHED", FLAG_FINISHED, hasPrevious, sb); 10357 hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb); 10358 hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb); 10359 hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb); 10360 hasPrevious = flagToString("FLAG_PRE_IME_ONLY", FLAG_PRE_IME_ONLY, hasPrevious, sb); 10361 if (!hasPrevious) { 10362 sb.append("0"); 10363 } 10364 sb.append(", hasNextQueuedEvent=" + (mEvent != null ? "true" : "false")); 10365 sb.append(", hasInputEventReceiver=" + (mReceiver != null ? "true" : "false")); 10366 sb.append(", mEvent=" + mEvent + "}"); 10367 return sb.toString(); 10368 } 10369 flagToString(String name, int flag, boolean hasPrevious, StringBuilder sb)10370 private boolean flagToString(String name, int flag, 10371 boolean hasPrevious, StringBuilder sb) { 10372 if ((mFlags & flag) != 0) { 10373 if (hasPrevious) { 10374 sb.append("|"); 10375 } 10376 sb.append(name); 10377 return true; 10378 } 10379 return hasPrevious; 10380 } 10381 } 10382 obtainQueuedInputEvent(InputEvent event, InputEventReceiver receiver, int flags)10383 private QueuedInputEvent obtainQueuedInputEvent(InputEvent event, 10384 InputEventReceiver receiver, int flags) { 10385 QueuedInputEvent q = mQueuedInputEventPool; 10386 if (q != null) { 10387 mQueuedInputEventPoolSize -= 1; 10388 mQueuedInputEventPool = q.mNext; 10389 q.mNext = null; 10390 } else { 10391 q = new QueuedInputEvent(); 10392 } 10393 10394 q.mEvent = event; 10395 q.mReceiver = receiver; 10396 q.mFlags = flags; 10397 return q; 10398 } 10399 recycleQueuedInputEvent(QueuedInputEvent q)10400 private void recycleQueuedInputEvent(QueuedInputEvent q) { 10401 q.mEvent = null; 10402 q.mReceiver = null; 10403 10404 if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) { 10405 mQueuedInputEventPoolSize += 1; 10406 q.mNext = mQueuedInputEventPool; 10407 mQueuedInputEventPool = q; 10408 } 10409 } 10410 10411 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) enqueueInputEvent(InputEvent event)10412 public void enqueueInputEvent(InputEvent event) { 10413 enqueueInputEvent(event, null, 0, false); 10414 } 10415 10416 @UnsupportedAppUsage enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately)10417 QueuedInputEvent enqueueInputEvent(InputEvent event, 10418 InputEventReceiver receiver, int flags, boolean processImmediately) { 10419 QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags); 10420 10421 if (event instanceof MotionEvent) { 10422 MotionEvent me = (MotionEvent) event; 10423 if (me.getAction() == MotionEvent.ACTION_CANCEL) { 10424 EventLog.writeEvent(EventLogTags.VIEW_ENQUEUE_INPUT_EVENT, "Motion - Cancel", 10425 getTitle().toString()); 10426 } 10427 } else if (event instanceof KeyEvent) { 10428 KeyEvent ke = (KeyEvent) event; 10429 if (ke.isCanceled()) { 10430 EventLog.writeEvent(EventLogTags.VIEW_ENQUEUE_INPUT_EVENT, "Key - Cancel", 10431 getTitle().toString()); 10432 } 10433 } 10434 // Always enqueue the input event in order, regardless of its time stamp. 10435 // We do this because the application or the IME may inject key events 10436 // in response to touch events and we want to ensure that the injected keys 10437 // are processed in the order they were received and we cannot trust that 10438 // the time stamp of injected events are monotonic. 10439 QueuedInputEvent last = mPendingInputEventTail; 10440 if (last == null) { 10441 mPendingInputEventHead = q; 10442 mPendingInputEventTail = q; 10443 } else { 10444 last.mNext = q; 10445 mPendingInputEventTail = q; 10446 } 10447 mPendingInputEventCount += 1; 10448 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName, 10449 mPendingInputEventCount); 10450 10451 if (processImmediately) { 10452 doProcessInputEvents(); 10453 } else { 10454 scheduleProcessInputEvents(); 10455 } 10456 return q; 10457 } 10458 scheduleProcessInputEvents()10459 private void scheduleProcessInputEvents() { 10460 if (!mProcessInputEventsScheduled) { 10461 mProcessInputEventsScheduled = true; 10462 Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS); 10463 msg.setAsynchronous(true); 10464 mHandler.sendMessage(msg); 10465 } 10466 } 10467 doProcessInputEvents()10468 void doProcessInputEvents() { 10469 // Deliver all pending input events in the queue. 10470 while (mPendingInputEventHead != null) { 10471 QueuedInputEvent q = mPendingInputEventHead; 10472 mPendingInputEventHead = q.mNext; 10473 if (mPendingInputEventHead == null) { 10474 mPendingInputEventTail = null; 10475 } 10476 q.mNext = null; 10477 10478 mPendingInputEventCount -= 1; 10479 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName, 10480 mPendingInputEventCount); 10481 10482 mViewFrameInfo.setInputEvent(mInputEventAssigner.processEvent(q.mEvent)); 10483 10484 deliverInputEvent(q); 10485 } 10486 10487 // We are done processing all input events that we can process right now 10488 // so we can clear the pending flag immediately. 10489 if (mProcessInputEventsScheduled) { 10490 mProcessInputEventsScheduled = false; 10491 mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS); 10492 } 10493 } 10494 deliverInputEvent(QueuedInputEvent q)10495 private void deliverInputEvent(QueuedInputEvent q) { 10496 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent", 10497 q.mEvent.getId()); 10498 10499 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 10500 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent src=0x" 10501 + Integer.toHexString(q.mEvent.getSource()) + " eventTimeNano=" 10502 + q.mEvent.getEventTimeNanos() + " id=0x" 10503 + Integer.toHexString(q.mEvent.getId())); 10504 } 10505 try { 10506 if (mInputEventConsistencyVerifier != null) { 10507 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "verifyEventConsistency"); 10508 try { 10509 mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0); 10510 } finally { 10511 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 10512 } 10513 } 10514 10515 InputStage stage; 10516 if (q.shouldSendToSynthesizer()) { 10517 stage = mSyntheticInputStage; 10518 } else { 10519 stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage; 10520 } 10521 10522 if (q.mEvent instanceof KeyEvent) { 10523 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "preDispatchToUnhandledKeyManager"); 10524 try { 10525 mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent); 10526 } finally { 10527 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 10528 } 10529 } 10530 10531 if (stage != null) { 10532 handleWindowFocusChanged(); 10533 stage.deliver(q); 10534 } else { 10535 finishInputEvent(q); 10536 } 10537 } finally { 10538 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 10539 } 10540 } 10541 finishInputEvent(QueuedInputEvent q)10542 private void finishInputEvent(QueuedInputEvent q) { 10543 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent", 10544 q.mEvent.getId()); 10545 10546 if (q.mReceiver != null) { 10547 boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0; 10548 boolean modified = (q.mFlags & QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY) != 0; 10549 if (modified) { 10550 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventBeforeFinish"); 10551 InputEvent processedEvent; 10552 try { 10553 processedEvent = 10554 mInputCompatProcessor.processInputEventBeforeFinish(q.mEvent); 10555 } finally { 10556 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 10557 } 10558 if (processedEvent != null) { 10559 q.mReceiver.finishInputEvent(processedEvent, handled); 10560 } 10561 } else { 10562 q.mReceiver.finishInputEvent(q.mEvent, handled); 10563 } 10564 if (q.mEvent instanceof KeyEvent) { 10565 logHandledSystemKey((KeyEvent) q.mEvent, handled); 10566 } 10567 } else { 10568 q.mEvent.recycleIfNeededAfterDispatch(); 10569 } 10570 10571 recycleQueuedInputEvent(q); 10572 } 10573 logHandledSystemKey(KeyEvent event, boolean handled)10574 private void logHandledSystemKey(KeyEvent event, boolean handled) { 10575 final int keyCode = event.getKeyCode(); 10576 if (keyCode != KeyEvent.KEYCODE_STEM_PRIMARY) { 10577 return; 10578 } 10579 if (event.isDown() && event.getRepeatCount() == 0 && handled) { 10580 // Initial DOWN event is handled. Log the stem primary key press. 10581 Counter.logIncrementWithUid( 10582 "input.value_app_handled_stem_primary_key_gestures_count", 10583 Process.myUid()); 10584 } 10585 } 10586 isTerminalInputEvent(InputEvent event)10587 static boolean isTerminalInputEvent(InputEvent event) { 10588 if (event instanceof KeyEvent) { 10589 final KeyEvent keyEvent = (KeyEvent)event; 10590 return keyEvent.getAction() == KeyEvent.ACTION_UP; 10591 } else { 10592 final MotionEvent motionEvent = (MotionEvent)event; 10593 final int action = motionEvent.getAction(); 10594 return action == MotionEvent.ACTION_UP 10595 || action == MotionEvent.ACTION_CANCEL 10596 || action == MotionEvent.ACTION_HOVER_EXIT; 10597 } 10598 } 10599 scheduleConsumeBatchedInput()10600 void scheduleConsumeBatchedInput() { 10601 // If anything is currently scheduled to consume batched input then there's no point in 10602 // scheduling it again. 10603 if (!mConsumeBatchedInputScheduled && !mConsumeBatchedInputImmediatelyScheduled) { 10604 mConsumeBatchedInputScheduled = true; 10605 mChoreographer.postCallback(Choreographer.CALLBACK_INPUT, 10606 mConsumedBatchedInputRunnable, null); 10607 if (mAttachInfo.mThreadedRenderer != null) { 10608 mAttachInfo.mThreadedRenderer.notifyCallbackPending(); 10609 } 10610 } 10611 } 10612 unscheduleConsumeBatchedInput()10613 void unscheduleConsumeBatchedInput() { 10614 if (mConsumeBatchedInputScheduled) { 10615 mConsumeBatchedInputScheduled = false; 10616 mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT, 10617 mConsumedBatchedInputRunnable, null); 10618 } 10619 } 10620 scheduleConsumeBatchedInputImmediately()10621 void scheduleConsumeBatchedInputImmediately() { 10622 if (!mConsumeBatchedInputImmediatelyScheduled) { 10623 unscheduleConsumeBatchedInput(); 10624 mConsumeBatchedInputImmediatelyScheduled = true; 10625 mHandler.post(mConsumeBatchedInputImmediatelyRunnable); 10626 } 10627 } 10628 doConsumeBatchedInput(long frameTimeNanos)10629 boolean doConsumeBatchedInput(long frameTimeNanos) { 10630 final boolean consumedBatches; 10631 if (mInputEventReceiver != null) { 10632 consumedBatches = mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos); 10633 } else { 10634 consumedBatches = false; 10635 } 10636 doProcessInputEvents(); 10637 return consumedBatches; 10638 } 10639 10640 final class TraversalRunnable implements Runnable { 10641 @Override run()10642 public void run() { 10643 doTraversal(); 10644 } 10645 } 10646 final TraversalRunnable mTraversalRunnable = new TraversalRunnable(); 10647 10648 final class WindowInputEventReceiver extends InputEventReceiver { WindowInputEventReceiver(InputChannel inputChannel, Looper looper)10649 public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) { 10650 super(inputChannel, looper); 10651 } 10652 10653 @Override onInputEvent(InputEvent event)10654 public void onInputEvent(InputEvent event) { 10655 processRawInputEvent(event); 10656 } 10657 10658 @Override onBatchedInputEventPending(int source)10659 public void onBatchedInputEventPending(int source) { 10660 final boolean unbuffered = mUnbufferedInputDispatch 10661 || (source & mUnbufferedInputSource) != SOURCE_CLASS_NONE; 10662 if (unbuffered) { 10663 if (mConsumeBatchedInputScheduled) { 10664 unscheduleConsumeBatchedInput(); 10665 } 10666 // Consume event immediately if unbuffered input dispatch has been requested. 10667 consumeBatchedInputEvents(-1); 10668 return; 10669 } 10670 scheduleConsumeBatchedInput(); 10671 } 10672 10673 @Override onFocusEvent(boolean hasFocus)10674 public void onFocusEvent(boolean hasFocus) { 10675 windowFocusChanged(hasFocus); 10676 } 10677 10678 @Override onTouchModeChanged(boolean inTouchMode)10679 public void onTouchModeChanged(boolean inTouchMode) { 10680 touchModeChanged(inTouchMode); 10681 } 10682 10683 @Override onPointerCaptureEvent(boolean pointerCaptureEnabled)10684 public void onPointerCaptureEvent(boolean pointerCaptureEnabled) { 10685 dispatchPointerCaptureChanged(pointerCaptureEnabled); 10686 } 10687 10688 @Override onDragEvent(boolean isExiting, float x, float y, int displayId)10689 public void onDragEvent(boolean isExiting, float x, float y, int displayId) { 10690 // force DRAG_EXITED_EVENT if appropriate 10691 DragEvent event = DragEvent.obtain( 10692 isExiting ? DragEvent.ACTION_DRAG_EXITED : DragEvent.ACTION_DRAG_LOCATION, x, y, 10693 0 /* offsetX */, 0 /* offsetY */, displayId, 0 /* flags */, 10694 null/* localState */, null/* description */, null /* data */, 10695 null /* dragSurface */, null /* dragAndDropPermissions */, false /* result */); 10696 dispatchDragEvent(event); 10697 } 10698 10699 @Override dispose()10700 public void dispose() { 10701 unscheduleConsumeBatchedInput(); 10702 super.dispose(); 10703 } 10704 } 10705 private WindowInputEventReceiver mInputEventReceiver; 10706 10707 final class InputMetricsListener 10708 implements HardwareRendererObserver.OnFrameMetricsAvailableListener { 10709 public long[] data = new long[FrameMetrics.Index.FRAME_STATS_COUNT]; 10710 10711 @Override onFrameMetricsAvailable(int dropCountSinceLastInvocation)10712 public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) { 10713 final int inputEventId = (int) data[FrameMetrics.Index.INPUT_EVENT_ID]; 10714 if (inputEventId == INVALID_INPUT_EVENT_ID) { 10715 return; 10716 } 10717 final long presentTime = data[FrameMetrics.Index.DISPLAY_PRESENT_TIME]; 10718 if (presentTime <= 0) { 10719 // Present time is not available for this frame. If the present time is not 10720 // available, we cannot compute end-to-end input latency metrics. 10721 return; 10722 } 10723 final long gpuCompletedTime = data[FrameMetrics.Index.GPU_COMPLETED]; 10724 if (mInputEventReceiver == null) { 10725 return; 10726 } 10727 if (gpuCompletedTime >= presentTime) { 10728 final double discrepancyMs = (gpuCompletedTime - presentTime) * 1E-6; 10729 final long vsyncId = data[FrameMetrics.Index.FRAME_TIMELINE_VSYNC_ID]; 10730 Log.w(TAG, "Not reporting timeline because gpuCompletedTime is " + discrepancyMs 10731 + "ms ahead of presentTime. FRAME_TIMELINE_VSYNC_ID=" + vsyncId 10732 + ", INPUT_EVENT_ID=" + inputEventId); 10733 // TODO(b/186664409): figure out why this sometimes happens 10734 return; 10735 } 10736 mInputEventReceiver.reportTimeline(inputEventId, gpuCompletedTime, presentTime); 10737 } 10738 } 10739 HardwareRendererObserver mHardwareRendererObserver; 10740 10741 final class ConsumeBatchedInputRunnable implements Runnable { 10742 @Override run()10743 public void run() { 10744 Trace.traceBegin(TRACE_TAG_VIEW, mTag); 10745 try { 10746 mConsumeBatchedInputScheduled = false; 10747 if (doConsumeBatchedInput(mChoreographer.getFrameTimeNanos())) { 10748 // If we consumed a batch here, we want to go ahead and schedule the 10749 // consumption of batched input events on the next frame. Otherwise, we would 10750 // wait until we have more input events pending and might get starved by other 10751 // things occurring in the process. 10752 scheduleConsumeBatchedInput(); 10753 } 10754 } finally { 10755 Trace.traceEnd(TRACE_TAG_VIEW); 10756 } 10757 } 10758 } 10759 final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable = 10760 new ConsumeBatchedInputRunnable(); 10761 boolean mConsumeBatchedInputScheduled; 10762 10763 final class ConsumeBatchedInputImmediatelyRunnable implements Runnable { 10764 @Override run()10765 public void run() { 10766 mConsumeBatchedInputImmediatelyScheduled = false; 10767 doConsumeBatchedInput(-1); 10768 } 10769 } 10770 final ConsumeBatchedInputImmediatelyRunnable mConsumeBatchedInputImmediatelyRunnable = 10771 new ConsumeBatchedInputImmediatelyRunnable(); 10772 boolean mConsumeBatchedInputImmediatelyScheduled; 10773 10774 final class InvalidateOnAnimationRunnable implements Runnable { 10775 private boolean mPosted; 10776 private final ArrayList<View> mViews = new ArrayList<View>(); 10777 private final ArrayList<AttachInfo.InvalidateInfo> mViewRects = 10778 new ArrayList<AttachInfo.InvalidateInfo>(); 10779 private View[] mTempViews; 10780 private AttachInfo.InvalidateInfo[] mTempViewRects; 10781 addView(View view)10782 public void addView(View view) { 10783 synchronized (this) { 10784 mViews.add(view); 10785 postIfNeededLocked(); 10786 } 10787 if (mAttachInfo.mThreadedRenderer != null) { 10788 mAttachInfo.mThreadedRenderer.notifyCallbackPending(); 10789 } 10790 } 10791 addViewRect(AttachInfo.InvalidateInfo info)10792 public void addViewRect(AttachInfo.InvalidateInfo info) { 10793 synchronized (this) { 10794 mViewRects.add(info); 10795 postIfNeededLocked(); 10796 } 10797 if (mAttachInfo.mThreadedRenderer != null) { 10798 mAttachInfo.mThreadedRenderer.notifyCallbackPending(); 10799 } 10800 } 10801 removeView(View view)10802 public void removeView(View view) { 10803 synchronized (this) { 10804 mViews.remove(view); 10805 10806 for (int i = mViewRects.size(); i-- > 0; ) { 10807 AttachInfo.InvalidateInfo info = mViewRects.get(i); 10808 if (info.target == view) { 10809 mViewRects.remove(i); 10810 info.recycle(); 10811 } 10812 } 10813 10814 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) { 10815 mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null); 10816 mPosted = false; 10817 } 10818 } 10819 } 10820 10821 @Override run()10822 public void run() { 10823 final int viewCount; 10824 final int viewRectCount; 10825 synchronized (this) { 10826 mPosted = false; 10827 10828 viewCount = mViews.size(); 10829 if (viewCount != 0) { 10830 mTempViews = mViews.toArray(mTempViews != null 10831 ? mTempViews : new View[viewCount]); 10832 mViews.clear(); 10833 } 10834 10835 viewRectCount = mViewRects.size(); 10836 if (viewRectCount != 0) { 10837 mTempViewRects = mViewRects.toArray(mTempViewRects != null 10838 ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]); 10839 mViewRects.clear(); 10840 } 10841 } 10842 10843 for (int i = 0; i < viewCount; i++) { 10844 mTempViews[i].invalidate(); 10845 mTempViews[i] = null; 10846 } 10847 10848 for (int i = 0; i < viewRectCount; i++) { 10849 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i]; 10850 info.target.invalidate(info.left, info.top, info.right, info.bottom); 10851 info.recycle(); 10852 } 10853 } 10854 postIfNeededLocked()10855 private void postIfNeededLocked() { 10856 if (!mPosted) { 10857 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null); 10858 mPosted = true; 10859 } 10860 } 10861 } 10862 final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable = 10863 new InvalidateOnAnimationRunnable(); 10864 10865 /** 10866 * Handle the incoming event. 10867 * 10868 * <p>The event will be first sent to the compatibility processor, which could choose to handle 10869 * it. The compat processor could also choose to produce more synthetic events in response to 10870 * the incoming one. Events that are not consumed by the compat processor are added to the 10871 * {@link ViewRootImpl}'s queue for further processing inside ViewRootImpl. 10872 * 10873 * @hide 10874 */ 10875 @VisibleForTesting processRawInputEvent(InputEvent event)10876 public void processRawInputEvent(InputEvent event) { 10877 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventForCompatibility"); 10878 List<InputEvent> processedEvents; 10879 try { 10880 processedEvents = 10881 mInputCompatProcessor.processInputEventForCompatibility(event); 10882 } finally { 10883 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 10884 } 10885 if (processedEvents != null) { 10886 if (processedEvents.isEmpty()) { 10887 // InputEvent consumed by mInputCompatProcessor 10888 mInputEventReceiver.finishInputEvent(event, true); 10889 } else { 10890 for (int i = 0; i < processedEvents.size(); i++) { 10891 enqueueInputEvent( 10892 processedEvents.get(i), mInputEventReceiver, 10893 QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY, true); 10894 } 10895 } 10896 } else { 10897 enqueueInputEvent(event, mInputEventReceiver, 0, true); 10898 } 10899 } 10900 dispatchInvalidateDelayed(View view, long delayMilliseconds)10901 public void dispatchInvalidateDelayed(View view, long delayMilliseconds) { 10902 Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view); 10903 mHandler.sendMessageDelayed(msg, delayMilliseconds); 10904 } 10905 dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info, long delayMilliseconds)10906 public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info, 10907 long delayMilliseconds) { 10908 final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info); 10909 mHandler.sendMessageDelayed(msg, delayMilliseconds); 10910 } 10911 dispatchInvalidateOnAnimation(View view)10912 public void dispatchInvalidateOnAnimation(View view) { 10913 mInvalidateOnAnimationRunnable.addView(view); 10914 } 10915 dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info)10916 public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) { 10917 mInvalidateOnAnimationRunnable.addViewRect(info); 10918 } 10919 10920 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) cancelInvalidate(View view)10921 public void cancelInvalidate(View view) { 10922 mHandler.removeMessages(MSG_INVALIDATE, view); 10923 // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning 10924 // them to the pool 10925 mHandler.removeMessages(MSG_INVALIDATE_RECT, view); 10926 mInvalidateOnAnimationRunnable.removeView(view); 10927 } 10928 10929 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) dispatchInputEvent(InputEvent event)10930 public void dispatchInputEvent(InputEvent event) { 10931 dispatchInputEvent(event, null); 10932 } 10933 10934 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) dispatchInputEvent(InputEvent event, InputEventReceiver receiver)10935 public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) { 10936 SomeArgs args = SomeArgs.obtain(); 10937 args.arg1 = event; 10938 args.arg2 = receiver; 10939 Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args); 10940 msg.setAsynchronous(true); 10941 mHandler.sendMessage(msg); 10942 } 10943 synthesizeInputEvent(InputEvent event)10944 public void synthesizeInputEvent(InputEvent event) { 10945 Message msg = mHandler.obtainMessage(MSG_SYNTHESIZE_INPUT_EVENT, event); 10946 msg.setAsynchronous(true); 10947 mHandler.sendMessage(msg); 10948 } 10949 10950 @UnsupportedAppUsage dispatchKeyFromIme(KeyEvent event)10951 public void dispatchKeyFromIme(KeyEvent event) { 10952 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event); 10953 msg.setAsynchronous(true); 10954 mHandler.sendMessage(msg); 10955 } 10956 dispatchKeyFromAutofill(KeyEvent event)10957 public void dispatchKeyFromAutofill(KeyEvent event) { 10958 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_AUTOFILL, event); 10959 msg.setAsynchronous(true); 10960 mHandler.sendMessage(msg); 10961 } 10962 10963 /** 10964 * Reinject unhandled {@link InputEvent}s in order to synthesize fallbacks events. 10965 * 10966 * Note that it is the responsibility of the caller of this API to recycle the InputEvent it 10967 * passes in. 10968 */ 10969 @UnsupportedAppUsage dispatchUnhandledInputEvent(InputEvent event)10970 public void dispatchUnhandledInputEvent(InputEvent event) { 10971 if (event instanceof MotionEvent) { 10972 event = MotionEvent.obtain((MotionEvent) event); 10973 } 10974 synthesizeInputEvent(event); 10975 } 10976 dispatchAppVisibility(boolean visible)10977 public void dispatchAppVisibility(boolean visible) { 10978 Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY); 10979 msg.arg1 = visible ? 1 : 0; 10980 mHandler.sendMessage(msg); 10981 } 10982 dispatchGetNewSurface()10983 public void dispatchGetNewSurface() { 10984 Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE); 10985 mHandler.sendMessage(msg); 10986 } 10987 10988 /** 10989 * Notifies this {@link ViewRootImpl} object that window focus has changed. 10990 */ windowFocusChanged(boolean hasFocus)10991 public void windowFocusChanged(boolean hasFocus) { 10992 synchronized (this) { 10993 mWindowFocusChanged = true; 10994 mUpcomingWindowFocus = hasFocus; 10995 } 10996 Message msg = Message.obtain(); 10997 msg.what = MSG_WINDOW_FOCUS_CHANGED; 10998 mHandler.sendMessage(msg); 10999 } 11000 11001 /** 11002 * Notifies this {@link ViewRootImpl} object that touch mode state has changed. 11003 */ touchModeChanged(boolean inTouchMode)11004 public void touchModeChanged(boolean inTouchMode) { 11005 synchronized (this) { 11006 mUpcomingInTouchMode = inTouchMode; 11007 } 11008 Message msg = Message.obtain(); 11009 msg.what = MSG_WINDOW_TOUCH_MODE_CHANGED; 11010 mHandler.sendMessage(msg); 11011 } 11012 dispatchWindowShown()11013 public void dispatchWindowShown() { 11014 mHandler.sendEmptyMessage(MSG_DISPATCH_WINDOW_SHOWN); 11015 } 11016 dispatchCloseSystemDialogs(String reason)11017 public void dispatchCloseSystemDialogs(String reason) { 11018 Message msg = Message.obtain(); 11019 msg.what = MSG_CLOSE_SYSTEM_DIALOGS; 11020 msg.obj = reason; 11021 mHandler.sendMessage(msg); 11022 } 11023 dispatchDragEvent(DragEvent event)11024 public void dispatchDragEvent(DragEvent event) { 11025 final int what; 11026 if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) { 11027 what = MSG_DISPATCH_DRAG_LOCATION_EVENT; 11028 mHandler.removeMessages(what); 11029 } else { 11030 what = MSG_DISPATCH_DRAG_EVENT; 11031 } 11032 Message msg = mHandler.obtainMessage(what, event); 11033 mHandler.sendMessage(msg); 11034 } 11035 dispatchCheckFocus()11036 public void dispatchCheckFocus() { 11037 if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) { 11038 // This will result in a call to checkFocus() below. 11039 mHandler.sendEmptyMessage(MSG_CHECK_FOCUS); 11040 } 11041 } 11042 dispatchRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId)11043 public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) { 11044 mHandler.obtainMessage( 11045 MSG_REQUEST_KEYBOARD_SHORTCUTS, deviceId, 0, receiver).sendToTarget(); 11046 } 11047 dispatchPointerCaptureChanged(boolean on)11048 private void dispatchPointerCaptureChanged(boolean on) { 11049 final int what = MSG_POINTER_CAPTURE_CHANGED; 11050 mHandler.removeMessages(what); 11051 Message msg = mHandler.obtainMessage(what); 11052 msg.arg1 = on ? 1 : 0; 11053 mHandler.sendMessage(msg); 11054 } 11055 11056 /** 11057 * Post a callback to send a 11058 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event. 11059 * This event is send at most once every 11060 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 11061 */ postSendWindowContentChangedCallback(View source, int changeType)11062 private void postSendWindowContentChangedCallback(View source, int changeType) { 11063 if (mSendWindowContentChangedAccessibilityEvent == null) { 11064 mSendWindowContentChangedAccessibilityEvent = 11065 new SendWindowContentChangedAccessibilityEvent(); 11066 } 11067 mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType); 11068 } 11069 11070 /** 11071 * Remove a posted callback to send a 11072 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event. 11073 */ removeSendWindowContentChangedCallback()11074 private void removeSendWindowContentChangedCallback() { 11075 if (mSendWindowContentChangedAccessibilityEvent != null) { 11076 mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent); 11077 } 11078 } 11079 11080 /** 11081 * Return the connection ID for the {@link AccessibilityInteractionController} of this instance. 11082 * @see AccessibilityNodeInfo#setQueryFromAppProcessEnabled 11083 */ getDirectAccessibilityConnectionId()11084 public int getDirectAccessibilityConnectionId() { 11085 return mAccessibilityInteractionConnectionManager.ensureDirectConnection(); 11086 } 11087 11088 @Override showContextMenuForChild(View originalView)11089 public boolean showContextMenuForChild(View originalView) { 11090 return false; 11091 } 11092 11093 @Override showContextMenuForChild(View originalView, float x, float y)11094 public boolean showContextMenuForChild(View originalView, float x, float y) { 11095 return false; 11096 } 11097 11098 @Override startActionModeForChild(View originalView, ActionMode.Callback callback)11099 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) { 11100 return null; 11101 } 11102 11103 @Override startActionModeForChild( View originalView, ActionMode.Callback callback, int type)11104 public ActionMode startActionModeForChild( 11105 View originalView, ActionMode.Callback callback, int type) { 11106 return null; 11107 } 11108 11109 @Override createContextMenu(ContextMenu menu)11110 public void createContextMenu(ContextMenu menu) { 11111 } 11112 11113 @Override childDrawableStateChanged(View child)11114 public void childDrawableStateChanged(View child) { 11115 } 11116 11117 @Override requestSendAccessibilityEvent(View child, AccessibilityEvent event)11118 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) { 11119 if (mView == null || mStopped || mPausedForTransition) { 11120 return false; 11121 } 11122 11123 // Immediately flush pending content changed event (if any) to preserve event order 11124 if (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED 11125 && mSendWindowContentChangedAccessibilityEvent != null 11126 && mSendWindowContentChangedAccessibilityEvent.mSource != null) { 11127 mSendWindowContentChangedAccessibilityEvent.removeCallbacksAndRun(); 11128 } 11129 11130 // Intercept accessibility focus events fired by virtual nodes to keep 11131 // track of accessibility focus position in such nodes. 11132 final int eventType = event.getEventType(); 11133 final View source = getSourceForAccessibilityEvent(event); 11134 switch (eventType) { 11135 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: { 11136 if (source != null) { 11137 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider(); 11138 if (provider != null) { 11139 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId( 11140 event.getSourceNodeId()); 11141 final AccessibilityNodeInfo node; 11142 node = provider.createAccessibilityNodeInfo(virtualNodeId); 11143 setAccessibilityFocus(source, node); 11144 } 11145 } 11146 } break; 11147 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: { 11148 if (source != null && source.getAccessibilityNodeProvider() != null) { 11149 setAccessibilityFocus(null, null); 11150 } 11151 } break; 11152 11153 11154 case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: { 11155 handleWindowContentChangedEvent(event); 11156 } break; 11157 } 11158 mAccessibilityManager.sendAccessibilityEvent(event); 11159 return true; 11160 } 11161 getSourceForAccessibilityEvent(AccessibilityEvent event)11162 private View getSourceForAccessibilityEvent(AccessibilityEvent event) { 11163 final long sourceNodeId = event.getSourceNodeId(); 11164 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId( 11165 sourceNodeId); 11166 return AccessibilityNodeIdManager.getInstance().findView(accessibilityViewId); 11167 } 11168 isAccessibilityFocusDirty()11169 private boolean isAccessibilityFocusDirty() { 11170 final Drawable drawable = mAttachInfo.mAccessibilityFocusDrawable; 11171 if (drawable != null) { 11172 final Rect bounds = mAttachInfo.mTmpInvalRect; 11173 final boolean hasFocus = getAccessibilityFocusedRect(bounds); 11174 if (!hasFocus) { 11175 bounds.setEmpty(); 11176 } 11177 if (!bounds.equals(drawable.getBounds())) { 11178 return true; 11179 } 11180 } 11181 return false; 11182 } 11183 11184 /** 11185 * Updates the focused virtual view, when necessary, in response to a 11186 * content changed event. 11187 * <p> 11188 * This is necessary to get updated bounds after a position change. 11189 * 11190 * @param event an accessibility event of type 11191 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} 11192 */ handleWindowContentChangedEvent(AccessibilityEvent event)11193 private void handleWindowContentChangedEvent(AccessibilityEvent event) { 11194 final View focusedHost = mAccessibilityFocusedHost; 11195 if (focusedHost == null || mAccessibilityFocusedVirtualView == null) { 11196 // No virtual view focused, nothing to do here. 11197 return; 11198 } 11199 11200 final AccessibilityNodeProvider provider = focusedHost.getAccessibilityNodeProvider(); 11201 if (provider == null) { 11202 // Error state: virtual view with no provider. Clear focus. 11203 mAccessibilityFocusedHost = null; 11204 mAccessibilityFocusedVirtualView = null; 11205 focusedHost.clearAccessibilityFocusNoCallbacks(0); 11206 return; 11207 } 11208 11209 // We only care about change types that may affect the bounds of the 11210 // focused virtual view. 11211 final int changes = event.getContentChangeTypes(); 11212 if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) == 0 11213 && changes != AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) { 11214 return; 11215 } 11216 11217 final long eventSourceNodeId = event.getSourceNodeId(); 11218 final int changedViewId = AccessibilityNodeInfo.getAccessibilityViewId(eventSourceNodeId); 11219 11220 // Search up the tree for subtree containment. 11221 boolean hostInSubtree = false; 11222 View root = mAccessibilityFocusedHost; 11223 while (root != null && !hostInSubtree) { 11224 if (changedViewId == root.getAccessibilityViewId()) { 11225 hostInSubtree = true; 11226 } else { 11227 final ViewParent parent = root.getParent(); 11228 if (parent instanceof View) { 11229 root = (View) parent; 11230 } else { 11231 root = null; 11232 } 11233 } 11234 } 11235 11236 // We care only about changes in subtrees containing the host view. 11237 if (!hostInSubtree) { 11238 return; 11239 } 11240 11241 final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId(); 11242 int focusedChildId = AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId); 11243 11244 // Refresh the node for the focused virtual view. 11245 final Rect oldBounds = mTempRect; 11246 mAccessibilityFocusedVirtualView.getBoundsInScreen(oldBounds); 11247 mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo(focusedChildId); 11248 if (mAccessibilityFocusedVirtualView == null) { 11249 // Error state: The node no longer exists. Clear focus. 11250 mAccessibilityFocusedHost = null; 11251 focusedHost.clearAccessibilityFocusNoCallbacks(0); 11252 11253 // This will probably fail, but try to keep the provider's internal 11254 // state consistent by clearing focus. 11255 provider.performAction(focusedChildId, 11256 AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(), null); 11257 invalidateRectOnScreen(oldBounds); 11258 } else { 11259 // The node was refreshed, invalidate bounds if necessary. 11260 final Rect newBounds = mAccessibilityFocusedVirtualView.getBoundsInScreen(); 11261 if (!oldBounds.equals(newBounds)) { 11262 oldBounds.union(newBounds); 11263 invalidateRectOnScreen(oldBounds); 11264 } 11265 } 11266 } 11267 11268 @Override notifySubtreeAccessibilityStateChanged(View child, View source, int changeType)11269 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) { 11270 postSendWindowContentChangedCallback(Objects.requireNonNull(source), changeType); 11271 } 11272 11273 @Override canResolveLayoutDirection()11274 public boolean canResolveLayoutDirection() { 11275 return true; 11276 } 11277 11278 @Override isLayoutDirectionResolved()11279 public boolean isLayoutDirectionResolved() { 11280 return true; 11281 } 11282 11283 @Override getLayoutDirection()11284 public int getLayoutDirection() { 11285 return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT; 11286 } 11287 11288 @Override canResolveTextDirection()11289 public boolean canResolveTextDirection() { 11290 return true; 11291 } 11292 11293 @Override isTextDirectionResolved()11294 public boolean isTextDirectionResolved() { 11295 return true; 11296 } 11297 11298 @Override getTextDirection()11299 public int getTextDirection() { 11300 return View.TEXT_DIRECTION_RESOLVED_DEFAULT; 11301 } 11302 11303 @Override canResolveTextAlignment()11304 public boolean canResolveTextAlignment() { 11305 return true; 11306 } 11307 11308 @Override isTextAlignmentResolved()11309 public boolean isTextAlignmentResolved() { 11310 return true; 11311 } 11312 11313 @Override getTextAlignment()11314 public int getTextAlignment() { 11315 return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT; 11316 } 11317 getCommonPredecessor(View first, View second)11318 private View getCommonPredecessor(View first, View second) { 11319 if (mTempHashSet == null) { 11320 mTempHashSet = new HashSet<View>(); 11321 } 11322 HashSet<View> seen = mTempHashSet; 11323 seen.clear(); 11324 View firstCurrent = first; 11325 while (firstCurrent != null) { 11326 seen.add(firstCurrent); 11327 ViewParent firstCurrentParent = firstCurrent.mParent; 11328 if (firstCurrentParent instanceof View) { 11329 firstCurrent = (View) firstCurrentParent; 11330 } else { 11331 firstCurrent = null; 11332 } 11333 } 11334 View secondCurrent = second; 11335 while (secondCurrent != null) { 11336 if (seen.contains(secondCurrent)) { 11337 seen.clear(); 11338 return secondCurrent; 11339 } 11340 ViewParent secondCurrentParent = secondCurrent.mParent; 11341 if (secondCurrentParent instanceof View) { 11342 secondCurrent = (View) secondCurrentParent; 11343 } else { 11344 secondCurrent = null; 11345 } 11346 } 11347 seen.clear(); 11348 return null; 11349 } 11350 checkThread()11351 void checkThread() { 11352 Thread current = Thread.currentThread(); 11353 if (mThread != current) { 11354 throw new CalledFromWrongThreadException( 11355 "Only the original thread that created a view hierarchy can touch its views." 11356 + " Expected: " + mThread.getName() 11357 + " Calling: " + current.getName()); 11358 } 11359 } 11360 11361 @Override requestDisallowInterceptTouchEvent(boolean disallowIntercept)11362 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { 11363 // ViewAncestor never intercepts touch event, so this can be a no-op 11364 } 11365 11366 @Override requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate)11367 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) { 11368 if (rectangle == null) { 11369 return scrollToRectOrFocus(null, immediate); 11370 } 11371 rectangle.offset(child.getLeft() - child.getScrollX(), 11372 child.getTop() - child.getScrollY()); 11373 final boolean scrolled = scrollToRectOrFocus(rectangle, immediate); 11374 mTempRect.set(rectangle); 11375 mTempRect.offset(0, -mCurScrollY); 11376 mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 11377 try { 11378 mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect); 11379 } catch (RemoteException re) { 11380 /* ignore */ 11381 } 11382 return scrolled; 11383 } 11384 11385 @Override childHasTransientStateChanged(View child, boolean hasTransientState)11386 public void childHasTransientStateChanged(View child, boolean hasTransientState) { 11387 // Do nothing. 11388 } 11389 11390 @Override onStartNestedScroll(View child, View target, int nestedScrollAxes)11391 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) { 11392 return false; 11393 } 11394 11395 @Override onStopNestedScroll(View target)11396 public void onStopNestedScroll(View target) { 11397 } 11398 11399 @Override onNestedScrollAccepted(View child, View target, int nestedScrollAxes)11400 public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) { 11401 } 11402 11403 @Override onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed)11404 public void onNestedScroll(View target, int dxConsumed, int dyConsumed, 11405 int dxUnconsumed, int dyUnconsumed) { 11406 } 11407 11408 @Override onNestedPreScroll(View target, int dx, int dy, int[] consumed)11409 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) { 11410 } 11411 11412 @Override onNestedFling(View target, float velocityX, float velocityY, boolean consumed)11413 public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) { 11414 return false; 11415 } 11416 11417 @Override onNestedPreFling(View target, float velocityX, float velocityY)11418 public boolean onNestedPreFling(View target, float velocityX, float velocityY) { 11419 return false; 11420 } 11421 11422 @Override onNestedPrePerformAccessibilityAction(View target, int action, Bundle args)11423 public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) { 11424 return false; 11425 } 11426 11427 /** 11428 * Checks the input event receiver for input availability. 11429 * May return false negatives. 11430 * @hide 11431 */ probablyHasInput()11432 public boolean probablyHasInput() { 11433 if (mInputEventReceiver == null) { 11434 return false; 11435 } 11436 return mInputEventReceiver.probablyHasInput(); 11437 } 11438 11439 /** 11440 * Adds a scroll capture callback to this window. 11441 * 11442 * @param callback the callback to add 11443 */ addScrollCaptureCallback(ScrollCaptureCallback callback)11444 public void addScrollCaptureCallback(ScrollCaptureCallback callback) { 11445 if (mRootScrollCaptureCallbacks == null) { 11446 mRootScrollCaptureCallbacks = new HashSet<>(); 11447 } 11448 mRootScrollCaptureCallbacks.add(callback); 11449 } 11450 11451 /** 11452 * Removes a scroll capture callback from this window. 11453 * 11454 * @param callback the callback to remove 11455 */ removeScrollCaptureCallback(ScrollCaptureCallback callback)11456 public void removeScrollCaptureCallback(ScrollCaptureCallback callback) { 11457 if (mRootScrollCaptureCallbacks != null) { 11458 mRootScrollCaptureCallbacks.remove(callback); 11459 if (mRootScrollCaptureCallbacks.isEmpty()) { 11460 mRootScrollCaptureCallbacks = null; 11461 } 11462 } 11463 } 11464 11465 /** 11466 * Dispatches a scroll capture request to the view hierarchy on the ui thread. 11467 * 11468 * @param listener for the response 11469 */ dispatchScrollCaptureRequest(@onNull IScrollCaptureResponseListener listener)11470 public void dispatchScrollCaptureRequest(@NonNull IScrollCaptureResponseListener listener) { 11471 mHandler.obtainMessage(MSG_REQUEST_SCROLL_CAPTURE, listener).sendToTarget(); 11472 } 11473 11474 /** 11475 * Collect and include any ScrollCaptureCallback instances registered with the window. 11476 * 11477 * @see #addScrollCaptureCallback(ScrollCaptureCallback) 11478 * @param results an object to collect the results of the search 11479 */ collectRootScrollCaptureTargets(ScrollCaptureSearchResults results)11480 private void collectRootScrollCaptureTargets(ScrollCaptureSearchResults results) { 11481 if (mRootScrollCaptureCallbacks == null) { 11482 return; 11483 } 11484 for (ScrollCaptureCallback cb : mRootScrollCaptureCallbacks) { 11485 // Add to the list for consideration 11486 Point offset = new Point(mView.getLeft(), mView.getTop()); 11487 Rect rect = new Rect(0, 0, mView.getWidth(), mView.getHeight()); 11488 results.addTarget(new ScrollCaptureTarget(mView, rect, offset, cb)); 11489 } 11490 } 11491 11492 /** 11493 * Update the timeout for scroll capture requests. Only affects this view root. 11494 * The default value is {@link #SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS}. 11495 * 11496 * @param timeMillis the new timeout in milliseconds 11497 */ setScrollCaptureRequestTimeout(int timeMillis)11498 public void setScrollCaptureRequestTimeout(int timeMillis) { 11499 mScrollCaptureRequestTimeout = timeMillis; 11500 } 11501 11502 /** 11503 * Get the current timeout for scroll capture requests. 11504 * 11505 * @return the timeout in milliseconds 11506 */ getScrollCaptureRequestTimeout()11507 public long getScrollCaptureRequestTimeout() { 11508 return mScrollCaptureRequestTimeout; 11509 } 11510 11511 /** 11512 * Handles an inbound request for scroll capture from the system. A search will be 11513 * dispatched through the view tree to locate scrolling content. 11514 * <p> 11515 * A call to 11516 * {@link IScrollCaptureResponseListener#onScrollCaptureResponse} will follow. 11517 * 11518 * @param listener to receive responses 11519 * @see ScrollCaptureSearchResults 11520 */ handleScrollCaptureRequest(@onNull IScrollCaptureResponseListener listener)11521 public void handleScrollCaptureRequest(@NonNull IScrollCaptureResponseListener listener) { 11522 ScrollCaptureSearchResults results = 11523 new ScrollCaptureSearchResults(mContext.getMainExecutor()); 11524 11525 // Window (root) level callbacks 11526 collectRootScrollCaptureTargets(results); 11527 11528 // Search through View-tree 11529 View rootView = getView(); 11530 if (rootView == null) { 11531 ScrollCaptureResponse.Builder response = new ScrollCaptureResponse.Builder(); 11532 response.setWindowTitle(getTitle().toString()); 11533 response.setPackageName(mContext.getPackageName()); 11534 response.setDescription("The root view was null"); 11535 try { 11536 listener.onScrollCaptureResponse(response.build()); 11537 } catch (RemoteException e) { 11538 Log.e(TAG, "Failed to send scroll capture search result", e); 11539 } 11540 return; 11541 } 11542 11543 Point point = new Point(); 11544 Rect rect = new Rect(0, 0, rootView.getWidth(), rootView.getHeight()); 11545 getChildVisibleRect(rootView, rect, point); 11546 rootView.dispatchScrollCaptureSearch(rect, point, results::addTarget); 11547 11548 Runnable onComplete = () -> dispatchScrollCaptureSearchResponse(listener, results); 11549 results.setOnCompleteListener(onComplete); 11550 if (!results.isComplete()) { 11551 mHandler.postDelayed(results::finish, getScrollCaptureRequestTimeout()); 11552 } 11553 } 11554 11555 /** Called by {@link #handleScrollCaptureRequest} when a result is returned */ dispatchScrollCaptureSearchResponse( @onNull IScrollCaptureResponseListener listener, @NonNull ScrollCaptureSearchResults results)11556 private void dispatchScrollCaptureSearchResponse( 11557 @NonNull IScrollCaptureResponseListener listener, 11558 @NonNull ScrollCaptureSearchResults results) { 11559 11560 ScrollCaptureTarget selectedTarget = results.getTopResult(); 11561 11562 ScrollCaptureResponse.Builder response = new ScrollCaptureResponse.Builder(); 11563 response.setWindowTitle(getTitle().toString()); 11564 response.setPackageName(mContext.getPackageName()); 11565 11566 StringWriter writer = new StringWriter(); 11567 IndentingPrintWriter pw = new IndentingPrintWriter(writer); 11568 results.dump(pw); 11569 pw.flush(); 11570 response.addMessage(writer.toString()); 11571 11572 if (mView == null) { 11573 response.setDescription("The root view disappeared!"); 11574 try { 11575 listener.onScrollCaptureResponse(response.build()); 11576 } catch (RemoteException e) { 11577 Log.e(TAG, "Failed to send scroll capture search result", e); 11578 } 11579 return; 11580 } 11581 11582 if (selectedTarget == null) { 11583 response.setDescription("No scrollable targets found in window"); 11584 try { 11585 listener.onScrollCaptureResponse(response.build()); 11586 } catch (RemoteException e) { 11587 Log.e(TAG, "Failed to send scroll capture search result", e); 11588 } 11589 return; 11590 } 11591 11592 response.setDescription("Connected"); 11593 11594 // Compute area covered by scrolling content within window 11595 Rect boundsInWindow = new Rect(); 11596 View containingView = selectedTarget.getContainingView(); 11597 containingView.getLocationInWindow(mAttachInfo.mTmpLocation); 11598 boundsInWindow.set(selectedTarget.getScrollBounds()); 11599 boundsInWindow.offset(mAttachInfo.mTmpLocation[0], mAttachInfo.mTmpLocation[1]); 11600 response.setBoundsInWindow(boundsInWindow); 11601 11602 // Compute the area on screen covered by the window 11603 Rect boundsOnScreen = new Rect(); 11604 mView.getLocationOnScreen(mAttachInfo.mTmpLocation); 11605 boundsOnScreen.set(0, 0, mView.getWidth(), mView.getHeight()); 11606 boundsOnScreen.offset(mAttachInfo.mTmpLocation[0], mAttachInfo.mTmpLocation[1]); 11607 response.setWindowBounds(boundsOnScreen); 11608 Log.d(TAG, "ScrollCaptureSearchResponse: " + response); 11609 11610 // Create a connection and return it to the caller 11611 ScrollCaptureConnection connection = new ScrollCaptureConnection( 11612 mView.getContext().getMainExecutor(), selectedTarget); 11613 response.setConnection(connection); 11614 11615 try { 11616 listener.onScrollCaptureResponse(response.build()); 11617 } catch (RemoteException e) { 11618 if (DEBUG_SCROLL_CAPTURE) { 11619 Log.w(TAG, "Failed to send scroll capture search response.", e); 11620 } 11621 connection.close(); 11622 } 11623 } 11624 reportNextDraw(String reason)11625 private void reportNextDraw(String reason) { 11626 if (DEBUG_BLAST) { 11627 Log.d(mTag, "reportNextDraw " + Debug.getCallers(5)); 11628 } 11629 mReportNextDraw = true; 11630 mLastReportNextDrawReason = reason; 11631 } 11632 11633 /** 11634 * Force the window to report its next draw. 11635 * <p> 11636 * This method is only supposed to be used to speed up the interaction from SystemUI and window 11637 * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE 11638 * unless you fully understand this interaction. 11639 * 11640 * @param syncBuffer If true, the transaction that contains the buffer from the draw should be 11641 * sent to system to be synced. If false, VRI will not try to sync the buffer, 11642 * but only report back that a buffer was drawn. 11643 * @param reason A debug string indicating the reason for reporting the next draw 11644 * @hide 11645 */ setReportNextDraw(boolean syncBuffer, String reason)11646 public void setReportNextDraw(boolean syncBuffer, String reason) { 11647 mSyncBuffer = syncBuffer; 11648 reportNextDraw(reason); 11649 invalidate(); 11650 } 11651 changeCanvasOpacity(boolean opaque)11652 void changeCanvasOpacity(boolean opaque) { 11653 Log.d(mTag, "changeCanvasOpacity: opaque=" + opaque); 11654 opaque = opaque & ((mView.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0); 11655 if (mAttachInfo.mThreadedRenderer != null) { 11656 mAttachInfo.mThreadedRenderer.setOpaque(opaque); 11657 } 11658 } 11659 11660 /** 11661 * Dispatches a KeyEvent to all registered key fallback handlers. 11662 * 11663 * @param event 11664 * @return {@code true} if the event was handled, {@code false} otherwise. 11665 */ dispatchUnhandledKeyEvent(KeyEvent event)11666 public boolean dispatchUnhandledKeyEvent(KeyEvent event) { 11667 return mUnhandledKeyManager.dispatch(mView, event); 11668 } 11669 11670 class TakenSurfaceHolder extends BaseSurfaceHolder { 11671 @Override onAllowLockCanvas()11672 public boolean onAllowLockCanvas() { 11673 return mDrawingAllowed; 11674 } 11675 11676 @Override onRelayoutContainer()11677 public void onRelayoutContainer() { 11678 // Not currently interesting -- from changing between fixed and layout size. 11679 } 11680 11681 @Override setFormat(int format)11682 public void setFormat(int format) { 11683 ((RootViewSurfaceTaker)mView).setSurfaceFormat(format); 11684 } 11685 11686 @Override setType(int type)11687 public void setType(int type) { 11688 ((RootViewSurfaceTaker)mView).setSurfaceType(type); 11689 } 11690 11691 @Override onUpdateSurface()11692 public void onUpdateSurface() { 11693 // We take care of format and type changes on our own. 11694 throw new IllegalStateException("Shouldn't be here"); 11695 } 11696 11697 @Override isCreating()11698 public boolean isCreating() { 11699 return mIsCreating; 11700 } 11701 11702 @Override setFixedSize(int width, int height)11703 public void setFixedSize(int width, int height) { 11704 throw new UnsupportedOperationException( 11705 "Currently only support sizing from layout"); 11706 } 11707 11708 @Override setKeepScreenOn(boolean screenOn)11709 public void setKeepScreenOn(boolean screenOn) { 11710 ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn); 11711 } 11712 } 11713 11714 static class W extends IWindow.Stub implements WindowStateTransactionItem.TransactionListener { 11715 private final WeakReference<ViewRootImpl> mViewAncestor; 11716 private final IWindowSession mWindowSession; 11717 private boolean mIsFromTransactionItem; 11718 W(ViewRootImpl viewAncestor)11719 W(ViewRootImpl viewAncestor) { 11720 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor); 11721 mWindowSession = viewAncestor.mWindowSession; 11722 } 11723 11724 @Override onExecutingWindowStateTransactionItem()11725 public void onExecutingWindowStateTransactionItem() { 11726 mIsFromTransactionItem = true; 11727 } 11728 11729 @Override resized(ClientWindowFrames frames, boolean reportDraw, MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing, @Nullable ActivityWindowInfo activityWindowInfo)11730 public void resized(ClientWindowFrames frames, boolean reportDraw, 11731 MergedConfiguration mergedConfiguration, InsetsState insetsState, 11732 boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, 11733 boolean dragResizing, @Nullable ActivityWindowInfo activityWindowInfo) { 11734 final boolean isFromResizeItem = mIsFromTransactionItem; 11735 mIsFromTransactionItem = false; 11736 // Although this is a AIDL method, it will only be triggered in local process through 11737 // either WindowStateResizeItem or WindowlessWindowManager. 11738 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11739 if (viewAncestor == null) { 11740 return; 11741 } 11742 if (insetsState.isSourceOrDefaultVisible(ID_IME, Type.ime())) { 11743 ImeTracing.getInstance().triggerClientDump("ViewRootImpl.W#resized", 11744 viewAncestor.getInsetsController().getHost().getInputMethodManager(), 11745 null /* icProto */); 11746 } 11747 // If the UI thread is the same as the current thread that is dispatching 11748 // WindowStateResizeItem, then it can run directly. 11749 if (isFromResizeItem && viewAncestor.mHandler.getLooper() 11750 == ActivityThread.currentActivityThread().getLooper()) { 11751 viewAncestor.handleResized(frames, reportDraw, mergedConfiguration, insetsState, 11752 forceLayout, alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing, 11753 activityWindowInfo); 11754 return; 11755 } 11756 // The the parameters from WindowStateResizeItem are already copied. 11757 final boolean needsCopy = 11758 !isFromResizeItem && (Binder.getCallingPid() == Process.myPid()); 11759 if (needsCopy) { 11760 insetsState = new InsetsState(insetsState, true /* copySource */); 11761 frames = new ClientWindowFrames(frames); 11762 mergedConfiguration = new MergedConfiguration(mergedConfiguration); 11763 } 11764 viewAncestor.dispatchResized(frames, reportDraw, mergedConfiguration, insetsState, 11765 forceLayout, alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing, 11766 activityWindowInfo); 11767 } 11768 11769 @Override insetsControlChanged(InsetsState insetsState, InsetsSourceControl.Array activeControls)11770 public void insetsControlChanged(InsetsState insetsState, 11771 InsetsSourceControl.Array activeControls) { 11772 final boolean isFromInsetsControlChangeItem; 11773 isFromInsetsControlChangeItem = mIsFromTransactionItem; 11774 mIsFromTransactionItem = false; 11775 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11776 if (viewAncestor == null) { 11777 if (isFromInsetsControlChangeItem) { 11778 activeControls.release(); 11779 } 11780 return; 11781 } 11782 if (insetsState.isSourceOrDefaultVisible(ID_IME, Type.ime())) { 11783 ImeTracing.getInstance().triggerClientDump( 11784 "ViewRootImpl#dispatchInsetsControlChanged", 11785 viewAncestor.getInsetsController().getHost().getInputMethodManager(), 11786 null /* icProto */); 11787 } 11788 // If the UI thread is the same as the current thread that is dispatching 11789 // WindowStateInsetsControlChangeItem, then it can run directly. 11790 if (isFromInsetsControlChangeItem && viewAncestor.mHandler.getLooper() 11791 == ActivityThread.currentActivityThread().getLooper()) { 11792 viewAncestor.handleInsetsControlChanged(insetsState, activeControls); 11793 return; 11794 } 11795 // The parameters from WindowStateInsetsControlChangeItem are already copied. 11796 final boolean needsCopy = 11797 !isFromInsetsControlChangeItem && (Binder.getCallingPid() == Process.myPid()); 11798 if (needsCopy) { 11799 insetsState = new InsetsState(insetsState, true /* copySource */); 11800 activeControls = new InsetsSourceControl.Array( 11801 activeControls, true /* copyControls */); 11802 } 11803 11804 viewAncestor.dispatchInsetsControlChanged(insetsState, activeControls); 11805 } 11806 11807 @Override showInsets(@nsetsType int types, boolean fromIme, @Nullable ImeTracker.Token statsToken)11808 public void showInsets(@InsetsType int types, boolean fromIme, 11809 @Nullable ImeTracker.Token statsToken) { 11810 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11811 if (fromIme) { 11812 ImeTracing.getInstance().triggerClientDump("ViewRootImpl.W#showInsets", 11813 viewAncestor.getInsetsController().getHost().getInputMethodManager(), 11814 null /* icProto */); 11815 } 11816 if (viewAncestor != null) { 11817 ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_SHOW_INSETS); 11818 viewAncestor.showInsets(types, fromIme, statsToken); 11819 } else { 11820 ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_SHOW_INSETS); 11821 } 11822 } 11823 11824 @Override hideInsets(@nsetsType int types, boolean fromIme, @Nullable ImeTracker.Token statsToken)11825 public void hideInsets(@InsetsType int types, boolean fromIme, 11826 @Nullable ImeTracker.Token statsToken) { 11827 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11828 if (fromIme) { 11829 ImeTracing.getInstance().triggerClientDump("ViewRootImpl.W#hideInsets", 11830 viewAncestor.getInsetsController().getHost().getInputMethodManager(), 11831 null /* icProto */); 11832 } 11833 if (viewAncestor != null) { 11834 ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_HIDE_INSETS); 11835 viewAncestor.hideInsets(types, fromIme, statsToken); 11836 } else { 11837 ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_HIDE_INSETS); 11838 } 11839 } 11840 11841 @Override moved(int newX, int newY)11842 public void moved(int newX, int newY) { 11843 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11844 if (viewAncestor != null) { 11845 viewAncestor.dispatchMoved(newX, newY); 11846 } 11847 } 11848 11849 @Override dispatchAppVisibility(boolean visible)11850 public void dispatchAppVisibility(boolean visible) { 11851 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11852 if (viewAncestor != null) { 11853 viewAncestor.dispatchAppVisibility(visible); 11854 } 11855 } 11856 11857 @Override dispatchGetNewSurface()11858 public void dispatchGetNewSurface() { 11859 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11860 if (viewAncestor != null) { 11861 viewAncestor.dispatchGetNewSurface(); 11862 } 11863 } 11864 checkCallingPermission(String permission)11865 private static int checkCallingPermission(String permission) { 11866 try { 11867 return ActivityManager.getService().checkPermission( 11868 permission, Binder.getCallingPid(), Binder.getCallingUid()); 11869 } catch (RemoteException e) { 11870 return PackageManager.PERMISSION_DENIED; 11871 } 11872 } 11873 11874 @Override executeCommand(String command, String parameters, ParcelFileDescriptor out)11875 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) { 11876 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11877 if (viewAncestor != null) { 11878 final View view = viewAncestor.mView; 11879 if (view != null) { 11880 if (checkCallingPermission(Manifest.permission.DUMP) != 11881 PackageManager.PERMISSION_GRANTED) { 11882 throw new SecurityException("Insufficient permissions to invoke" 11883 + " executeCommand() from pid=" + Binder.getCallingPid() 11884 + ", uid=" + Binder.getCallingUid()); 11885 } 11886 11887 OutputStream clientStream = null; 11888 try { 11889 clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out); 11890 ViewDebug.dispatchCommand(view, command, parameters, clientStream); 11891 } catch (IOException e) { 11892 e.printStackTrace(); 11893 } finally { 11894 if (clientStream != null) { 11895 try { 11896 clientStream.close(); 11897 } catch (IOException e) { 11898 e.printStackTrace(); 11899 } 11900 } 11901 } 11902 } 11903 } 11904 } 11905 11906 @Override closeSystemDialogs(String reason)11907 public void closeSystemDialogs(String reason) { 11908 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11909 if (viewAncestor != null) { 11910 viewAncestor.dispatchCloseSystemDialogs(reason); 11911 } 11912 } 11913 11914 @Override dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, float zoom, boolean sync)11915 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, 11916 float zoom, boolean sync) { 11917 if (sync) { 11918 try { 11919 mWindowSession.wallpaperOffsetsComplete(asBinder()); 11920 } catch (RemoteException e) { 11921 } 11922 } 11923 } 11924 11925 @Override dispatchWallpaperCommand(String action, int x, int y, int z, Bundle extras, boolean sync)11926 public void dispatchWallpaperCommand(String action, int x, int y, 11927 int z, Bundle extras, boolean sync) { 11928 if (sync) { 11929 try { 11930 mWindowSession.wallpaperCommandComplete(asBinder(), null); 11931 } catch (RemoteException e) { 11932 } 11933 } 11934 } 11935 11936 /* Drag/drop */ 11937 @Override dispatchDragEvent(DragEvent event)11938 public void dispatchDragEvent(DragEvent event) { 11939 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11940 if (viewAncestor != null) { 11941 viewAncestor.dispatchDragEvent(event); 11942 } 11943 } 11944 11945 @Override dispatchWindowShown()11946 public void dispatchWindowShown() { 11947 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11948 if (viewAncestor != null) { 11949 viewAncestor.dispatchWindowShown(); 11950 } 11951 } 11952 11953 @Override requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId)11954 public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) { 11955 ViewRootImpl viewAncestor = mViewAncestor.get(); 11956 if (viewAncestor != null) { 11957 viewAncestor.dispatchRequestKeyboardShortcuts(receiver, deviceId); 11958 } 11959 } 11960 11961 @Override requestScrollCapture(IScrollCaptureResponseListener listener)11962 public void requestScrollCapture(IScrollCaptureResponseListener listener) { 11963 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11964 if (viewAncestor != null) { 11965 viewAncestor.dispatchScrollCaptureRequest(listener); 11966 } 11967 } 11968 11969 @Override dumpWindow(ParcelFileDescriptor pfd)11970 public void dumpWindow(ParcelFileDescriptor pfd) { 11971 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11972 if (viewAncestor == null) { 11973 return; 11974 } 11975 viewAncestor.mHandler.postAtFrontOfQueue(() -> { 11976 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); 11977 try { 11978 PrintWriter pw = new FastPrintWriter(new FileOutputStream( 11979 pfd.getFileDescriptor())); 11980 viewAncestor.dump("", pw); 11981 pw.flush(); 11982 } finally { 11983 IoUtils.closeQuietly(pfd); 11984 StrictMode.setThreadPolicy(oldPolicy); 11985 } 11986 }); 11987 } 11988 } 11989 11990 public static final class CalledFromWrongThreadException extends AndroidRuntimeException { 11991 @UnsupportedAppUsage CalledFromWrongThreadException(String msg)11992 public CalledFromWrongThreadException(String msg) { 11993 super(msg); 11994 } 11995 } 11996 getRunQueue()11997 static HandlerActionQueue getRunQueue() { 11998 HandlerActionQueue rq = sRunQueues.get(); 11999 if (rq != null) { 12000 return rq; 12001 } 12002 rq = new HandlerActionQueue(); 12003 sRunQueues.set(rq); 12004 return rq; 12005 } 12006 12007 /** 12008 * Start a drag resizing which will inform all listeners that a window resize is taking place. 12009 */ startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets, Rect stableInsets)12010 private void startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets, 12011 Rect stableInsets) { 12012 if (!mDragResizing) { 12013 mDragResizing = true; 12014 if (mUseMTRenderer) { 12015 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { 12016 mWindowCallbacks.get(i).onWindowDragResizeStart( 12017 initialBounds, fullscreen, systemInsets, stableInsets); 12018 } 12019 } 12020 mFullRedrawNeeded = true; 12021 } 12022 } 12023 12024 /** 12025 * End a drag resize which will inform all listeners that a window resize has ended. 12026 */ endDragResizing()12027 private void endDragResizing() { 12028 if (mDragResizing) { 12029 mDragResizing = false; 12030 if (mUseMTRenderer) { 12031 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { 12032 mWindowCallbacks.get(i).onWindowDragResizeEnd(); 12033 } 12034 } 12035 mFullRedrawNeeded = true; 12036 } 12037 } 12038 updateContentDrawBounds()12039 private boolean updateContentDrawBounds() { 12040 boolean updated = false; 12041 if (mUseMTRenderer) { 12042 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { 12043 updated |= 12044 mWindowCallbacks.get(i).onContentDrawn(mWindowAttributes.surfaceInsets.left, 12045 mWindowAttributes.surfaceInsets.top, mWidth, mHeight); 12046 } 12047 } 12048 return updated | (mDragResizing && mReportNextDraw); 12049 } 12050 requestDrawWindow()12051 private void requestDrawWindow() { 12052 if (!mUseMTRenderer) { 12053 return; 12054 } 12055 // Only wait if it will report next draw. 12056 if (mReportNextDraw) { 12057 mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size()); 12058 } 12059 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { 12060 mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw); 12061 } 12062 } 12063 getSurfaceControl()12064 public SurfaceControl getSurfaceControl() { 12065 return mSurfaceControl; 12066 } 12067 12068 /** 12069 * @return Returns a token used to identify the windows input channel. 12070 */ getInputToken()12071 public IBinder getInputToken() { 12072 if (mInputEventReceiver == null) { 12073 return null; 12074 } 12075 return mInputEventReceiver.getToken(); 12076 } 12077 12078 /** 12079 * {@inheritDoc} 12080 */ 12081 @NonNull 12082 @Override getInputTransferToken()12083 public InputTransferToken getInputTransferToken() { 12084 IBinder inputToken = getInputToken(); 12085 if (inputToken == null) { 12086 throw new IllegalStateException( 12087 "Called getInputTransferToken for Window with no input channel"); 12088 } 12089 return new InputTransferToken(inputToken); 12090 } 12091 @NonNull getWindowToken()12092 public IBinder getWindowToken() { 12093 return mAttachInfo.mWindowToken; 12094 } 12095 12096 /** 12097 * {@inheritDoc} 12098 */ 12099 @NonNull 12100 @Override 12101 @FlaggedApi(com.android.window.flags.Flags.FLAG_JANK_API) registerOnJankDataListener( @onNull @allbackExecutor Executor executor, @NonNull SurfaceControl.OnJankDataListener listener)12102 public SurfaceControl.OnJankDataListenerRegistration registerOnJankDataListener( 12103 @NonNull @CallbackExecutor Executor executor, 12104 @NonNull SurfaceControl.OnJankDataListener listener) { 12105 SurfaceControl.OnJankDataListener wrapped = (data) -> 12106 executor.execute(() -> listener.onJankDataAvailable(data)); 12107 return mSurfaceControl.addOnJankDataListener(wrapped); 12108 } 12109 12110 /** 12111 * Class for managing the accessibility interaction connection 12112 * based on the global accessibility state. 12113 */ 12114 final class AccessibilityInteractionConnectionManager 12115 implements AccessibilityStateChangeListener { 12116 private int mDirectConnectionId = AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID; 12117 12118 @Override onAccessibilityStateChanged(boolean enabled)12119 public void onAccessibilityStateChanged(boolean enabled) { 12120 if (enabled) { 12121 ensureConnection(); 12122 setAccessibilityWindowAttributesIfNeeded(); 12123 if (mAttachInfo.mHasWindowFocus && (mView != null)) { 12124 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 12125 View focusedView = mView.findFocus(); 12126 if (focusedView != null && focusedView != mView) { 12127 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 12128 } 12129 } 12130 if (mAttachInfo.mLeashedParentToken != null) { 12131 mAccessibilityManager.associateEmbeddedHierarchy( 12132 mAttachInfo.mLeashedParentToken, mLeashToken); 12133 } 12134 } else { 12135 ensureNoConnection(); 12136 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget(); 12137 } 12138 } 12139 ensureConnection()12140 public void ensureConnection() { 12141 final boolean registered = mAttachInfo.mAccessibilityWindowId 12142 != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 12143 if (!registered) { 12144 mAttachInfo.mAccessibilityWindowId = 12145 mAccessibilityManager.addAccessibilityInteractionConnection(mWindow, 12146 mLeashToken, 12147 mContext.getPackageName(), 12148 new AccessibilityInteractionConnection(ViewRootImpl.this)); 12149 } 12150 } 12151 ensureNoConnection()12152 public void ensureNoConnection() { 12153 final boolean registered = mAttachInfo.mAccessibilityWindowId 12154 != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 12155 if (registered) { 12156 mAttachInfo.mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 12157 mAccessibilityWindowAttributes = null; 12158 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow); 12159 } 12160 } 12161 ensureDirectConnection()12162 public int ensureDirectConnection() { 12163 if (mDirectConnectionId == AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID) { 12164 mDirectConnectionId = AccessibilityInteractionClient.addDirectConnection( 12165 new AccessibilityInteractionConnection(ViewRootImpl.this), 12166 mAccessibilityManager); 12167 // Notify listeners in the app process. 12168 mAccessibilityManager.notifyAccessibilityStateChanged(); 12169 } 12170 return mDirectConnectionId; 12171 } 12172 ensureNoDirectConnection()12173 public void ensureNoDirectConnection() { 12174 if (mDirectConnectionId != AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID) { 12175 AccessibilityInteractionClient.removeConnection(mDirectConnectionId); 12176 mDirectConnectionId = AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID; 12177 // Notify listeners in the app process. 12178 mAccessibilityManager.notifyAccessibilityStateChanged(); 12179 } 12180 } 12181 } 12182 12183 final class HighContrastTextManager implements HighContrastTextStateChangeListener { HighContrastTextManager()12184 HighContrastTextManager() { 12185 ThreadedRenderer.setHighContrastText(mAccessibilityManager.isHighContrastTextEnabled()); 12186 } 12187 @Override onHighContrastTextStateChanged(boolean enabled)12188 public void onHighContrastTextStateChanged(boolean enabled) { 12189 ThreadedRenderer.setHighContrastText(enabled); 12190 12191 destroyAndInvalidate(); 12192 } 12193 } 12194 12195 /** 12196 * Destroy Displaylists so they can be recreated with new recordings, in case you are changing 12197 * the way things are rendered (e.g. high contrast, force dark), then invalidate to trigger a 12198 * redraw. 12199 */ destroyAndInvalidate()12200 private void destroyAndInvalidate() { 12201 destroyHardwareResources(); 12202 12203 // Schedule redraw, which will rerecord + redraw all text 12204 invalidate(); 12205 } 12206 12207 /** 12208 * This class is an interface this ViewAncestor provides to the 12209 * AccessibilityManagerService to the latter can interact with 12210 * the view hierarchy in this ViewAncestor. 12211 */ 12212 static final class AccessibilityInteractionConnection 12213 extends IAccessibilityInteractionConnection.Stub { 12214 private final WeakReference<ViewRootImpl> mViewRootImpl; 12215 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl)12216 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) { 12217 mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl); 12218 } 12219 12220 @Override findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix, Bundle args)12221 public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, 12222 Region interactiveRegion, int interactionId, 12223 IAccessibilityInteractionConnectionCallback callback, int flags, 12224 int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix, 12225 Bundle args) { 12226 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 12227 if (viewRootImpl != null && viewRootImpl.mView != null) { 12228 viewRootImpl.getAccessibilityInteractionController() 12229 .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId, 12230 interactiveRegion, interactionId, callback, flags, interrogatingPid, 12231 interrogatingTid, spec, matrix, args); 12232 } else { 12233 // We cannot make the call and notify the caller so it does not wait. 12234 try { 12235 callback.setFindAccessibilityNodeInfosResult(null, interactionId); 12236 } catch (RemoteException re) { 12237 /* best effort - ignore */ 12238 } 12239 } 12240 } 12241 12242 @Override performAccessibilityAction(long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid)12243 public void performAccessibilityAction(long accessibilityNodeId, int action, 12244 Bundle arguments, int interactionId, 12245 IAccessibilityInteractionConnectionCallback callback, int flags, 12246 int interrogatingPid, long interrogatingTid) { 12247 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 12248 if (viewRootImpl != null && viewRootImpl.mView != null) { 12249 viewRootImpl.getAccessibilityInteractionController() 12250 .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments, 12251 interactionId, callback, flags, interrogatingPid, interrogatingTid); 12252 } else { 12253 // We cannot make the call and notify the caller so it does not wait. 12254 try { 12255 callback.setPerformAccessibilityActionResult(false, interactionId); 12256 } catch (RemoteException re) { 12257 /* best effort - ignore */ 12258 } 12259 } 12260 } 12261 12262 @Override findAccessibilityNodeInfosByViewId(long accessibilityNodeId, String viewId, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix)12263 public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId, 12264 String viewId, Region interactiveRegion, int interactionId, 12265 IAccessibilityInteractionConnectionCallback callback, int flags, 12266 int interrogatingPid, long interrogatingTid, MagnificationSpec spec, 12267 float[] matrix) { 12268 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 12269 if (viewRootImpl != null && viewRootImpl.mView != null) { 12270 viewRootImpl.getAccessibilityInteractionController() 12271 .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId, 12272 viewId, interactiveRegion, interactionId, callback, flags, 12273 interrogatingPid, interrogatingTid, spec, matrix); 12274 } else { 12275 // We cannot make the call and notify the caller so it does not wait. 12276 try { 12277 callback.setFindAccessibilityNodeInfoResult(null, interactionId); 12278 } catch (RemoteException re) { 12279 /* best effort - ignore */ 12280 } 12281 } 12282 } 12283 12284 @Override findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix)12285 public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, 12286 Region interactiveRegion, int interactionId, 12287 IAccessibilityInteractionConnectionCallback callback, int flags, 12288 int interrogatingPid, long interrogatingTid, MagnificationSpec spec, 12289 float[] matrix) { 12290 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 12291 if (viewRootImpl != null && viewRootImpl.mView != null) { 12292 viewRootImpl.getAccessibilityInteractionController() 12293 .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text, 12294 interactiveRegion, interactionId, callback, flags, interrogatingPid, 12295 interrogatingTid, spec, matrix); 12296 } else { 12297 // We cannot make the call and notify the caller so it does not wait. 12298 try { 12299 callback.setFindAccessibilityNodeInfosResult(null, interactionId); 12300 } catch (RemoteException re) { 12301 /* best effort - ignore */ 12302 } 12303 } 12304 } 12305 12306 @Override findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix)12307 public void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion, 12308 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, 12309 int interrogatingPid, long interrogatingTid, MagnificationSpec spec, 12310 float[] matrix) { 12311 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 12312 if (viewRootImpl != null && viewRootImpl.mView != null) { 12313 viewRootImpl.getAccessibilityInteractionController() 12314 .findFocusClientThread(accessibilityNodeId, focusType, interactiveRegion, 12315 interactionId, callback, flags, interrogatingPid, interrogatingTid, 12316 spec, matrix); 12317 } else { 12318 // We cannot make the call and notify the caller so it does not wait. 12319 try { 12320 callback.setFindAccessibilityNodeInfoResult(null, interactionId); 12321 } catch (RemoteException re) { 12322 /* best effort - ignore */ 12323 } 12324 } 12325 } 12326 12327 @Override focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix)12328 public void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion, 12329 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, 12330 int interrogatingPid, long interrogatingTid, MagnificationSpec spec, 12331 float[] matrix) { 12332 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 12333 if (viewRootImpl != null && viewRootImpl.mView != null) { 12334 viewRootImpl.getAccessibilityInteractionController() 12335 .focusSearchClientThread(accessibilityNodeId, direction, interactiveRegion, 12336 interactionId, callback, flags, interrogatingPid, interrogatingTid, 12337 spec, matrix); 12338 } else { 12339 // We cannot make the call and notify the caller so it does not wait. 12340 try { 12341 callback.setFindAccessibilityNodeInfoResult(null, interactionId); 12342 } catch (RemoteException re) { 12343 /* best effort - ignore */ 12344 } 12345 } 12346 } 12347 12348 @Override clearAccessibilityFocus()12349 public void clearAccessibilityFocus() { 12350 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 12351 if (viewRootImpl != null && viewRootImpl.mView != null) { 12352 viewRootImpl.getAccessibilityInteractionController() 12353 .clearAccessibilityFocusClientThread(); 12354 } 12355 } 12356 12357 @Override notifyOutsideTouch()12358 public void notifyOutsideTouch() { 12359 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 12360 if (viewRootImpl != null && viewRootImpl.mView != null) { 12361 viewRootImpl.getAccessibilityInteractionController() 12362 .notifyOutsideTouchClientThread(); 12363 } 12364 } 12365 12366 @Override takeScreenshotOfWindow(int interactionId, ScreenCapture.ScreenCaptureListener listener, IAccessibilityInteractionConnectionCallback callback)12367 public void takeScreenshotOfWindow(int interactionId, 12368 ScreenCapture.ScreenCaptureListener listener, 12369 IAccessibilityInteractionConnectionCallback callback) { 12370 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 12371 if (viewRootImpl != null && viewRootImpl.mView != null) { 12372 viewRootImpl.getAccessibilityInteractionController() 12373 .takeScreenshotOfWindowClientThread(interactionId, listener, callback); 12374 } else { 12375 try { 12376 callback.sendTakeScreenshotOfWindowError( 12377 AccessibilityService.ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR, 12378 interactionId); 12379 } catch (RemoteException re) { 12380 /* best effort - ignore */ 12381 } 12382 } 12383 } 12384 12385 @Override getWindowSurfaceInfo(IWindowSurfaceInfoCallback callback)12386 public void getWindowSurfaceInfo(IWindowSurfaceInfoCallback callback) { 12387 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 12388 if (viewRootImpl != null && viewRootImpl.mView != null) { 12389 viewRootImpl.getAccessibilityInteractionController() 12390 .getWindowSurfaceInfoClientThread(callback); 12391 } 12392 } 12393 attachAccessibilityOverlayToWindow( SurfaceControl sc, int interactionId, IAccessibilityInteractionConnectionCallback callback)12394 public void attachAccessibilityOverlayToWindow( 12395 SurfaceControl sc, 12396 int interactionId, 12397 IAccessibilityInteractionConnectionCallback callback) { 12398 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 12399 if (viewRootImpl != null) { 12400 viewRootImpl 12401 .getAccessibilityInteractionController() 12402 .attachAccessibilityOverlayToWindowClientThread( 12403 sc, interactionId, callback); 12404 } 12405 } 12406 } 12407 12408 /** 12409 * Gets an accessibility embedded connection interface for this ViewRootImpl. 12410 * @hide 12411 */ getAccessibilityEmbeddedConnection()12412 public IAccessibilityEmbeddedConnection getAccessibilityEmbeddedConnection() { 12413 if (mAccessibilityEmbeddedConnection == null) { 12414 mAccessibilityEmbeddedConnection = new AccessibilityEmbeddedConnection( 12415 ViewRootImpl.this); 12416 } 12417 return mAccessibilityEmbeddedConnection; 12418 } 12419 12420 private class SendWindowContentChangedAccessibilityEvent implements Runnable { 12421 private int mChangeTypes = 0; 12422 12423 public View mSource; 12424 public long mLastEventTimeMillis; 12425 /** 12426 * Keep track of action that caused the event. 12427 * This is empty if there's no performing actions for pending events. 12428 * This is zero if there're multiple events performed for pending events. 12429 */ 12430 @NonNull public OptionalInt mAction = OptionalInt.empty(); 12431 /** 12432 * Override for {@link AccessibilityEvent#originStackTrace} to provide the stack trace 12433 * of the original {@link #runOrPost} call instead of one for sending the delayed event 12434 * from a looper. 12435 */ 12436 public StackTraceElement[] mOrigin; 12437 12438 @Override run()12439 public void run() { 12440 // Protect against re-entrant code and attempt to do the right thing in the case that 12441 // we're multithreaded. 12442 View source = mSource; 12443 mSource = null; 12444 if (source == null) { 12445 Log.e(TAG, "Accessibility content change has no source"); 12446 return; 12447 } 12448 // The accessibility may be turned off while we were waiting so check again. 12449 if (mAccessibilityManager.isEnabled()) { 12450 mLastEventTimeMillis = SystemClock.uptimeMillis(); 12451 AccessibilityEvent event = AccessibilityEvent.obtain(); 12452 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 12453 event.setContentChangeTypes(mChangeTypes); 12454 if (mAction.isPresent()) event.setAction(mAction.getAsInt()); 12455 if (AccessibilityEvent.DEBUG_ORIGIN) event.originStackTrace = mOrigin; 12456 source.sendAccessibilityEventUnchecked(event); 12457 } else { 12458 mLastEventTimeMillis = 0; 12459 } 12460 // In any case reset to initial state. 12461 source.resetSubtreeAccessibilityStateChanged(); 12462 mChangeTypes = 0; 12463 mAction = OptionalInt.empty(); 12464 if (AccessibilityEvent.DEBUG_ORIGIN) mOrigin = null; 12465 } 12466 runOrPost(View source, int changeType)12467 public void runOrPost(View source, int changeType) { 12468 if (mHandler.getLooper() != Looper.myLooper()) { 12469 CalledFromWrongThreadException e = new CalledFromWrongThreadException("Only the " 12470 + "original thread that created a view hierarchy can touch its views."); 12471 // TODO: Throw the exception 12472 Log.e(TAG, "Accessibility content change on non-UI thread. Future Android " 12473 + "versions will throw an exception.", e); 12474 // Attempt to recover. This code does not eliminate the thread safety issue, but 12475 // it should force any issues to happen near the above log. 12476 mHandler.removeCallbacks(this); 12477 if (mSource != null) { 12478 // Dispatch whatever was pending. It's still possible that the runnable started 12479 // just before we removed the callbacks, and bad things will happen, but at 12480 // least they should happen very close to the logged error. 12481 run(); 12482 } 12483 } 12484 12485 if (!canContinueThrottle(source, changeType)) { 12486 removeCallbacksAndRun(); 12487 } 12488 12489 if (mSource != null) { 12490 View newSource = getCommonPredecessor(mSource, source); 12491 if (newSource != null) { 12492 newSource = newSource.getSelfOrParentImportantForA11y(); 12493 } 12494 if (newSource == null) { 12495 // If there is no common predecessor, then mSource points to 12496 // a removed view, hence in this case always prefer the source. 12497 newSource = source; 12498 } 12499 12500 mChangeTypes |= changeType; 12501 if (mSource != newSource) { 12502 mChangeTypes |= AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE; 12503 mSource = newSource; 12504 } 12505 12506 final int performingAction = mAccessibilityManager.getPerformingAction(); 12507 if (performingAction != 0) { 12508 if (mAction.isEmpty()) { 12509 mAction = OptionalInt.of(performingAction); 12510 } else if (mAction.getAsInt() != performingAction) { 12511 // Multiple actions are performed for pending events. We cannot decide one 12512 // action here. 12513 // We're doing best effort to set action value, and it's fine to set 12514 // no action this case. 12515 mAction = OptionalInt.of(0); 12516 } 12517 } 12518 12519 return; 12520 } 12521 mSource = source; 12522 mChangeTypes = changeType; 12523 if (mAccessibilityManager.getPerformingAction() != 0) { 12524 mAction = OptionalInt.of(mAccessibilityManager.getPerformingAction()); 12525 } 12526 if (AccessibilityEvent.DEBUG_ORIGIN) { 12527 mOrigin = Thread.currentThread().getStackTrace(); 12528 } 12529 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis; 12530 final long minEventIntervalMillis = 12531 ViewConfiguration.getSendRecurringAccessibilityEventsInterval(); 12532 if (timeSinceLastMillis >= minEventIntervalMillis) { 12533 removeCallbacksAndRun(); 12534 } else { 12535 mHandler.postDelayed(this, minEventIntervalMillis - timeSinceLastMillis); 12536 } 12537 } 12538 removeCallbacksAndRun()12539 public void removeCallbacksAndRun() { 12540 mHandler.removeCallbacks(this); 12541 run(); 12542 } 12543 canContinueThrottle(View source, int changeType)12544 private boolean canContinueThrottle(View source, int changeType) { 12545 if (!reduceWindowContentChangedEventThrottle()) { 12546 // Old behavior. Always throttle. 12547 return true; 12548 } 12549 if (mSource == null) { 12550 // We don't have a pending event. 12551 return true; 12552 } 12553 if (mSource == source) { 12554 // We can merge a new event with a pending event from the same source. 12555 return true; 12556 } 12557 // We can merge subtree change events. 12558 return changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE 12559 && mChangeTypes == AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE; 12560 } 12561 } 12562 12563 private static class UnhandledKeyManager { 12564 // This is used to ensure that unhandled events are only dispatched once. We attempt 12565 // to dispatch more than once in order to achieve a certain order. Specifically, if we 12566 // are in an Activity or Dialog (and have a Window.Callback), the unhandled events should 12567 // be dispatched after the view hierarchy, but before the Callback. However, if we aren't 12568 // in an activity, we still want unhandled keys to be dispatched. 12569 private boolean mDispatched = true; 12570 12571 // Keeps track of which Views have unhandled key focus for which keys. This doesn't 12572 // include modifiers. 12573 private final SparseArray<WeakReference<View>> mCapturedKeys = new SparseArray<>(); 12574 12575 // The current receiver. This value is transient and used between the pre-dispatch and 12576 // pre-view phase to ensure that other input-stages don't interfere with tracking. 12577 private WeakReference<View> mCurrentReceiver = null; 12578 dispatch(View root, KeyEvent event)12579 boolean dispatch(View root, KeyEvent event) { 12580 if (mDispatched) { 12581 return false; 12582 } 12583 View consumer; 12584 try { 12585 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "UnhandledKeyEvent dispatch"); 12586 mDispatched = true; 12587 12588 consumer = root.dispatchUnhandledKeyEvent(event); 12589 12590 // If an unhandled listener handles one, then keep track of it so that the 12591 // consuming view is first to receive its repeats and release as well. 12592 if (event.getAction() == KeyEvent.ACTION_DOWN) { 12593 int keycode = event.getKeyCode(); 12594 if (consumer != null && !KeyEvent.isModifierKey(keycode)) { 12595 mCapturedKeys.put(keycode, new WeakReference<>(consumer)); 12596 } 12597 } 12598 } finally { 12599 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 12600 } 12601 return consumer != null; 12602 } 12603 12604 /** 12605 * Called before the event gets dispatched to anything 12606 */ preDispatch(KeyEvent event)12607 void preDispatch(KeyEvent event) { 12608 // Always clean-up 'up' events since it's possible for earlier dispatch stages to 12609 // consume them without consuming the corresponding 'down' event. 12610 mCurrentReceiver = null; 12611 if (event.getAction() == KeyEvent.ACTION_UP) { 12612 int idx = mCapturedKeys.indexOfKey(event.getKeyCode()); 12613 if (idx >= 0) { 12614 mCurrentReceiver = mCapturedKeys.valueAt(idx); 12615 mCapturedKeys.removeAt(idx); 12616 } 12617 } 12618 } 12619 12620 /** 12621 * Called before the event gets dispatched to the view hierarchy 12622 * @return {@code true} if an unhandled handler has focus and consumed the event 12623 */ preViewDispatch(KeyEvent event)12624 boolean preViewDispatch(KeyEvent event) { 12625 mDispatched = false; 12626 if (mCurrentReceiver == null) { 12627 mCurrentReceiver = mCapturedKeys.get(event.getKeyCode()); 12628 } 12629 if (mCurrentReceiver != null) { 12630 View target = mCurrentReceiver.get(); 12631 if (event.getAction() == KeyEvent.ACTION_UP) { 12632 mCurrentReceiver = null; 12633 } 12634 if (target != null && target.isAttachedToWindow()) { 12635 target.onUnhandledKeyEvent(event); 12636 } 12637 // consume anyways so that we don't feed uncaptured key events to other views 12638 return true; 12639 } 12640 return false; 12641 } 12642 } 12643 12644 /** 12645 * @hide 12646 */ setDisplayDecoration(boolean displayDecoration)12647 public void setDisplayDecoration(boolean displayDecoration) { 12648 if (displayDecoration == mDisplayDecorationCached) return; 12649 12650 mDisplayDecorationCached = displayDecoration; 12651 12652 if (mSurfaceControl.isValid()) { 12653 updateDisplayDecoration(); 12654 } 12655 } 12656 updateDisplayDecoration()12657 private void updateDisplayDecoration() { 12658 mTransaction.setDisplayDecoration(mSurfaceControl, mDisplayDecorationCached).apply(); 12659 } 12660 12661 /** 12662 * Sends a list of blur regions to SurfaceFlinger, tagged with a frame. 12663 * 12664 * @param regionCopy List of regions 12665 * @param frameNumber Frame where it should be applied (or current when using BLAST) 12666 */ dispatchBlurRegions(float[][] regionCopy, long frameNumber)12667 public void dispatchBlurRegions(float[][] regionCopy, long frameNumber) { 12668 final SurfaceControl surfaceControl = getSurfaceControl(); 12669 if (!surfaceControl.isValid()) { 12670 return; 12671 } 12672 12673 SurfaceControl.Transaction transaction = new SurfaceControl.Transaction(); 12674 transaction.setBlurRegions(surfaceControl, regionCopy); 12675 12676 if (mBlastBufferQueue != null) { 12677 transaction.onMergeWithNextTransaction(getTitle()); 12678 mBlastBufferQueue.mergeWithNextTransaction(transaction, frameNumber); 12679 } 12680 } 12681 12682 /** 12683 * Creates a background blur drawable for the backing {@link Surface}. 12684 */ createBackgroundBlurDrawable()12685 public BackgroundBlurDrawable createBackgroundBlurDrawable() { 12686 return mBlurRegionAggregator.createBackgroundBlurDrawable(mContext); 12687 } 12688 12689 @Override onDescendantUnbufferedRequested()12690 public void onDescendantUnbufferedRequested() { 12691 mUnbufferedInputSource = mView.mUnbufferedInputSource; 12692 } 12693 getSurfaceSequenceId()12694 int getSurfaceSequenceId() { 12695 return mSurfaceSequenceId; 12696 } 12697 12698 /** 12699 * Merges the transaction passed in with the next transaction in BLASTBufferQueue. This ensures 12700 * you can add transactions to the upcoming frame. 12701 */ mergeWithNextTransaction(Transaction t, long frameNumber)12702 public void mergeWithNextTransaction(Transaction t, long frameNumber) { 12703 if (mBlastBufferQueue != null) { 12704 if (t != null) { 12705 t.onMergeWithNextTransaction(getTitle()); 12706 } 12707 mBlastBufferQueue.mergeWithNextTransaction(t, frameNumber); 12708 } else { 12709 t.apply(); 12710 } 12711 } 12712 12713 @Override buildReparentTransaction( @onNull SurfaceControl child)12714 @Nullable public SurfaceControl.Transaction buildReparentTransaction( 12715 @NonNull SurfaceControl child) { 12716 if (mSurfaceControl.isValid()) { 12717 Transaction t = new Transaction(); 12718 return t.reparent(child, updateAndGetBoundsLayer(t)); 12719 } 12720 return null; 12721 } 12722 12723 @Override applyTransactionOnDraw(@onNull SurfaceControl.Transaction t)12724 public boolean applyTransactionOnDraw(@NonNull SurfaceControl.Transaction t) { 12725 if (mRemoved || !isHardwareEnabled()) { 12726 logAndTrace("applyTransactionOnDraw applyImmediately"); 12727 t.apply(); 12728 } else { 12729 Trace.instant(Trace.TRACE_TAG_VIEW, "applyTransactionOnDraw-" + mTag); 12730 // Copy and clear the passed in transaction for thread safety. The new transaction is 12731 // accessed on the render thread. 12732 mPendingTransaction.merge(t); 12733 mHasPendingTransactions = true; 12734 } 12735 return true; 12736 } 12737 12738 @Override getBufferTransformHint()12739 public @SurfaceControl.BufferTransform int getBufferTransformHint() { 12740 // TODO(b/326482114) We use mPreviousTransformHint (calculated using mDisplay's rotation) 12741 // instead of mSurfaceControl#getTransformHint because there's a race where SurfaceFlinger 12742 // can set an incorrect transform hint for a few frames before it is aware of the updated 12743 // display rotation. 12744 if (enableBufferTransformHintFromDisplay()) { 12745 return mPreviousTransformHint; 12746 } 12747 12748 if (mSurfaceControl.isValid()) { 12749 return mSurfaceControl.getTransformHint(); 12750 } else { 12751 return SurfaceControl.BUFFER_TRANSFORM_IDENTITY; 12752 } 12753 } 12754 12755 @Override addOnBufferTransformHintChangedListener( OnBufferTransformHintChangedListener listener)12756 public void addOnBufferTransformHintChangedListener( 12757 OnBufferTransformHintChangedListener listener) { 12758 Objects.requireNonNull(listener); 12759 if (mTransformHintListeners.contains(listener)) { 12760 throw new IllegalArgumentException( 12761 "attempt to call addOnBufferTransformHintChangedListener() " 12762 + "with a previously registered listener"); 12763 } 12764 mTransformHintListeners.add(listener); 12765 } 12766 12767 @Override removeOnBufferTransformHintChangedListener( OnBufferTransformHintChangedListener listener)12768 public void removeOnBufferTransformHintChangedListener( 12769 OnBufferTransformHintChangedListener listener) { 12770 Objects.requireNonNull(listener); 12771 mTransformHintListeners.remove(listener); 12772 } 12773 dispatchTransformHintChanged(@urfaceControl.BufferTransform int hint)12774 private void dispatchTransformHintChanged(@SurfaceControl.BufferTransform int hint) { 12775 if (mTransformHintListeners.isEmpty()) { 12776 return; 12777 } 12778 ArrayList<OnBufferTransformHintChangedListener> listeners = 12779 (ArrayList<OnBufferTransformHintChangedListener>) mTransformHintListeners.clone(); 12780 for (int i = 0; i < listeners.size(); i++) { 12781 OnBufferTransformHintChangedListener listener = listeners.get(i); 12782 listener.onBufferTransformHintChanged(hint); 12783 } 12784 } 12785 wasRelayoutRequested()12786 boolean wasRelayoutRequested() { 12787 return mRelayoutRequested; 12788 } 12789 forceWmRelayout()12790 void forceWmRelayout() { 12791 mForceNextWindowRelayout = true; 12792 scheduleTraversals(); 12793 } 12794 12795 /** 12796 * Returns the {@link OnBackInvokedDispatcher} on the decor view if one exists, or the 12797 * fallback {@link OnBackInvokedDispatcher} instance. 12798 */ 12799 @NonNull getOnBackInvokedDispatcher()12800 public WindowOnBackInvokedDispatcher getOnBackInvokedDispatcher() { 12801 return mOnBackInvokedDispatcher; 12802 } 12803 12804 @NonNull 12805 @Override findOnBackInvokedDispatcherForChild( @onNull View child, @NonNull View requester)12806 public OnBackInvokedDispatcher findOnBackInvokedDispatcherForChild( 12807 @NonNull View child, @NonNull View requester) { 12808 return getOnBackInvokedDispatcher(); 12809 } 12810 12811 /** 12812 * When this ViewRootImpl is added to the window manager, transfers the first 12813 * {@link OnBackInvokedCallback} to be called to the server. 12814 */ registerBackCallbackOnWindow()12815 private void registerBackCallbackOnWindow() { 12816 if (OnBackInvokedDispatcher.DEBUG) { 12817 Log.d(OnBackInvokedDispatcher.TAG, TextUtils.formatSimple( 12818 "ViewRootImpl.registerBackCallbackOnWindow. Dispatcher:%s Package:%s " 12819 + "IWindow:%s Session:%s", 12820 mOnBackInvokedDispatcher, mBasePackageName, mWindow, mWindowSession)); 12821 } 12822 mOnBackInvokedDispatcher.attachToWindow(mWindowSession, mWindow, this, 12823 mImeBackAnimationController); 12824 } 12825 12826 /** 12827 * Sends {@link KeyEvent#ACTION_DOWN ACTION_DOWN} and {@link KeyEvent#ACTION_UP ACTION_UP} 12828 * back key events 12829 * 12830 * @param preImeOnly whether the back events should be sent to the pre-ime stage only 12831 * @return whether the event was handled (i.e. onKeyPreIme consumed it if preImeOnly=true) 12832 */ injectBackKeyEvents(boolean preImeOnly)12833 public boolean injectBackKeyEvents(boolean preImeOnly) { 12834 sendBackKeyEvent(KeyEvent.ACTION_DOWN, preImeOnly); 12835 return sendBackKeyEvent(KeyEvent.ACTION_UP, preImeOnly); 12836 } 12837 sendBackKeyEvent(int action, boolean preImeOnly)12838 private boolean sendBackKeyEvent(int action, boolean preImeOnly) { 12839 long when = SystemClock.uptimeMillis(); 12840 final KeyEvent ev = new KeyEvent(when, when, action, 12841 KeyEvent.KEYCODE_BACK, 0 /* repeat */, 0 /* metaState */, 12842 KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */, 12843 KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY, 12844 InputDevice.SOURCE_KEYBOARD); 12845 int flags = preImeOnly ? QueuedInputEvent.FLAG_PRE_IME_ONLY : 0; 12846 QueuedInputEvent q = enqueueInputEvent(ev, null /* receiver */, flags, 12847 true /* processImmediately */); 12848 return (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0; 12849 } 12850 registerCompatOnBackInvokedCallback()12851 private void registerCompatOnBackInvokedCallback() { 12852 mCompatOnBackInvokedCallback = () -> { 12853 injectBackKeyEvents(/* preImeOnly */ false); 12854 }; 12855 if (mOnBackInvokedDispatcher.hasImeOnBackInvokedDispatcher()) { 12856 Log.d(TAG, "Skip registering CompatOnBackInvokedCallback on IME dispatcher"); 12857 return; 12858 } 12859 mOnBackInvokedDispatcher.registerOnBackInvokedCallback( 12860 OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCompatOnBackInvokedCallback); 12861 } 12862 12863 @Override setTouchableRegion(Region r)12864 public void setTouchableRegion(Region r) { 12865 if (r != null) { 12866 mTouchableRegion = new Region(r); 12867 } else { 12868 mTouchableRegion = null; 12869 } 12870 mLastGivenInsets.reset(); 12871 requestLayout(); 12872 } 12873 getWindowSession()12874 IWindowSession getWindowSession() { 12875 return mWindowSession; 12876 } 12877 registerCallbacksForSync(boolean syncBuffer, final SurfaceSyncGroup surfaceSyncGroup)12878 private void registerCallbacksForSync(boolean syncBuffer, 12879 final SurfaceSyncGroup surfaceSyncGroup) { 12880 if (!isHardwareEnabled()) { 12881 return; 12882 } 12883 12884 if (DEBUG_BLAST) { 12885 Log.d(mTag, "registerCallbacksForSync syncBuffer=" + syncBuffer); 12886 } 12887 12888 final Transaction t; 12889 if (mHasPendingTransactions) { 12890 t = new Transaction(); 12891 t.merge(mPendingTransaction); 12892 mHasPendingTransactions = false; 12893 } else { 12894 t = null; 12895 } 12896 12897 mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() { 12898 @Override 12899 public void onFrameDraw(long frame) { 12900 } 12901 12902 @Override 12903 public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) { 12904 if (DEBUG_BLAST) { 12905 Log.d(mTag, 12906 "Received frameDrawingCallback syncResult=" + syncResult + " frameNum=" 12907 + frame + "."); 12908 } 12909 if (t != null) { 12910 mergeWithNextTransaction(t, frame); 12911 } 12912 12913 // If the syncResults are SYNC_LOST_SURFACE_REWARD_IF_FOUND or 12914 // SYNC_CONTEXT_IS_STOPPED it means nothing will draw. There's no need to set up 12915 // any blast sync or commit callback, and the code should directly call 12916 // pendingDrawFinished. 12917 if ((syncResult 12918 & (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) { 12919 surfaceSyncGroup.addTransaction( 12920 mBlastBufferQueue.gatherPendingTransactions(frame)); 12921 surfaceSyncGroup.markSyncReady(); 12922 return null; 12923 } 12924 12925 if (DEBUG_BLAST) { 12926 Log.d(mTag, "Setting up sync and frameCommitCallback"); 12927 } 12928 12929 if (syncBuffer) { 12930 boolean result = mBlastBufferQueue.syncNextTransaction(transaction -> { 12931 Runnable timeoutRunnable = () -> Log.e(mTag, 12932 "Failed to submit the sync transaction after 4s. Likely to ANR " 12933 + "soon"); 12934 mHandler.postDelayed(timeoutRunnable, 4000L * Build.HW_TIMEOUT_MULTIPLIER); 12935 transaction.addTransactionCommittedListener(mSimpleExecutor, 12936 () -> mHandler.removeCallbacks(timeoutRunnable)); 12937 surfaceSyncGroup.addTransaction(transaction); 12938 surfaceSyncGroup.markSyncReady(); 12939 }); 12940 if (!result) { 12941 // syncNextTransaction can only return false if something is already trying 12942 // to sync the same frame in the same BBQ. That shouldn't be possible, but 12943 // if it did happen, invoke markSyncReady so the active SSG doesn't get 12944 // stuck. 12945 Log.w(mTag, "Unable to syncNextTransaction. Possibly something else is" 12946 + " trying to sync?"); 12947 surfaceSyncGroup.markSyncReady(); 12948 } 12949 } 12950 12951 return didProduceBuffer -> { 12952 if (DEBUG_BLAST) { 12953 Log.d(mTag, "Received frameCommittedCallback" 12954 + " lastAttemptedDrawFrameNum=" + frame 12955 + " didProduceBuffer=" + didProduceBuffer); 12956 } 12957 12958 // If frame wasn't drawn, clear out the next transaction so it doesn't affect 12959 // the next draw attempt. The next transaction and transaction complete callback 12960 // were only set for the current draw attempt. 12961 if (!didProduceBuffer) { 12962 mBlastBufferQueue.clearSyncTransaction(); 12963 12964 // Gather the transactions that were sent to mergeWithNextTransaction 12965 // since the frame didn't draw on this vsync. It's possible the frame will 12966 // draw later, but it's better to not be sync than to block on a frame that 12967 // may never come. 12968 surfaceSyncGroup.addTransaction( 12969 mBlastBufferQueue.gatherPendingTransactions(frame)); 12970 surfaceSyncGroup.markSyncReady(); 12971 return; 12972 } 12973 12974 // If we didn't request to sync a buffer, then we won't get the 12975 // syncNextTransaction callback. Instead, just report back to the Syncer so it 12976 // knows that this sync request is complete. 12977 if (!syncBuffer) { 12978 surfaceSyncGroup.markSyncReady(); 12979 } 12980 }; 12981 } 12982 }); 12983 } 12984 12985 /** 12986 * This code will ensure that if multiple SurfaceSyncGroups are created for the same 12987 * ViewRootImpl the SurfaceSyncGroups will maintain an order. The scenario that could occur 12988 * is the following: 12989 * <p> 12990 * 1. SSG1 is created that includes the target VRI. There could be other VRIs in SSG1 12991 * 2. The target VRI draws its frame and marks its own active SSG as ready, but SSG1 is still 12992 * waiting on other things in the SSG 12993 * 3. Another SSG2 is created for the target VRI. The second frame renders and marks its own 12994 * second SSG as complete. SSG2 has nothing else to wait on, so it will apply at this point, 12995 * even though SSG1 has not finished. 12996 * 4. Frame2 will get to SF first and Frame1 will later get to SF when SSG1 completes. 12997 * <p> 12998 * The code below ensures the SSGs that contains the VRI maintain an order. We create a new SSG 12999 * that's a safeguard SSG. Its only job is to prevent the next active SSG from completing. 13000 * The current active SSG for VRI will add a transaction committed callback and when that's 13001 * invoked, it will mark the safeguard SSG as ready. If a new request to create a SSG comes 13002 * in and the safeguard SSG is not null, it's added as part of the new active SSG. A new 13003 * safeguard SSG is created to correspond to the new active SSG. This creates a chain to 13004 * ensure the latter SSG always waits for the former SSG's transaction to get to SF. 13005 */ safeguardOverlappingSyncs(SurfaceSyncGroup activeSurfaceSyncGroup)13006 private void safeguardOverlappingSyncs(SurfaceSyncGroup activeSurfaceSyncGroup) { 13007 SurfaceSyncGroup safeguardSsg = new SurfaceSyncGroup("Safeguard-" + mTag); 13008 // Always disable timeout on the safeguard sync 13009 safeguardSsg.toggleTimeout(false /* enable */); 13010 synchronized (mPreviousSyncSafeguardLock) { 13011 if (mPreviousSyncSafeguard != null) { 13012 activeSurfaceSyncGroup.add(mPreviousSyncSafeguard, null /* runnable */); 13013 // Temporarily disable the timeout on the SSG that will contain the buffer. This 13014 // is to ensure we don't timeout the active SSG before the previous one completes to 13015 // ensure the order is maintained. The previous SSG has a timeout on its own SSG 13016 // so it's guaranteed to complete. 13017 activeSurfaceSyncGroup.toggleTimeout(false /* enable */); 13018 mPreviousSyncSafeguard.addSyncCompleteCallback(mSimpleExecutor, () -> { 13019 // Once we receive that the previous sync guard has been invoked, we can re-add 13020 // the timeout on the active sync to ensure we eventually complete so it's not 13021 // stuck permanently. 13022 activeSurfaceSyncGroup.toggleTimeout(true /*enable */); 13023 }); 13024 } 13025 mPreviousSyncSafeguard = safeguardSsg; 13026 } 13027 13028 Transaction t = new Transaction(); 13029 t.addTransactionCommittedListener(mSimpleExecutor, () -> { 13030 safeguardSsg.markSyncReady(); 13031 synchronized (mPreviousSyncSafeguardLock) { 13032 if (mPreviousSyncSafeguard == safeguardSsg) { 13033 mPreviousSyncSafeguard = null; 13034 } 13035 } 13036 }); 13037 activeSurfaceSyncGroup.addTransaction(t); 13038 } 13039 13040 /** 13041 * Resume rendering after being paused for sync due to a timeout. 13042 */ resumeAfterSyncTimeout()13043 private void resumeAfterSyncTimeout() { 13044 Log.e(mTag, "Timedout waiting to unpause for sync mNumPausedForSync=" + mNumPausedForSync); 13045 mNumPausedForSync = 0; 13046 scheduleTraversals(); 13047 } 13048 13049 @Override getOrCreateSurfaceSyncGroup()13050 public SurfaceSyncGroup getOrCreateSurfaceSyncGroup() { 13051 boolean newSyncGroup = false; 13052 if (mActiveSurfaceSyncGroup == null) { 13053 mActiveSurfaceSyncGroup = new SurfaceSyncGroup(mTag); 13054 mActiveSurfaceSyncGroup.setAddedToSyncListener(() -> { 13055 Runnable runnable = () -> { 13056 // Check if it's already 0 because the timeout could have reset the count to 13057 // 0 and we don't want to go negative. 13058 if (mNumPausedForSync > 0) { 13059 mNumPausedForSync--; 13060 } 13061 if (mNumPausedForSync == 0) { 13062 mHandler.removeMessages(MSG_PAUSED_FOR_SYNC_TIMEOUT); 13063 if (!mIsInTraversal) { 13064 scheduleTraversals(); 13065 } 13066 } 13067 }; 13068 13069 if (Thread.currentThread() == mThread) { 13070 runnable.run(); 13071 } else { 13072 mHandler.post(runnable); 13073 } 13074 }); 13075 newSyncGroup = true; 13076 13077 // If the sync group is marked ready by a timeout, check if rendering is paused and 13078 // if it is, resume rendering and trigger a traversal. 13079 mActiveSurfaceSyncGroup.addSyncCompleteCallback(mExecutor, () -> { 13080 if (mActiveSurfaceSyncGroup != null 13081 && mActiveSurfaceSyncGroup.isComplete() && mNumPausedForSync > 0) { 13082 mHandler.removeMessages(MSG_PAUSED_FOR_SYNC_TIMEOUT); 13083 resumeAfterSyncTimeout(); 13084 } 13085 }); 13086 } 13087 13088 Trace.instant(Trace.TRACE_TAG_VIEW, 13089 "getOrCreateSurfaceSyncGroup isNew=" + newSyncGroup + " " + mTag); 13090 13091 if (DEBUG_BLAST) { 13092 if (newSyncGroup) { 13093 Log.d(mTag, "Creating new active sync group " + mActiveSurfaceSyncGroup.getName()); 13094 } else { 13095 Log.d(mTag, "Return already created active sync group " 13096 + mActiveSurfaceSyncGroup.getName()); 13097 } 13098 } 13099 13100 // The sync group can be marked ready by a timeout. This makes incrementing 13101 // mNumPausedForSync racy. Here we check if the sync group is complete and 13102 // if it is then we don't pause for syncing. 13103 if (!mActiveSurfaceSyncGroup.isComplete()) { 13104 mNumPausedForSync++; 13105 mHandler.removeMessages(MSG_PAUSED_FOR_SYNC_TIMEOUT); 13106 mHandler.sendEmptyMessageDelayed(MSG_PAUSED_FOR_SYNC_TIMEOUT, 13107 1000 * Build.HW_TIMEOUT_MULTIPLIER); 13108 } else { 13109 Log.d(mTag, "Active sync group is already completed " 13110 + mActiveSurfaceSyncGroup.getName()); 13111 } 13112 return mActiveSurfaceSyncGroup; 13113 } 13114 13115 private final Executor mSimpleExecutor = Runnable::run; 13116 updateSyncInProgressCount(SurfaceSyncGroup syncGroup)13117 private void updateSyncInProgressCount(SurfaceSyncGroup syncGroup) { 13118 if (mAttachInfo.mThreadedRenderer == null) { 13119 return; 13120 } 13121 13122 synchronized (sSyncProgressLock) { 13123 if (sNumSyncsInProgress++ == 0) { 13124 HardwareRenderer.setRtAnimationsEnabled(false); 13125 } 13126 } 13127 13128 syncGroup.addSyncCompleteCallback(mSimpleExecutor, () -> { 13129 synchronized (sSyncProgressLock) { 13130 if (--sNumSyncsInProgress == 0) { 13131 HardwareRenderer.setRtAnimationsEnabled(true); 13132 } 13133 } 13134 }); 13135 } 13136 addToSync(SurfaceSyncGroup syncable)13137 void addToSync(SurfaceSyncGroup syncable) { 13138 if (mActiveSurfaceSyncGroup == null) { 13139 return; 13140 } 13141 mActiveSurfaceSyncGroup.add(syncable, null /* Runnable */); 13142 } 13143 13144 @Override setChildBoundingInsets(@onNull Rect insets)13145 public void setChildBoundingInsets(@NonNull Rect insets) { 13146 if (insets.left < 0 || insets.top < 0 || insets.right < 0 || insets.bottom < 0) { 13147 throw new IllegalArgumentException("Negative insets passed to setChildBoundingInsets."); 13148 } 13149 mChildBoundingInsets.set(insets); 13150 mChildBoundingInsetsChanged = true; 13151 scheduleTraversals(); 13152 } 13153 13154 logAndTrace(String msg)13155 private void logAndTrace(String msg) { 13156 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 13157 Trace.instant(Trace.TRACE_TAG_VIEW, mTag + "-" + msg); 13158 } 13159 if (DEBUG_BLAST) { 13160 Log.d(mTag, msg); 13161 } 13162 EventLog.writeEvent(LOGTAG_VIEWROOT_DRAW_EVENT, mTag, msg); 13163 } 13164 13165 /** 13166 * Views that are animating with the ThreadedRenderer don't use the normal invalidation 13167 * path, so the value won't be updated through performTraversals. This reads the votes 13168 * from those views. 13169 */ updateFrameRateFromThreadedRendererViews()13170 private void updateFrameRateFromThreadedRendererViews() { 13171 ArrayList<View> views = mThreadedRendererViews; 13172 for (int i = views.size() - 1; i >= 0; i--) { 13173 View view = views.get(i); 13174 View.AttachInfo attachInfo = view.mAttachInfo; 13175 if (attachInfo == null || attachInfo.mViewRootImpl != this) { 13176 views.remove(i); 13177 } else { 13178 view.votePreferredFrameRate(); 13179 } 13180 } 13181 } 13182 13183 /** 13184 * Sets the mPreferredFrameRateCategory from the high, high_hint, normal, and low counts. 13185 */ setCategoryFromCategoryCounts()13186 private void setCategoryFromCategoryCounts() { 13187 switch (mPreferredFrameRateCategory) { 13188 case FRAME_RATE_CATEGORY_LOW -> mFrameRateCategoryLowCount = FRAME_RATE_CATEGORY_COUNT; 13189 case FRAME_RATE_CATEGORY_NORMAL -> 13190 mFrameRateCategoryNormalCount = FRAME_RATE_CATEGORY_COUNT; 13191 case FRAME_RATE_CATEGORY_HIGH_HINT -> 13192 mFrameRateCategoryHighHintCount = FRAME_RATE_CATEGORY_COUNT; 13193 case FRAME_RATE_CATEGORY_HIGH -> 13194 mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT; 13195 } 13196 13197 13198 if (mFrameRateCategoryHighCount > 0) { 13199 mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH; 13200 } else if (mFrameRateCategoryHighHintCount > 0) { 13201 mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH_HINT; 13202 } else if (mFrameRateCategoryNormalCount > 0) { 13203 mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NORMAL; 13204 } else if (mFrameRateCategoryLowCount > 0) { 13205 mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_LOW; 13206 } 13207 } 13208 setPreferredFrameRateCategory(int preferredFrameRateCategory)13209 private void setPreferredFrameRateCategory(int preferredFrameRateCategory) { 13210 if (!shouldSetFrameRateCategory()) { 13211 return; 13212 } 13213 13214 int frameRateCategory; 13215 int frameRateReason; 13216 String view; 13217 13218 if (mIsFrameRateBoosting || mInsetsAnimationRunning) { 13219 frameRateCategory = FRAME_RATE_CATEGORY_HIGH; 13220 frameRateReason = FRAME_RATE_CATEGORY_REASON_BOOST; 13221 view = null; 13222 } else if (mIsTouchBoosting && preferredFrameRateCategory < FRAME_RATE_CATEGORY_HIGH_HINT) { 13223 frameRateCategory = FRAME_RATE_CATEGORY_HIGH_HINT; 13224 frameRateReason = FRAME_RATE_CATEGORY_REASON_TOUCH; 13225 view = null; 13226 } else { 13227 frameRateCategory = preferredFrameRateCategory; 13228 frameRateReason = mFrameRateCategoryChangeReason; 13229 view = mFrameRateCategoryView; 13230 } 13231 13232 boolean traceFrameRateCategory = false; 13233 try { 13234 if ((frameRateCategory != FRAME_RATE_CATEGORY_DEFAULT 13235 && mLastPreferredFrameRateCategory != frameRateCategory) 13236 || mSurfaceReplaced) { 13237 traceFrameRateCategory = Trace.isTagEnabled(Trace.TRACE_TAG_VIEW); 13238 if (traceFrameRateCategory) { 13239 String reason = reasonToString(frameRateReason); 13240 String sourceView = view == null ? "-" : view; 13241 String category = categoryToString(frameRateCategory); 13242 Trace.traceBegin( 13243 Trace.TRACE_TAG_VIEW, "ViewRootImpl#setFrameRateCategory " 13244 + category + ", reason " + reason + ", " 13245 + sourceView); 13246 } 13247 if (sToolkitFrameRateFunctionEnablingReadOnlyFlagValue) { 13248 mFrameRateTransaction.setFrameRateCategory(mSurfaceControl, 13249 frameRateCategory, false).applyAsyncUnsafe(); 13250 13251 if (sToolkitFrameRateDebugFlagValue) { 13252 Log.v(mTag, "### ViewRootImpl setFrameRateCategory '" 13253 + categoryToString(frameRateCategory) + "'"); 13254 } 13255 } 13256 mLastPreferredFrameRateCategory = frameRateCategory; 13257 } 13258 } catch (Exception e) { 13259 Log.e(mTag, "Unable to set frame rate category", e); 13260 } finally { 13261 if (traceFrameRateCategory) { 13262 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 13263 } 13264 } 13265 } 13266 categoryToString(int frameRateCategory)13267 static String categoryToString(int frameRateCategory) { 13268 String category; 13269 switch (frameRateCategory) { 13270 case FRAME_RATE_CATEGORY_NO_PREFERENCE -> category = "no preference"; 13271 case FRAME_RATE_CATEGORY_LOW -> category = "low"; 13272 case FRAME_RATE_CATEGORY_NORMAL -> category = "normal"; 13273 case FRAME_RATE_CATEGORY_HIGH_HINT -> category = "high hint"; 13274 case FRAME_RATE_CATEGORY_HIGH -> category = "high"; 13275 default -> category = "default"; 13276 } 13277 return category; 13278 } 13279 reasonToString(int reason)13280 private static String reasonToString(int reason) { 13281 String str; 13282 switch (reason) { 13283 case FRAME_RATE_CATEGORY_REASON_INTERMITTENT -> str = "intermittent"; 13284 case FRAME_RATE_CATEGORY_REASON_SMALL -> str = "small"; 13285 case FRAME_RATE_CATEGORY_REASON_LARGE -> str = "large"; 13286 case FRAME_RATE_CATEGORY_REASON_REQUESTED -> str = "requested"; 13287 case FRAME_RATE_CATEGORY_REASON_INVALID -> str = "invalid frame rate"; 13288 case FRAME_RATE_CATEGORY_REASON_VELOCITY -> str = "velocity"; 13289 case FRAME_RATE_CATEGORY_REASON_UNKNOWN -> str = "unknown"; 13290 case FRAME_RATE_CATEGORY_REASON_BOOST -> str = "boost"; 13291 case FRAME_RATE_CATEGORY_REASON_TOUCH -> str = "touch"; 13292 case FRAME_RATE_CATEGORY_REASON_CONFLICTED -> str = "conflicted"; 13293 default -> str = String.valueOf(reason); 13294 } 13295 return str; 13296 } 13297 setPreferredFrameRate(float preferredFrameRate)13298 private void setPreferredFrameRate(float preferredFrameRate) { 13299 if (!shouldSetFrameRate() || preferredFrameRate < 0) { 13300 return; 13301 } 13302 13303 boolean traceFrameRate = false; 13304 try { 13305 if (mLastPreferredFrameRate != preferredFrameRate || mSurfaceReplaced) { 13306 traceFrameRate = Trace.isTagEnabled(Trace.TRACE_TAG_VIEW); 13307 if (traceFrameRate) { 13308 Trace.traceBegin( 13309 Trace.TRACE_TAG_VIEW, "ViewRootImpl#setFrameRate " 13310 + preferredFrameRate + " compatibility " 13311 + mFrameRateCompatibility); 13312 } 13313 if (sToolkitFrameRateFunctionEnablingReadOnlyFlagValue) { 13314 if (preferredFrameRate > 0) { 13315 mFrameRateTransaction.setFrameRate(mSurfaceControl, preferredFrameRate, 13316 mFrameRateCompatibility); 13317 if (sToolkitFrameRateDebugFlagValue) { 13318 Log.v(mTag, "### ViewRootImpl setFrameRate '" 13319 + preferredFrameRate + "'"); 13320 } 13321 } else { 13322 mFrameRateTransaction.clearFrameRate(mSurfaceControl); 13323 if (sToolkitFrameRateDebugFlagValue) { 13324 Log.v(mTag, "### ViewRootImpl setFrameRate 0 Hz"); 13325 } 13326 } 13327 mFrameRateTransaction.applyAsyncUnsafe(); 13328 } 13329 mLastPreferredFrameRate = preferredFrameRate; 13330 } 13331 } catch (Exception e) { 13332 Log.e(mTag, "Unable to set frame rate", e); 13333 } finally { 13334 if (traceFrameRate) { 13335 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 13336 } 13337 } 13338 } 13339 shouldSetFrameRateCategory()13340 private boolean shouldSetFrameRateCategory() { 13341 // use toolkitSetFrameRate flag to gate the change 13342 return shouldEnableDvrr() && mSurface.isValid(); 13343 } 13344 shouldSetFrameRate()13345 private boolean shouldSetFrameRate() { 13346 // use toolkitSetFrameRate flag to gate the change 13347 return shouldEnableDvrr() && mSurface.isValid() && mPreferredFrameRate >= 0 13348 && !mIsFrameRateConflicted; 13349 } 13350 shouldTouchBoost(int motionEventAction, int windowType)13351 private boolean shouldTouchBoost(int motionEventAction, int windowType) { 13352 // boost for almost all input 13353 boolean desiredAction = motionEventAction != MotionEvent.ACTION_OUTSIDE; 13354 boolean undesiredType = windowType == TYPE_INPUT_METHOD 13355 && sToolkitFrameRateTypingReadOnlyFlagValue; 13356 13357 // don't suppress touch boost for TYPE_INPUT_METHOD in ViewRootImpl 13358 if (toolkitFrameRateTouchBoost25q1()) { 13359 return desiredAction && shouldEnableDvrr() && getFrameRateBoostOnTouchEnabled(); 13360 } 13361 // use toolkitSetFrameRate flag to gate the change 13362 return desiredAction && !undesiredType && shouldEnableDvrr() 13363 && getFrameRateBoostOnTouchEnabled(); 13364 } 13365 13366 /** 13367 * Allow Views to vote for the preferred frame rate category 13368 * 13369 * @param frameRateCategory the preferred frame rate category of a View 13370 */ 13371 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED) votePreferredFrameRateCategory(int frameRateCategory, int reason, View view)13372 public void votePreferredFrameRateCategory(int frameRateCategory, int reason, View view) { 13373 if (frameRateCategory > mPreferredFrameRateCategory) { 13374 mPreferredFrameRateCategory = frameRateCategory; 13375 mFrameRateCategoryChangeReason = reason; 13376 // mFrameRateCategoryView = view == null ? "-" : view.getClass().getSimpleName(); 13377 } 13378 mDrawnThisFrame = true; 13379 13380 if (sToolkitFrameRateDebugFlagValue) { 13381 String viewName = view == null ? "-" : view.getClass().getSimpleName(); 13382 Log.v(mTag, "### View: " + viewName + " votes '" 13383 + categoryToString(frameRateCategory) + "'"); 13384 } 13385 } 13386 13387 /** 13388 * Mark a View as having an active ThreadedRenderer animation. This is used for 13389 * RenderNodeAnimators and AnimatedVectorDrawables. When the animation stops, 13390 * {@link #removeThreadedRendererView(View)} must be called. 13391 * @param view The View with the ThreadedRenderer animation that started. 13392 */ addThreadedRendererView(View view)13393 public void addThreadedRendererView(View view) { 13394 if (shouldEnableDvrr() && !mThreadedRendererViews.contains(view)) { 13395 mThreadedRendererViews.add(view); 13396 } 13397 } 13398 13399 /** 13400 * When a ThreadedRenderer animation ends, the View that is associated with it using 13401 * {@link #addThreadedRendererView(View)} must be removed with a call to this method. 13402 * @param view The View whose ThreadedRender animation has stopped. 13403 */ removeThreadedRendererView(View view)13404 public void removeThreadedRendererView(View view) { 13405 mThreadedRendererViews.remove(view); 13406 if (shouldEnableDvrr() 13407 && !mInvalidationIdleMessagePosted && sSurfaceFlingerBugfixFlagValue) { 13408 mInvalidationIdleMessagePosted = true; 13409 mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE, IDLE_TIME_MILLIS); 13410 } 13411 } 13412 13413 /** 13414 * Returns {@link #INTERMITTENT_STATE_INTERMITTENT} when the ViewRootImpl has only been 13415 * updated intermittently, {@link #INTERMITTENT_STATE_NOT_INTERMITTENT} when it is 13416 * not updated intermittently, and {@link #INTERMITTENT_STATE_IN_TRANSITION} when it 13417 * is transitioning between {@link #INTERMITTENT_STATE_NOT_INTERMITTENT} and 13418 * {@link #INTERMITTENT_STATE_INTERMITTENT}. 13419 */ intermittentUpdateState()13420 int intermittentUpdateState() { 13421 if (mMinusOneFrameIntervalMillis + mMinusTwoFrameIntervalMillis 13422 < INFREQUENT_UPDATE_INTERVAL_MILLIS) { 13423 return INTERMITTENT_STATE_NOT_INTERMITTENT; 13424 } 13425 if (mInfrequentUpdateCount == INFREQUENT_UPDATE_COUNTS) { 13426 return INTERMITTENT_STATE_INTERMITTENT; 13427 } 13428 return INTERMITTENT_STATE_IN_TRANSITION; 13429 } 13430 13431 /** 13432 * Returns whether a View should vote for frame rate category. When the category is HIGH 13433 * already, there's no need to calculate the category on the View and vote. 13434 */ shouldCheckFrameRateCategory()13435 public boolean shouldCheckFrameRateCategory() { 13436 return mPreferredFrameRateCategory < FRAME_RATE_CATEGORY_HIGH; 13437 } 13438 13439 /** 13440 * Returns whether a View should vote for frame rate. When the maximum frame rate has already 13441 * been voted for, there's no point in calculating and voting for the frame rate. When 13442 * isDirect is false, then it will return false when the velocity-calculated frame rate 13443 * can be avoided. 13444 * @param isDirect true when the frame rate has been set directly on the View or false if 13445 * the calculation is based only on velocity. 13446 */ shouldCheckFrameRate(boolean isDirect)13447 public boolean shouldCheckFrameRate(boolean isDirect) { 13448 return mPreferredFrameRate < MAX_FRAME_RATE 13449 || (!isDirect && !sToolkitFrameRateVelocityMappingReadOnlyFlagValue 13450 && mPreferredFrameRateCategory < FRAME_RATE_CATEGORY_HIGH); 13451 } 13452 13453 /** 13454 * Allow Views to vote for the preferred frame rate and compatibility. 13455 * When determining the preferred frame rate value, 13456 * we follow this logic: If no preferred frame rate has been set yet, 13457 * we assign the value of frameRate as the preferred frame rate. 13458 * IF there are multiple frame rates are voted: 13459 * 1. There is a frame rate is a multiple of all other frame rates. 13460 * We choose this frmae rate to be the one to be set. 13461 * 2. There is no frame rate can be a multiple of others 13462 * We set category to HIGH if the maximum frame rate is greater than 60. 13463 * Otherwise, we set category to NORMAL. 13464 * 13465 * Use FRAME_RATE_COMPATIBILITY_AT_LEAST for velocity and FRAME_RATE_COMPATIBILITY_FIXED_SOURCE 13466 * for TextureView video play and user requested frame rate. 13467 * 13468 * @param frameRate the preferred frame rate of a View 13469 * @param frameRateCompatibility the preferred frame rate compatibility of a View 13470 */ 13471 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED) votePreferredFrameRate(float frameRate, int frameRateCompatibility)13472 public void votePreferredFrameRate(float frameRate, int frameRateCompatibility) { 13473 if (frameRate <= 0) { 13474 return; 13475 } 13476 if (frameRateCompatibility == FRAME_RATE_COMPATIBILITY_AT_LEAST && !mIsPressedGesture) { 13477 mIsTouchBoosting = false; 13478 mIsFrameRateBoosting = false; 13479 if (!sToolkitFrameRateVelocityMappingReadOnlyFlagValue) { 13480 mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH; 13481 mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT; 13482 mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_VELOCITY; 13483 mFrameRateCategoryView = null; 13484 mDrawnThisFrame = true; 13485 return; 13486 } 13487 } 13488 float nextFrameRate; 13489 int nextFrameRateCompatibility; 13490 if (frameRate > mPreferredFrameRate) { 13491 nextFrameRate = frameRate; 13492 nextFrameRateCompatibility = frameRateCompatibility; 13493 } else { 13494 nextFrameRate = mPreferredFrameRate; 13495 nextFrameRateCompatibility = mFrameRateCompatibility; 13496 } 13497 13498 if (mPreferredFrameRate > 0 && mPreferredFrameRate % frameRate != 0 13499 && frameRate % mPreferredFrameRate != 0) { 13500 mIsFrameRateConflicted = true; 13501 if (nextFrameRate > 60 && mFrameRateCategoryHighCount != FRAME_RATE_CATEGORY_COUNT) { 13502 mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT; 13503 mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_CONFLICTED; 13504 mFrameRateCategoryView = null; 13505 } else if (mFrameRateCategoryHighCount == 0 && mFrameRateCategoryHighHintCount == 0 13506 && mFrameRateCategoryNormalCount < FRAME_RATE_CATEGORY_COUNT) { 13507 mFrameRateCategoryNormalCount = FRAME_RATE_CATEGORY_COUNT; 13508 mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_CONFLICTED; 13509 mFrameRateCategoryView = null; 13510 } 13511 } 13512 13513 mPreferredFrameRate = nextFrameRate; 13514 mFrameRateCompatibility = nextFrameRateCompatibility; 13515 mDrawnThisFrame = true; 13516 } 13517 13518 /** 13519 * Get the value of mPreferredFrameRateCategory 13520 */ 13521 @VisibleForTesting getPreferredFrameRateCategory()13522 public int getPreferredFrameRateCategory() { 13523 return mPreferredFrameRateCategory; 13524 } 13525 13526 /** 13527 * Get the value of mLastPreferredFrameRateCategory 13528 */ 13529 @VisibleForTesting getLastPreferredFrameRateCategory()13530 public int getLastPreferredFrameRateCategory() { 13531 return mLastPreferredFrameRateCategory; 13532 } 13533 13534 /** 13535 * Get the value of mPreferredFrameRate 13536 */ 13537 @VisibleForTesting getPreferredFrameRate()13538 public float getPreferredFrameRate() { 13539 return mPreferredFrameRate >= 0 ? mPreferredFrameRate : mLastPreferredFrameRate; 13540 } 13541 13542 /** 13543 * Get the value of mLastPreferredFrameRate 13544 */ 13545 @VisibleForTesting getLastPreferredFrameRate()13546 public float getLastPreferredFrameRate() { 13547 return mLastPreferredFrameRate; 13548 } 13549 13550 /** 13551 * Returns whether touch boost is currently enabled. 13552 */ 13553 @VisibleForTesting getIsTouchBoosting()13554 public boolean getIsTouchBoosting() { 13555 return mIsTouchBoosting; 13556 } 13557 13558 /** 13559 * Get the value of mFrameRateCompatibility 13560 */ 13561 @VisibleForTesting getFrameRateCompatibility()13562 public int getFrameRateCompatibility() { 13563 return mFrameRateCompatibility; 13564 } 13565 13566 /** 13567 * Get the value of mIsFrameRateBoosting 13568 */ 13569 @VisibleForTesting getIsFrameRateBoosting()13570 public boolean getIsFrameRateBoosting() { 13571 return mIsFrameRateBoosting; 13572 } 13573 13574 /** 13575 * Get the value of mFrameRateBoostOnTouchEnabled 13576 * Can be used to checked if touch boost is enabled. The default value is true. 13577 */ 13578 @VisibleForTesting getFrameRateBoostOnTouchEnabled()13579 public boolean getFrameRateBoostOnTouchEnabled() { 13580 return mWindowAttributes.getFrameRateBoostOnTouchEnabled(); 13581 } 13582 boostFrameRate(int boostTimeOut)13583 private void boostFrameRate(int boostTimeOut) { 13584 mIsFrameRateBoosting = true; 13585 mHandler.removeMessages(MSG_TOUCH_BOOST_TIMEOUT); 13586 mHandler.sendEmptyMessageDelayed(MSG_TOUCH_BOOST_TIMEOUT, 13587 boostTimeOut); 13588 } 13589 13590 /** 13591 * Set the default back key callback for windowless window, to forward the back key event 13592 * to host app. 13593 * MUST NOT call this method for normal window. 13594 */ setBackKeyCallbackForWindowlessWindow(@onNull Predicate<KeyEvent> callback)13595 void setBackKeyCallbackForWindowlessWindow(@NonNull Predicate<KeyEvent> callback) { 13596 mWindowlessBackKeyCallback = callback; 13597 } 13598 recordViewPercentage(float percentage)13599 void recordViewPercentage(float percentage) { 13600 if (!Trace.isEnabled()) return; 13601 // Record the largest view of percentage to the display size. 13602 mLargestChildPercentage = Math.max(percentage, mLargestChildPercentage); 13603 } 13604 13605 /** 13606 * Get the value of mIsFrameRatePowerSavingsBalanced 13607 * Can be used to checked if toolkit dVRR feature is enabled. The default value is true. 13608 */ 13609 @VisibleForTesting isFrameRatePowerSavingsBalanced()13610 public boolean isFrameRatePowerSavingsBalanced() { 13611 if (sToolkitSetFrameRateReadOnlyFlagValue) { 13612 return mWindowAttributes.isFrameRatePowerSavingsBalanced(); 13613 } 13614 return true; 13615 } 13616 13617 /** 13618 * Get the value of mIsFrameRateConflicted 13619 * Can be used to checked if there is a conflict of frame rate votes. 13620 */ 13621 @VisibleForTesting isFrameRateConflicted()13622 public boolean isFrameRateConflicted() { 13623 return mIsFrameRateConflicted; 13624 } 13625 shouldEnableDvrr()13626 private boolean shouldEnableDvrr() { 13627 // uncomment this when we are ready for enabling dVRR 13628 if (sEnableVrr && sToolkitFrameRateViewEnablingReadOnlyFlagValue) { 13629 return sToolkitSetFrameRateReadOnlyFlagValue && isFrameRatePowerSavingsBalanced(); 13630 } 13631 return false; 13632 } 13633 removeVrrMessages()13634 private void removeVrrMessages() { 13635 mHandler.removeMessages(MSG_TOUCH_BOOST_TIMEOUT); 13636 mHandler.removeMessages(MSG_FRAME_RATE_SETTING); 13637 mHandler.removeMessages(MSG_SURFACE_REPLACED_TIMEOUT); 13638 if (mInvalidationIdleMessagePosted && sSurfaceFlingerBugfixFlagValue) { 13639 mInvalidationIdleMessagePosted = false; 13640 mHandler.removeMessages(MSG_CHECK_INVALIDATION_IDLE); 13641 } 13642 } 13643 13644 /** 13645 * This function is mainly used for migrating infrequent layer logic 13646 * from SurfaceFlinger to Toolkit. 13647 * The infrequent layer logic includes: 13648 * - NORMAL for infrequent update: FT2-FT1 > 100 && FT3-FT2 > 100. 13649 * - HIGH/NORMAL based on size for frequent update: (FT3-FT2) + (FT2 - FT1) < 100. 13650 * - otherwise, use the previous category value. 13651 */ updateInfrequentCount()13652 private void updateInfrequentCount() { 13653 long currentTimeMillis = mAttachInfo.mDrawingTime; 13654 int timeIntervalMillis = 13655 (int) Math.min(Integer.MAX_VALUE, currentTimeMillis - mLastUpdateTimeMillis); 13656 mMinusTwoFrameIntervalMillis = mMinusOneFrameIntervalMillis; 13657 mMinusOneFrameIntervalMillis = timeIntervalMillis; 13658 13659 mLastUpdateTimeMillis = currentTimeMillis; 13660 if (mThreadedRendererViews.isEmpty() && timeIntervalMillis + mMinusTwoFrameIntervalMillis 13661 >= INFREQUENT_UPDATE_INTERVAL_MILLIS) { 13662 int infrequentUpdateCount = mInfrequentUpdateCount; 13663 mInfrequentUpdateCount = infrequentUpdateCount == INFREQUENT_UPDATE_COUNTS 13664 ? infrequentUpdateCount : infrequentUpdateCount + 1; 13665 } else { 13666 mInfrequentUpdateCount = 0; 13667 } 13668 } 13669 logColorMode(@ctivityInfo.ColorMode int colorMode, boolean windowStopped)13670 private void logColorMode(@ActivityInfo.ColorMode int colorMode, boolean windowStopped) { 13671 if (mColorModeLastSetMillis == -1 && windowStopped) { 13672 Log.d(TAG, "Skipping stats log for color mode"); 13673 return; 13674 } 13675 13676 long currentTimeMillis = System.currentTimeMillis(); 13677 13678 if (windowStopped) { 13679 HwuiStatsLog.write(HwuiStatsLog.HARDWARE_RENDERER_EVENT, Process.myUid(), 13680 currentTimeMillis - mColorModeLastSetMillis, mCurrentColorMode); 13681 mColorModeLastSetMillis = -1; 13682 } else { 13683 if (mColorModeLastSetMillis > 0) { 13684 HwuiStatsLog.write(HwuiStatsLog.HARDWARE_RENDERER_EVENT, Process.myUid(), 13685 currentTimeMillis - mColorModeLastSetMillis, mCurrentColorMode); 13686 } 13687 mColorModeLastSetMillis = currentTimeMillis; 13688 } 13689 13690 mCurrentColorMode = colorMode; 13691 } 13692 13693 private static boolean sProtoLogInitialized = false; 13694 initializeProtoLogInProcess()13695 private void initializeProtoLogInProcess() { 13696 if (!sProtoLogInitialized) { 13697 ProtoLog.init(ViewProtoLogGroups.ALL_GROUPS); 13698 sProtoLogInitialized = true; 13699 } 13700 } 13701 preInitBufferAllocator()13702 private void preInitBufferAllocator() { 13703 if (com.android.graphics.hwui.flags.Flags.earlyPreinitBufferAllocator()) { 13704 ThreadedRenderer.preInitBufferAllocator(); 13705 } 13706 } 13707 13708 /** 13709 * @hide 13710 */ getChoreographer()13711 public Choreographer getChoreographer() { 13712 return mChoreographer; 13713 } 13714 } 13715