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.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; 20 import static android.content.pm.ActivityInfo.OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS; 21 import static android.graphics.HardwareRenderer.SYNC_CONTEXT_IS_STOPPED; 22 import static android.graphics.HardwareRenderer.SYNC_LOST_SURFACE_REWARD_IF_FOUND; 23 import static android.os.IInputConstants.INVALID_INPUT_EVENT_ID; 24 import static android.os.Trace.TRACE_TAG_VIEW; 25 import static android.view.Display.DEFAULT_DISPLAY; 26 import static android.view.Display.INVALID_DISPLAY; 27 import static android.view.DragEvent.ACTION_DRAG_LOCATION; 28 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APP_PROGRESS_GENERATION_ALLOWED; 29 import static android.view.flags.Flags.sensitiveContentPrematureProtectionRemovedFix; 30 import static android.view.InputDevice.SOURCE_CLASS_NONE; 31 import static android.view.InsetsSource.ID_IME; 32 import static android.view.Surface.FRAME_RATE_CATEGORY_DEFAULT; 33 import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH; 34 import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH_HINT; 35 import static android.view.Surface.FRAME_RATE_CATEGORY_LOW; 36 import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL; 37 import static android.view.Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE; 38 import static android.view.Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; 39 import static android.view.Surface.FRAME_RATE_COMPATIBILITY_GTE; 40 import static android.view.View.FRAME_RATE_CATEGORY_REASON_BOOST; 41 import static android.view.View.FRAME_RATE_CATEGORY_REASON_CONFLICTED; 42 import static android.view.View.FRAME_RATE_CATEGORY_REASON_INTERMITTENT; 43 import static android.view.View.FRAME_RATE_CATEGORY_REASON_INVALID; 44 import static android.view.View.FRAME_RATE_CATEGORY_REASON_LARGE; 45 import static android.view.View.FRAME_RATE_CATEGORY_REASON_REQUESTED; 46 import static android.view.View.FRAME_RATE_CATEGORY_REASON_SMALL; 47 import static android.view.View.FRAME_RATE_CATEGORY_REASON_TOUCH; 48 import static android.view.View.FRAME_RATE_CATEGORY_REASON_UNKNOWN; 49 import static android.view.View.FRAME_RATE_CATEGORY_REASON_VELOCITY; 50 import static android.view.View.MAX_FRAME_RATE; 51 import static android.view.View.PFLAG_DRAW_ANIMATION; 52 import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN; 53 import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; 54 import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; 55 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 56 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; 57 import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; 58 import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; 59 import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE; 60 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; 61 import static android.view.ViewRootImplProto.ADDED; 62 import static android.view.ViewRootImplProto.APP_VISIBLE; 63 import static android.view.ViewRootImplProto.CUR_SCROLL_Y; 64 import static android.view.ViewRootImplProto.DISPLAY_ID; 65 import static android.view.ViewRootImplProto.HEIGHT; 66 import static android.view.ViewRootImplProto.IS_ANIMATING; 67 import static android.view.ViewRootImplProto.IS_DRAWING; 68 import static android.view.ViewRootImplProto.LAST_WINDOW_INSETS; 69 import static android.view.ViewRootImplProto.REMOVED; 70 import static android.view.ViewRootImplProto.SCROLL_Y; 71 import static android.view.ViewRootImplProto.SOFT_INPUT_MODE; 72 import static android.view.ViewRootImplProto.VIEW; 73 import static android.view.ViewRootImplProto.VISIBLE_RECT; 74 import static android.view.ViewRootImplProto.WIDTH; 75 import static android.view.ViewRootImplProto.WINDOW_ATTRIBUTES; 76 import static android.view.ViewRootImplProto.WIN_FRAME; 77 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; 78 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS; 79 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; 80 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; 81 import static android.view.WindowInsetsController.Appearance; 82 import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT; 83 import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; 84 import static android.view.WindowLayout.UNSPECIFIED_LENGTH; 85 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; 86 import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; 87 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 88 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; 89 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; 90 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; 91 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; 92 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; 93 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EDGE_TO_EDGE_ENFORCED; 94 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FIT_INSETS_CONTROLLED; 95 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY; 96 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME; 97 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT; 98 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE; 99 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE; 100 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; 101 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; 102 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; 103 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; 104 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; 105 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; 106 import static android.view.WindowManager.LayoutParams.TYPE_TOAST; 107 import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY; 108 import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS; 109 import static android.view.WindowManagerGlobal.RELAYOUT_RES_CANCEL_AND_REDRAW; 110 import static android.view.WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS; 111 import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED; 112 import static android.view.accessibility.Flags.fixMergedContentChangeEventV2; 113 import static android.view.accessibility.Flags.forceInvertColor; 114 import static android.view.accessibility.Flags.reduceWindowContentChangedEventThrottle; 115 import static android.view.flags.Flags.addSchandleToVriSurface; 116 import static android.view.flags.Flags.sensitiveContentAppProtection; 117 import static android.view.flags.Flags.toolkitFrameRateFunctionEnablingReadOnly; 118 import static android.view.flags.Flags.toolkitFrameRateTypingReadOnly; 119 import static android.view.flags.Flags.toolkitFrameRateVelocityMappingReadOnly; 120 import static android.view.flags.Flags.toolkitFrameRateViewEnablingReadOnly; 121 import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision; 122 import static android.view.flags.Flags.toolkitSetFrameRateReadOnly; 123 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER; 124 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER; 125 126 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; 127 import static com.android.window.flags.Flags.activityWindowInfoFlag; 128 import static com.android.window.flags.Flags.enableBufferTransformHintFromDisplay; 129 import static com.android.window.flags.Flags.insetsControlChangedItem; 130 import static com.android.window.flags.Flags.setScPropertiesInClient; 131 import static com.android.window.flags.Flags.windowSessionRelayoutInfo; 132 import static com.android.text.flags.Flags.disableHandwritingInitiatorForIme; 133 134 import android.Manifest; 135 import android.accessibilityservice.AccessibilityService; 136 import android.animation.AnimationHandler; 137 import android.animation.LayoutTransition; 138 import android.annotation.AnyThread; 139 import android.annotation.NonNull; 140 import android.annotation.Nullable; 141 import android.annotation.Size; 142 import android.annotation.UiContext; 143 import android.app.ActivityManager; 144 import android.app.ActivityThread; 145 import android.app.ICompatCameraControlCallback; 146 import android.app.ResourcesManager; 147 import android.app.WindowConfiguration; 148 import android.app.compat.CompatChanges; 149 import android.app.servertransaction.WindowStateTransactionItem; 150 import android.compat.annotation.UnsupportedAppUsage; 151 import android.content.ClipData; 152 import android.content.ClipDescription; 153 import android.content.Context; 154 import android.content.pm.ActivityInfo; 155 import android.content.pm.PackageManager; 156 import android.content.res.CompatibilityInfo; 157 import android.content.res.Configuration; 158 import android.content.res.Resources; 159 import android.content.res.TypedArray; 160 import android.database.ContentObserver; 161 import android.graphics.BLASTBufferQueue; 162 import android.graphics.Canvas; 163 import android.graphics.Color; 164 import android.graphics.ForceDarkType; 165 import android.graphics.FrameInfo; 166 import android.graphics.HardwareRenderer; 167 import android.graphics.HardwareRenderer.FrameDrawingCallback; 168 import android.graphics.HardwareRendererObserver; 169 import android.graphics.Matrix; 170 import android.graphics.Paint; 171 import android.graphics.PixelFormat; 172 import android.graphics.Point; 173 import android.graphics.PointF; 174 import android.graphics.PorterDuff; 175 import android.graphics.RecordingCanvas; 176 import android.graphics.Rect; 177 import android.graphics.RectF; 178 import android.graphics.Region; 179 import android.graphics.RenderNode; 180 import android.graphics.drawable.Drawable; 181 import android.graphics.drawable.GradientDrawable; 182 import android.hardware.SyncFence; 183 import android.hardware.display.DisplayManager; 184 import android.hardware.display.DisplayManager.DisplayListener; 185 import android.hardware.display.DisplayManagerGlobal; 186 import android.hardware.input.InputManagerGlobal; 187 import android.hardware.input.InputSettings; 188 import android.media.AudioManager; 189 import android.os.Binder; 190 import android.os.Build; 191 import android.os.Bundle; 192 import android.os.Debug; 193 import android.os.Handler; 194 import android.os.IBinder; 195 import android.os.Looper; 196 import android.os.Message; 197 import android.os.ParcelFileDescriptor; 198 import android.os.Process; 199 import android.os.RemoteException; 200 import android.os.ServiceManager; 201 import android.os.StrictMode; 202 import android.os.SystemClock; 203 import android.os.SystemProperties; 204 import android.os.Trace; 205 import android.os.UserHandle; 206 import android.provider.Settings; 207 import android.sysprop.DisplayProperties; 208 import android.sysprop.ViewProperties; 209 import android.text.TextUtils; 210 import android.util.AndroidRuntimeException; 211 import android.util.DisplayMetrics; 212 import android.util.EventLog; 213 import android.util.IndentingPrintWriter; 214 import android.util.Log; 215 import android.util.LongArray; 216 import android.util.MergedConfiguration; 217 import android.util.Slog; 218 import android.util.SparseArray; 219 import android.util.TimeUtils; 220 import android.util.TypedValue; 221 import android.util.proto.ProtoOutputStream; 222 import android.view.InputDevice.InputSourceClass; 223 import android.view.Surface.OutOfResourcesException; 224 import android.view.SurfaceControl.Transaction; 225 import android.view.SurfaceControl.TransactionStats; 226 import android.view.View.AttachInfo; 227 import android.view.View.FocusDirection; 228 import android.view.View.MeasureSpec; 229 import android.view.Window.OnContentApplyWindowInsetsListener; 230 import android.view.WindowInsets.Type; 231 import android.view.WindowInsets.Type.InsetsType; 232 import android.view.WindowManager.LayoutParams.SoftInputModeFlags; 233 import android.view.accessibility.AccessibilityEvent; 234 import android.view.accessibility.AccessibilityInteractionClient; 235 import android.view.accessibility.AccessibilityManager; 236 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener; 237 import android.view.accessibility.AccessibilityManager.HighTextContrastChangeListener; 238 import android.view.accessibility.AccessibilityNodeIdManager; 239 import android.view.accessibility.AccessibilityNodeInfo; 240 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 241 import android.view.accessibility.AccessibilityNodeProvider; 242 import android.view.accessibility.AccessibilityWindowAttributes; 243 import android.view.accessibility.AccessibilityWindowInfo; 244 import android.view.accessibility.IAccessibilityEmbeddedConnection; 245 import android.view.accessibility.IAccessibilityInteractionConnection; 246 import android.view.accessibility.IAccessibilityInteractionConnectionCallback; 247 import android.view.animation.AccelerateDecelerateInterpolator; 248 import android.view.animation.Interpolator; 249 import android.view.autofill.AutofillManager; 250 import android.view.contentcapture.ContentCaptureManager; 251 import android.view.contentcapture.ContentCaptureSession; 252 import android.view.flags.Flags; 253 import android.view.inputmethod.ImeTracker; 254 import android.view.inputmethod.InputMethodManager; 255 import android.widget.Scroller; 256 import android.window.ActivityWindowInfo; 257 import android.window.BackEvent; 258 import android.window.ClientWindowFrames; 259 import android.window.CompatOnBackInvokedCallback; 260 import android.window.InputTransferToken; 261 import android.window.OnBackAnimationCallback; 262 import android.window.OnBackInvokedCallback; 263 import android.window.OnBackInvokedDispatcher; 264 import android.window.ScreenCapture; 265 import android.window.SurfaceSyncGroup; 266 import android.window.WindowOnBackInvokedDispatcher; 267 268 import com.android.internal.R; 269 import com.android.internal.annotations.GuardedBy; 270 import com.android.internal.annotations.VisibleForTesting; 271 import com.android.internal.graphics.drawable.BackgroundBlurDrawable; 272 import com.android.internal.inputmethod.ImeTracing; 273 import com.android.internal.inputmethod.InputMethodDebug; 274 import com.android.internal.os.IResultReceiver; 275 import com.android.internal.os.SomeArgs; 276 import com.android.internal.policy.DecorView; 277 import com.android.internal.policy.PhoneFallbackEventHandler; 278 import com.android.internal.util.FastPrintWriter; 279 import com.android.internal.view.BaseSurfaceHolder; 280 import com.android.internal.view.RootViewSurfaceTaker; 281 import com.android.internal.view.SurfaceCallbackHelper; 282 import com.android.modules.expresslog.Counter; 283 284 import libcore.io.IoUtils; 285 286 import java.io.FileOutputStream; 287 import java.io.IOException; 288 import java.io.OutputStream; 289 import java.io.PrintWriter; 290 import java.io.StringWriter; 291 import java.lang.ref.WeakReference; 292 import java.util.ArrayDeque; 293 import java.util.ArrayList; 294 import java.util.HashSet; 295 import java.util.List; 296 import java.util.Objects; 297 import java.util.OptionalInt; 298 import java.util.Queue; 299 import java.util.concurrent.CountDownLatch; 300 import java.util.concurrent.Executor; 301 import java.util.function.Consumer; 302 import java.util.function.Predicate; 303 /** 304 * The top of a view hierarchy, implementing the needed protocol between View 305 * and the WindowManager. This is for the most part an internal implementation 306 * detail of {@link WindowManagerGlobal}. 307 * 308 * {@hide} 309 */ 310 @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"}) 311 public final class ViewRootImpl implements ViewParent, 312 View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks, 313 AttachedSurfaceControl { 314 private static final String TAG = "ViewRootImpl"; 315 private static final boolean DBG = false; 316 private static final boolean LOCAL_LOGV = false; 317 /** @noinspection PointlessBooleanExpression*/ 318 private static final boolean DEBUG_DRAW = false || LOCAL_LOGV; 319 private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV; 320 private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV; 321 private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV; 322 private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV; 323 private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV; 324 private static final boolean DEBUG_IMF = false || LOCAL_LOGV; 325 private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV; 326 private static final boolean DEBUG_FPS = false; 327 private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV; 328 private static final boolean DEBUG_KEEP_SCREEN_ON = false || LOCAL_LOGV; 329 private static final boolean DEBUG_CONTENT_CAPTURE = false || LOCAL_LOGV; 330 private static final boolean DEBUG_SCROLL_CAPTURE = false || LOCAL_LOGV; 331 private static final boolean DEBUG_TOUCH_NAVIGATION = false || LOCAL_LOGV; 332 private static final boolean DEBUG_BLAST = false || LOCAL_LOGV; 333 private static final boolean DEBUG_SENSITIVE_CONTENT = false || LOCAL_LOGV; 334 private static final int LOGTAG_INPUT_FOCUS = 62001; 335 private static final int LOGTAG_VIEWROOT_DRAW_EVENT = 60004; 336 337 /** 338 * Set to false if we do not want to use the multi threaded renderer even though 339 * threaded renderer (aka hardware renderering) is used. Note that by disabling 340 * this, WindowCallbacks will not fire. 341 */ 342 private static final boolean MT_RENDERER_AVAILABLE = true; 343 344 /** 345 * Whether or not to report end-to-end input latency. Can be disabled temporarily as a 346 * risk mitigation against potential jank caused by acquiring a weak reference 347 * per frame. 348 */ 349 private static final boolean ENABLE_INPUT_LATENCY_TRACKING = true; 350 351 /** 352 * Controls whether to use the new oneway performHapticFeedback call. This returns 353 * true in a few more conditions, but doesn't affect which haptics happen. Notably, it 354 * makes the call to performHapticFeedback non-blocking, which reduces potential UI jank. 355 * This is intended as a temporary flag, ultimately becoming permanently 'true'. 356 */ 357 private static final boolean USE_ASYNC_PERFORM_HAPTIC_FEEDBACK = true; 358 359 /** 360 * Whether the client (system UI) is handling the transient gesture and the corresponding 361 * animation. 362 * @hide 363 */ 364 public static final boolean CLIENT_TRANSIENT = 365 SystemProperties.getBoolean("persist.wm.debug.client_transient", false); 366 367 /** 368 * Whether the client (system UI) is handling the immersive confirmation window. If 369 * {@link CLIENT_TRANSIENT} is set to true, the immersive confirmation window will always be the 370 * client instance and this flag will be ignored. Otherwise, the immersive confirmation window 371 * can be switched freely by this flag. 372 * @hide 373 */ 374 public static final boolean CLIENT_IMMERSIVE_CONFIRMATION = 375 SystemProperties.getBoolean("persist.wm.debug.client_immersive_confirmation", false); 376 377 /** 378 * Set this system property to true to force the view hierarchy to render 379 * at 60 Hz. This can be used to measure the potential framerate. 380 */ 381 private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering"; 382 383 /** 384 * Maximum time we allow the user to roll the trackball enough to generate 385 * a key event, before resetting the counters. 386 */ 387 static final int MAX_TRACKBALL_DELAY = 250; 388 389 /** 390 * Initial value for {@link #mContentCaptureEnabled}. 391 */ 392 private static final int CONTENT_CAPTURE_ENABLED_NOT_CHECKED = 0; 393 394 /** 395 * Value for {@link #mContentCaptureEnabled} when it was checked and set to {@code true}. 396 */ 397 private static final int CONTENT_CAPTURE_ENABLED_TRUE = 1; 398 399 /** 400 * Value for {@link #mContentCaptureEnabled} when it was checked and set to {@code false}. 401 */ 402 private static final int CONTENT_CAPTURE_ENABLED_FALSE = 2; 403 404 /** 405 * Maximum time to wait for {@link View#dispatchScrollCaptureSearch} to complete. 406 */ 407 private static final int SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS = 2500; 408 409 private static final int UNSET_SYNC_ID = -1; 410 411 private static final int INFREQUENT_UPDATE_INTERVAL_MILLIS = 100; 412 private static final int INFREQUENT_UPDATE_COUNTS = 2; 413 414 /** 415 * The {@link #intermittentUpdateState()} value when the ViewRootImpl isn't intermittent. 416 */ 417 public static final int INTERMITTENT_STATE_NOT_INTERMITTENT = 1; 418 419 /** 420 * The {@link #intermittentUpdateState()} value when the ViewRootImpl is transitioning either 421 * to or from intermittent to not intermittent. This indicates that the frame rate shouldn't 422 * change. 423 */ 424 public static final int INTERMITTENT_STATE_IN_TRANSITION = -1; 425 426 /** 427 * The {@link #intermittentUpdateState()} value when the ViewRootImpl is intermittent. 428 */ 429 public static final int INTERMITTENT_STATE_INTERMITTENT = 0; 430 431 /** 432 * Minimum time to wait before reporting changes to keep clear areas. 433 */ 434 private static final int KEEP_CLEAR_AREA_REPORT_RATE_MILLIS = 100; 435 436 private static final long NANOS_PER_SEC = 1000000000; 437 438 // If the ViewRootImpl has been idle for more than 750ms, clear the preferred 439 // frame rate category and frame rate. 440 private static final int IDLE_TIME_MILLIS = 750; 441 442 private static final long NANOS_PER_MILLI = 1_000_000; 443 444 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 445 static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>(); 446 447 static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<>(); 448 static boolean sFirstDrawComplete = false; 449 450 private ArrayList<OnBufferTransformHintChangedListener> mTransformHintListeners = 451 new ArrayList<>(); 452 private @SurfaceControl.BufferTransform 453 int mPreviousTransformHint = SurfaceControl.BUFFER_TRANSFORM_IDENTITY; 454 /** 455 * The top level {@link OnBackInvokedDispatcher}. 456 */ 457 private final WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher; 458 /** 459 * Compatibility {@link OnBackInvokedCallback} that dispatches KEYCODE_BACK events 460 * to view root for apps using legacy back behavior. 461 */ 462 private CompatOnBackInvokedCallback mCompatOnBackInvokedCallback; 463 464 @Nullable 465 private ContentObserver mForceInvertObserver; 466 467 private static final int INVALID_VALUE = Integer.MIN_VALUE; 468 private int mForceInvertEnabled = INVALID_VALUE; 469 /** 470 * Callback for notifying about global configuration changes. 471 */ 472 public interface ConfigChangedCallback { 473 474 /** Notifies about global config change. */ onConfigurationChanged(Configuration globalConfig)475 void onConfigurationChanged(Configuration globalConfig); 476 } 477 478 private static final ArrayList<ConfigChangedCallback> sConfigCallbacks = new ArrayList<>(); 479 480 /** 481 * Callback for notifying activities. 482 */ 483 public interface ActivityConfigCallback { 484 /** 485 * Notifies about override config change and/or move to different display. 486 * @param overrideConfig New override config to apply to activity. 487 * @param newDisplayId New display id, {@link Display#INVALID_DISPLAY} if not changed. 488 */ onConfigurationChanged(@onNull Configuration overrideConfig, int newDisplayId)489 default void onConfigurationChanged(@NonNull Configuration overrideConfig, 490 int newDisplayId) { 491 // Must override one of the #onConfigurationChanged. 492 throw new IllegalStateException("Not implemented"); 493 } 494 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 * @param activityWindowInfo New ActivityWindowInfo to apply to activity. 500 */ onConfigurationChanged(@onNull Configuration overrideConfig, int newDisplayId, @Nullable ActivityWindowInfo activityWindowInfo)501 default void onConfigurationChanged(@NonNull Configuration overrideConfig, 502 int newDisplayId, @Nullable ActivityWindowInfo activityWindowInfo) { 503 onConfigurationChanged(overrideConfig, newDisplayId); 504 } 505 506 /** 507 * Notify the corresponding activity about the request to show or hide a camera compat 508 * control for stretched issues in the viewfinder. 509 * 510 * @param showControl Whether the control should be shown or hidden. 511 * @param transformationApplied Whether the treatment is already applied. 512 * @param callback The callback executed when the user clicks on a control. 513 */ requestCompatCameraControl(boolean showControl, boolean transformationApplied, ICompatCameraControlCallback callback)514 void requestCompatCameraControl(boolean showControl, boolean transformationApplied, 515 ICompatCameraControlCallback callback); 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 * This list must only be modified by the main thread. 550 */ 551 final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList<>(); 552 @UnsupportedAppUsage 553 @UiContext 554 public final Context mContext; 555 556 @UnsupportedAppUsage 557 final IWindowSession mWindowSession; 558 @NonNull Display mDisplay; 559 final String mBasePackageName; 560 561 // If we would like to keep a particular eye on the corresponding package. 562 final boolean mExtraDisplayListenerLogging; 563 564 final int[] mTmpLocation = new int[2]; 565 566 final TypedValue mTmpValue = new TypedValue(); 567 568 final Thread mThread; 569 570 final WindowLeaked mLocation; 571 572 public final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams(); 573 574 final W mWindow; 575 576 final IBinder mLeashToken; 577 578 final int mTargetSdkVersion; 579 580 @UnsupportedAppUsage 581 View mView; 582 583 View mAccessibilityFocusedHost; 584 // Accessibility-focused virtual view. The bounds and sourceNodeId of 585 // mAccessibilityFocusedVirtualView is up-to-date while other fields may be stale. 586 AccessibilityNodeInfo mAccessibilityFocusedVirtualView; 587 588 // True if the window currently has pointer capture enabled. 589 boolean mPointerCapture; 590 591 int mViewVisibility; 592 boolean mAppVisible = true; 593 // For recents to freeform transition we need to keep drawing after the app receives information 594 // that it became invisible. This will ignore that information and depend on the decor view 595 // visibility to control drawing. The decor view visibility will get adjusted when the app get 596 // stopped and that's when the app will stop drawing further frames. 597 private boolean mForceDecorViewVisibility = false; 598 // Used for tracking app visibility updates separately in case we get double change. This will 599 // make sure that we always call relayout for the corresponding window. 600 private boolean mAppVisibilityChanged; 601 int mOrigWindowType = -1; 602 603 // Set to true if the owner of this window is in the stopped state, 604 // so the window should no longer be active. 605 @UnsupportedAppUsage 606 boolean mStopped = false; 607 608 // Set to true if the owner of this window is in ambient mode, 609 // which means it won't receive input events. 610 boolean mIsAmbientMode = false; 611 612 // Set to true to stop input during an Activity Transition. 613 boolean mPausedForTransition = false; 614 615 SurfaceHolder.Callback2 mSurfaceHolderCallback; 616 BaseSurfaceHolder mSurfaceHolder; 617 boolean mIsCreating; 618 boolean mDrawingAllowed; 619 620 final Region mTransparentRegion; 621 final Region mPreviousTransparentRegion; 622 623 Region mTouchableRegion; 624 Region mPreviousTouchableRegion; 625 626 private int mMeasuredWidth; 627 private int mMeasuredHeight; 628 629 // This indicates that we've already known the window size but without measuring the views. 630 // If this is true, we must measure the views before laying out them. 631 private boolean mViewMeasureDeferred; 632 633 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 634 int mWidth; 635 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 636 int mHeight; 637 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 638 private Rect mDirty; 639 public boolean mIsAnimating; 640 641 private boolean mUseMTRenderer; 642 private boolean mPendingDragResizing; 643 private boolean mDragResizing; 644 private boolean mInvalidateRootRequested; 645 private int mCanvasOffsetX; 646 private int mCanvasOffsetY; 647 CompatibilityInfo.Translator mTranslator; 648 649 @UnsupportedAppUsage 650 final View.AttachInfo mAttachInfo; 651 final SystemUiVisibilityInfo mCompatibleVisibilityInfo; 652 int mDispatchedSystemUiVisibility; 653 int mDispatchedSystemBarAppearance; 654 InputQueue.Callback mInputQueueCallback; 655 InputQueue mInputQueue; 656 @UnsupportedAppUsage 657 FallbackEventHandler mFallbackEventHandler; 658 final Choreographer mChoreographer; 659 protected final ViewFrameInfo mViewFrameInfo = new ViewFrameInfo(); 660 private final InputEventAssigner mInputEventAssigner = new InputEventAssigner(); 661 662 // Whether to draw this surface as DISPLAY_DECORATION. 663 boolean mDisplayDecorationCached = false; 664 665 // Is the stylus pointer icon enabled 666 private final boolean mIsStylusPointerIconEnabled; 667 668 // VRR check for number of infrequent updates 669 private int mInfrequentUpdateCount = 0; 670 // VRR time of last update 671 private long mLastUpdateTimeMillis = 0; 672 // VRR interval since the previous 673 private int mMinusOneFrameIntervalMillis = 0; 674 // VRR interval between the previous and the frame before 675 private int mMinusTwoFrameIntervalMillis = 0; 676 // VRR has the invalidation idle message been posted? 677 private boolean mInvalidationIdleMessagePosted = false; 678 // VRR: List of all Views that are animating with the threaded render 679 private ArrayList<View> mThreadedRendererViews = new ArrayList(); 680 681 /** 682 * Update the Choreographer's FrameInfo object with the timing information for the current 683 * ViewRootImpl instance. Erase the data in the current ViewFrameInfo to prepare for the next 684 * frame. 685 * @return the updated FrameInfo object 686 */ getUpdatedFrameInfo()687 protected @NonNull FrameInfo getUpdatedFrameInfo() { 688 // Since Choreographer is a thread-local singleton while we can have multiple 689 // ViewRootImpl's, populate the frame information from the current viewRootImpl before 690 // starting the draw 691 FrameInfo frameInfo = mChoreographer.mFrameInfo; 692 mViewFrameInfo.populateFrameInfo(frameInfo); 693 mViewFrameInfo.reset(); 694 mInputEventAssigner.notifyFrameProcessed(); 695 return frameInfo; 696 } 697 698 // used in relayout to get SurfaceControl size 699 // for BLAST adapter surface setup 700 private final Point mSurfaceSize = new Point(); 701 private final Point mLastSurfaceSize = new Point(); 702 703 private final Rect mVisRect = new Rect(); // used to retrieve visible rect of focused view. 704 private final Rect mTempRect = new Rect(); 705 706 private final WindowLayout mWindowLayout; 707 708 // This is used to reduce the race between window focus changes being dispatched from 709 // the window manager and input events coming through the input system. 710 @GuardedBy("this") 711 boolean mWindowFocusChanged; 712 @GuardedBy("this") 713 boolean mUpcomingWindowFocus; 714 @GuardedBy("this") 715 boolean mUpcomingInTouchMode; 716 // While set, allow this VRI to handle back key without drop it. 717 private boolean mProcessingBackKey; 718 /** 719 * Compatibility {@link OnBackInvokedCallback} for windowless window, to forward the back 720 * key event host app. 721 */ 722 private Predicate<KeyEvent> mWindowlessBackKeyCallback; 723 724 public boolean mTraversalScheduled; 725 int mTraversalBarrier; 726 boolean mWillDrawSoon; 727 /** Set to true while in performTraversals for detecting when die(true) is called from internal 728 * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */ 729 boolean mIsInTraversal; 730 boolean mApplyInsetsRequested; 731 boolean mLayoutRequested; 732 boolean mFirst; 733 734 @Nullable 735 int mContentCaptureEnabled = CONTENT_CAPTURE_ENABLED_NOT_CHECKED; 736 boolean mPerformContentCapture; 737 738 boolean mReportNextDraw; 739 /** Set only while mReportNextDraw=true, indicating the last reason that was triggered */ 740 String mLastReportNextDrawReason; 741 /** The reaason the last call to performDraw() returned false */ 742 String mLastPerformDrawSkippedReason; 743 /** The reason the last call to performTraversals() returned without drawing */ 744 String mLastPerformTraversalsSkipDrawReason; 745 /** The state of the WMS requested sync, if one is in progress. Can be one of the states 746 * below. */ 747 int mWmsRequestSyncGroupState; 748 749 // The possible states of the WMS requested sync, see createSyncIfNeeded() 750 private static final int WMS_SYNC_NONE = 0; 751 private static final int WMS_SYNC_PENDING = 1; 752 private static final int WMS_SYNC_RETURNED = 2; 753 private static final int WMS_SYNC_MERGED = 3; 754 755 /** 756 * Set whether the requested SurfaceSyncGroup should sync the buffer. When set to true, VRI will 757 * create a sync transaction with BBQ and send the resulting buffer back to the 758 * SurfaceSyncGroup. If false, VRI will not try to sync a buffer in BBQ, but still report when a 759 * draw occurred. 760 */ 761 private boolean mSyncBuffer = false; 762 763 /** 764 * Flag to determine whether the client needs to check with WMS if it can draw. WMS will notify 765 * the client that it can't draw if we're still in the middle of a sync set that includes this 766 * window. Once the sync is complete, the window can resume drawing. This is to ensure we don't 767 * deadlock the client by trying to request draws when there may not be any buffers available. 768 */ 769 private boolean mCheckIfCanDraw = false; 770 771 private boolean mWasLastDrawCanceled; 772 private boolean mLastTraversalWasVisible = true; 773 private boolean mLastDrawScreenOff; 774 775 private boolean mDrewOnceForSync = false; 776 777 int mSyncSeqId = 0; 778 int mLastSyncSeqId = 0; 779 780 private boolean mUpdateSurfaceNeeded; 781 boolean mFullRedrawNeeded; 782 boolean mNewSurfaceNeeded; 783 boolean mForceNextWindowRelayout; 784 CountDownLatch mWindowDrawCountDown; 785 786 /** 787 * Value to indicate whether someone has called {@link #applyTransactionOnDraw}before the 788 * traversal. This is used to determine whether a RT frame callback needs to be registered to 789 * merge the transaction with the next frame. The value is cleared after the VRI has run a 790 * traversal pass. 791 */ 792 boolean mHasPendingTransactions; 793 /** 794 * The combined transactions passed in from {@link #applyTransactionOnDraw} 795 */ 796 private Transaction mPendingTransaction = new Transaction(); 797 798 799 boolean mIsDrawing; 800 int mLastSystemUiVisibility; 801 int mClientWindowLayoutFlags; 802 803 // Pool of queued input events. 804 private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10; 805 private QueuedInputEvent mQueuedInputEventPool; 806 private int mQueuedInputEventPoolSize; 807 808 /* Input event queue. 809 * Pending input events are input events waiting to be delivered to the input stages 810 * and handled by the application. 811 */ 812 QueuedInputEvent mPendingInputEventHead; 813 QueuedInputEvent mPendingInputEventTail; 814 int mPendingInputEventCount; 815 boolean mProcessInputEventsScheduled; 816 boolean mUnbufferedInputDispatch; 817 @InputSourceClass 818 int mUnbufferedInputSource = SOURCE_CLASS_NONE; 819 820 String mPendingInputEventQueueLengthCounterName = "pq"; 821 822 InputStage mFirstInputStage; 823 InputStage mFirstPostImeInputStage; 824 InputStage mSyntheticInputStage; 825 826 private final UnhandledKeyManager mUnhandledKeyManager = new UnhandledKeyManager(); 827 828 boolean mWindowAttributesChanged = false; 829 830 // These can be accessed by any thread, must be protected with a lock. 831 // Surface can never be reassigned or cleared (use Surface.clear()). 832 @UnsupportedAppUsage 833 public final Surface mSurface = new Surface(); 834 private final SurfaceControl mSurfaceControl = new SurfaceControl(); 835 836 private BLASTBufferQueue mBlastBufferQueue; 837 838 private final HdrRenderState mHdrRenderState = new HdrRenderState(this); 839 840 /** 841 * Child container layer of {@code mSurface} with the same bounds as its parent, and cropped to 842 * the surface insets. This surface is created only if a client requests it via 843 * {@link #updateAndGetBoundsLayer(Transaction)}. By parenting to this bounds surface, child 844 * surfaces can ensure they do not draw into the surface inset region set by the parent window. 845 */ 846 private SurfaceControl mBoundsLayer; 847 private final SurfaceSession mSurfaceSession = new SurfaceSession(); 848 private final Transaction mTransaction = new Transaction(); 849 private final Transaction mFrameRateTransaction = new Transaction(); 850 851 @UnsupportedAppUsage 852 boolean mAdded; 853 boolean mAddedTouchMode; 854 855 /** 856 * It usually keeps the latest layout result from {@link IWindow#resized} or 857 * {@link IWindowSession#relayout}. 858 */ 859 private final ClientWindowFrames mTmpFrames = new ClientWindowFrames(); 860 861 // These are accessed by multiple threads. 862 final Rect mWinFrame; // frame given by window manager. 863 private final Rect mLastLayoutFrame; 864 Rect mOverrideInsetsFrame; 865 866 final Rect mPendingBackDropFrame = new Rect(); 867 868 boolean mPendingAlwaysConsumeSystemBars; 869 private int mRelayoutSeq; 870 private final Rect mWinFrameInScreen = new Rect(); 871 private final InsetsState mTempInsets = new InsetsState(); 872 private final InsetsSourceControl.Array mTempControls = new InsetsSourceControl.Array(); 873 private final WindowConfiguration mTempWinConfig = new WindowConfiguration(); 874 private float mInvCompatScale = 1f; 875 final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets 876 = new ViewTreeObserver.InternalInsetsInfo(); 877 878 private WindowInsets mLastWindowInsets; 879 880 // Insets types hidden by legacy window flags or system UI flags. 881 private @InsetsType int mTypesHiddenByFlags = 0; 882 883 /** Last applied configuration obtained from resources. */ 884 private final Configuration mLastConfigurationFromResources = new Configuration(); 885 /** Last configuration reported from WM or via {@link #MSG_UPDATE_CONFIGURATION}. */ 886 private final MergedConfiguration mLastReportedMergedConfiguration = new MergedConfiguration(); 887 /** Configurations waiting to be applied. */ 888 private final MergedConfiguration mPendingMergedConfiguration = new MergedConfiguration(); 889 890 /** Non-{@code null} if {@link #mActivityConfigCallback} is not {@code null}. */ 891 @Nullable 892 private ActivityWindowInfo mPendingActivityWindowInfo; 893 /** Non-{@code null} if {@link #mActivityConfigCallback} is not {@code null}. */ 894 @Nullable 895 private ActivityWindowInfo mLastReportedActivityWindowInfo; 896 897 boolean mScrollMayChange; 898 @SoftInputModeFlags 899 int mSoftInputMode; 900 @UnsupportedAppUsage 901 WeakReference<View> mLastScrolledFocus; 902 int mScrollY; 903 int mCurScrollY; 904 Scroller mScroller; 905 static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator(); 906 private ArrayList<LayoutTransition> mPendingTransitions; 907 908 final ViewConfiguration mViewConfiguration; 909 910 /* Drag/drop */ 911 ClipDescription mDragDescription; 912 View mCurrentDragView; 913 View mStartedDragViewForA11y; 914 volatile Object mLocalDragState; 915 final PointF mDragPoint = new PointF(); 916 final PointF mLastTouchPoint = new PointF(); 917 int mLastTouchSource; 918 int mLastTouchDeviceId = KeyCharacterMap.VIRTUAL_KEYBOARD; 919 int mLastTouchPointerId; 920 /** Tracks last {@link MotionEvent#getToolType(int)} with {@link MotionEvent#ACTION_UP}. **/ 921 private int mLastClickToolType; 922 923 private boolean mProfileRendering; 924 private Choreographer.FrameCallback mRenderProfiler; 925 private boolean mRenderProfilingEnabled; 926 927 // Variables to track frames per second, enabled via DEBUG_FPS flag 928 private long mFpsStartTime = -1; 929 private long mFpsPrevTime = -1; 930 private int mFpsNumFrames; 931 932 private boolean mInsetsAnimationRunning; 933 934 private long mPreviousFrameDrawnTime = -1; 935 // The largest view size percentage to the display size. Used on trace to collect metric. 936 private float mLargestChildPercentage = 0.0f; 937 // The reason the category was changed. 938 private int mFrameRateCategoryChangeReason = 0; 939 private String mFrameRateCategoryView; 940 941 /** 942 * The resolved pointer icon requested by this window. 943 * A null value indicates the resolved pointer icon has not yet been calculated. 944 */ 945 @Nullable 946 private PointerIcon mResolvedPointerIcon = null; 947 948 /** 949 * see {@link #playSoundEffect(int)} 950 */ 951 AudioManager mAudioManager; 952 953 final AccessibilityManager mAccessibilityManager; 954 955 AccessibilityInteractionController mAccessibilityInteractionController; 956 957 Paint mRoundDisplayAccessibilityHighlightPaint; 958 959 final AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager = 960 new AccessibilityInteractionConnectionManager(); 961 final HighContrastTextManager mHighContrastTextManager; 962 963 SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent; 964 965 HashSet<View> mTempHashSet; 966 967 private final int mDensity; 968 private final int mNoncompatDensity; 969 970 private boolean mInLayout = false; 971 ArrayList<View> mLayoutRequesters = new ArrayList<View>(); 972 boolean mHandlingLayoutInLayoutRequest = false; 973 974 private int mViewLayoutDirectionInitial; 975 976 /** Set to true once doDie() has been called. */ 977 private boolean mRemoved; 978 979 private boolean mNeedsRendererSetup; 980 981 private final InputEventCompatProcessor mInputCompatProcessor; 982 983 /** 984 * Consistency verifier for debugging purposes. 985 */ 986 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 987 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 988 new InputEventConsistencyVerifier(this, 0) : null; 989 990 private final InsetsController mInsetsController; 991 private final ImeBackAnimationController mImeBackAnimationController; 992 private final ImeFocusController mImeFocusController; 993 994 private boolean mIsSurfaceOpaque; 995 996 private final BackgroundBlurDrawable.Aggregator mBlurRegionAggregator = 997 new BackgroundBlurDrawable.Aggregator(this); 998 999 /** 1000 * @return {@link ImeFocusController} for this instance. 1001 */ 1002 @NonNull getImeFocusController()1003 public ImeFocusController getImeFocusController() { 1004 return mImeFocusController; 1005 } 1006 1007 private final ViewRootRectTracker mGestureExclusionTracker = 1008 new ViewRootRectTracker(v -> v.getSystemGestureExclusionRects()); 1009 private final ViewRootRectTracker mKeepClearRectsTracker = 1010 new ViewRootRectTracker(v -> v.collectPreferKeepClearRects()); 1011 private final ViewRootRectTracker mUnrestrictedKeepClearRectsTracker = 1012 new ViewRootRectTracker(v -> v.collectUnrestrictedPreferKeepClearRects()); 1013 private boolean mHasPendingKeepClearAreaChange; 1014 private Rect mKeepClearAccessibilityFocusRect; 1015 1016 private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection; 1017 1018 private final ISensitiveContentProtectionManager mSensitiveContentProtectionService; 1019 1020 static final class SystemUiVisibilityInfo { 1021 int globalVisibility; 1022 int localValue; 1023 int localChanges; 1024 } 1025 1026 private final HandwritingInitiator mHandwritingInitiator; 1027 1028 /** 1029 * Used by InputMethodManager. 1030 * @hide 1031 */ 1032 @NonNull getHandwritingInitiator()1033 public HandwritingInitiator getHandwritingInitiator() { 1034 return mHandwritingInitiator; 1035 } 1036 1037 /** 1038 * A SurfaceSyncGroup that is created when WMS requested to sync the buffer 1039 */ 1040 private SurfaceSyncGroup mWmsRequestSyncGroup; 1041 1042 /** 1043 * The SurfaceSyncGroup that represents the active VRI SurfaceSyncGroup. This is non null if 1044 * anyone requested the SurfaceSyncGroup for this VRI to ensure that anyone trying to sync with 1045 * this VRI are collected together. The SurfaceSyncGroup is cleared when the VRI draws since 1046 * that is the stop point where all changes are have been applied. A new SurfaceSyncGroup is 1047 * created after that point when something wants to sync VRI again. 1048 */ 1049 private SurfaceSyncGroup mActiveSurfaceSyncGroup; 1050 1051 1052 private final Object mPreviousSyncSafeguardLock = new Object(); 1053 1054 /** 1055 * Wraps the TransactionCommitted callback for the previous SSG so it can be added to the next 1056 * SSG if started before previous has completed. 1057 */ 1058 @GuardedBy("mPreviousSyncSafeguardLock") 1059 private SurfaceSyncGroup mPreviousSyncSafeguard; 1060 1061 private static final Object sSyncProgressLock = new Object(); 1062 // The count needs to be static since it's used to enable or disable RT animations which is 1063 // done at a global level per process. If any VRI syncs are in progress, we can't enable RT 1064 // animations until all are done. 1065 private static int sNumSyncsInProgress = 0; 1066 1067 private int mNumPausedForSync = 0; 1068 1069 private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks; 1070 1071 private long mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS; 1072 1073 /** 1074 * Increment this value when the surface has been replaced. 1075 */ 1076 private int mSurfaceSequenceId = 0; 1077 1078 private boolean mRelayoutRequested; 1079 1080 /** 1081 * Whether sandboxing of {@link android.view.View#getBoundsOnScreen}, 1082 * {@link android.view.View#getLocationOnScreen(int[])}, 1083 * {@link android.view.View#getWindowDisplayFrame} and 1084 * {@link android.view.View#getWindowVisibleDisplayFrame} 1085 * within Activity bounds is enabled for the current application. 1086 */ 1087 private final boolean mViewBoundsSandboxingEnabled; 1088 1089 private AccessibilityWindowAttributes mAccessibilityWindowAttributes; 1090 1091 /* 1092 * for Variable Refresh Rate project 1093 */ 1094 1095 // The preferred frame rate category of the view that 1096 // could be updated on a frame-by-frame basis. 1097 private int mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_DEFAULT; 1098 // The preferred frame rate category of the last frame that 1099 // could be used to lower frame rate after touch boost 1100 private int mLastPreferredFrameRateCategory = FRAME_RATE_CATEGORY_DEFAULT; 1101 // The preferred frame rate of the view that is mainly used for 1102 // touch boosting, view velocity handling, and TextureView. 1103 private float mPreferredFrameRate = 0; 1104 // The last preferred frame rate of the view that is mainly used to 1105 // track the difference between the current preferred frame rate and the previous value. 1106 private float mLastPreferredFrameRate = 0; 1107 // Used to check if it is in the frame rate boosting period. 1108 private boolean mIsFrameRateBoosting = false; 1109 // Used to check if it is in touch boosting period. 1110 private boolean mIsTouchBoosting = false; 1111 private boolean mDrawnThisFrame = false; 1112 // Used to check if there is a conflict between different frame rate voting. 1113 // Take 24 and 30 as an example, 24 is not a divisor of 30. 1114 // We consider there is a conflict. 1115 private boolean mIsFrameRateConflicted = false; 1116 // Used to set frame rate compatibility. 1117 @Surface.FrameRateCompatibility int mFrameRateCompatibility = 1118 FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; 1119 // time for touch boost period. 1120 private static final int FRAME_RATE_TOUCH_BOOST_TIME = 3000; 1121 // Timeout for the other frame rate boosts other than touch boost. 1122 private static final int FRAME_RATE_BOOST_TIME = 3000; 1123 // time for evaluating the interval between current time and 1124 // the time when frame rate was set previously. 1125 private static final int FRAME_RATE_SETTING_REEVALUATE_TIME = 100; 1126 1127 /* 1128 * The variables below are used to update frame rate category 1129 */ 1130 private static final int FRAME_RATE_CATEGORY_COUNT = 5; 1131 private int mFrameRateCategoryHighCount = 0; 1132 private int mFrameRateCategoryHighHintCount = 0; 1133 private int mFrameRateCategoryNormalCount = 0; 1134 private int mFrameRateCategoryLowCount = 0; 1135 1136 /* 1137 * the variables below are used to determine whther a dVRR feature should be enabled 1138 */ 1139 1140 /** 1141 * A temporary object used so relayoutWindow can return the latest SyncSeqId 1142 * system. The SyncSeqId system was designed to work without synchronous relayout 1143 * window, and actually synchronous relayout window presents a problem. We could have 1144 * a sequence like this: 1145 * 1. We send MSG_RESIZED to the client with a new syncSeqId to begin a new sync 1146 * 2. Due to scheduling the client executes performTraversals before calling MSG_RESIZED 1147 * 3. Coincidentally for some random reason it also calls relayout 1148 * 4. It observes the new state from relayout, and so the next frame will contain the state 1149 * However it hasn't received the seqId yet, and so under the designed operation of 1150 * seqId flowing through MSG_RESIZED, the next frame wouldn't be synced. Since it 1151 * contains our target sync state, we need to sync it! This problem won't come up once 1152 * we get rid of synchronous relayout, until then, we use this bundle to channel the 1153 * integer back over relayout. 1154 */ 1155 private final Bundle mRelayoutBundle = windowSessionRelayoutInfo() 1156 ? null 1157 : new Bundle(); 1158 1159 private final WindowRelayoutResult mRelayoutResult = windowSessionRelayoutInfo() 1160 ? new WindowRelayoutResult(mTmpFrames, mPendingMergedConfiguration, mSurfaceControl, 1161 mTempInsets, mTempControls) 1162 : null; 1163 1164 private static volatile boolean sAnrReported = false; 1165 static BLASTBufferQueue.TransactionHangCallback sTransactionHangCallback = 1166 new BLASTBufferQueue.TransactionHangCallback() { 1167 @Override 1168 public void onTransactionHang(String reason) { 1169 if (sAnrReported) { 1170 return; 1171 } 1172 1173 sAnrReported = true; 1174 // If we're making an in-process call to ActivityManagerService 1175 // and the previous binder call on this thread was oneway, the 1176 // calling PID will be 0. Clearing the calling identity fixes 1177 // this and ensures ActivityManager gets the correct calling 1178 // pid. 1179 final long identityToken = Binder.clearCallingIdentity(); 1180 try { 1181 ActivityManager.getService().appNotResponding(reason); 1182 } catch (RemoteException e) { 1183 // We asked the system to crash us, but the system 1184 // already crashed. Unfortunately things may be 1185 // out of control. 1186 } finally { 1187 Binder.restoreCallingIdentity(identityToken); 1188 } 1189 } 1190 }; 1191 private final Rect mChildBoundingInsets = new Rect(); 1192 private boolean mChildBoundingInsetsChanged = false; 1193 1194 private String mTag = TAG; 1195 private String mFpsTraceName; 1196 private String mLargestViewTraceName; 1197 1198 private final boolean mAppStartInfoTimestampsFlagValue; 1199 @GuardedBy("this") 1200 private boolean mAppStartTimestampsSent = false; 1201 private boolean mAppStartTrackingStarted = false; 1202 private long mRenderThreadDrawStartTimeNs = -1; 1203 private long mFirstFramePresentedTimeNs = -1; 1204 1205 private static boolean sToolkitSetFrameRateReadOnlyFlagValue; 1206 private static boolean sToolkitFrameRateFunctionEnablingReadOnlyFlagValue; 1207 private static boolean sToolkitMetricsForFrameRateDecisionFlagValue; 1208 private static boolean sToolkitFrameRateTypingReadOnlyFlagValue; 1209 private static final boolean sToolkitFrameRateViewEnablingReadOnlyFlagValue; 1210 private static boolean sToolkitFrameRateVelocityMappingReadOnlyFlagValue = 1211 toolkitFrameRateVelocityMappingReadOnly(); 1212 private static boolean sToolkitEnableInvalidateCheckThreadFlagValue = 1213 Flags.enableInvalidateCheckThread(); 1214 private static boolean sSurfaceFlingerBugfixFlagValue = 1215 com.android.graphics.surfaceflinger.flags.Flags.vrrBugfix24q4(); 1216 private static final boolean sEnableVrr = ViewProperties.vrr_enabled().orElse(true); 1217 1218 static { 1219 sToolkitSetFrameRateReadOnlyFlagValue = toolkitSetFrameRateReadOnly(); 1220 sToolkitMetricsForFrameRateDecisionFlagValue = toolkitMetricsForFrameRateDecision(); 1221 sToolkitFrameRateTypingReadOnlyFlagValue = toolkitFrameRateTypingReadOnly(); 1222 sToolkitFrameRateFunctionEnablingReadOnlyFlagValue = 1223 toolkitFrameRateFunctionEnablingReadOnly(); 1224 sToolkitFrameRateViewEnablingReadOnlyFlagValue = 1225 toolkitFrameRateViewEnablingReadOnly(); 1226 } 1227 1228 // The latest input event from the gesture that was used to resolve the pointer icon. 1229 private MotionEvent mPointerIconEvent = null; 1230 ViewRootImpl(Context context, Display display)1231 public ViewRootImpl(Context context, Display display) { 1232 this(context, display, WindowManagerGlobal.getWindowSession(), new WindowLayout()); 1233 } 1234 ViewRootImpl(@iContext Context context, Display display, IWindowSession session, WindowLayout windowLayout)1235 public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session, 1236 WindowLayout windowLayout) { 1237 mContext = context; 1238 mWindowSession = session; 1239 mWindowLayout = windowLayout; 1240 mDisplay = display; 1241 mBasePackageName = context.getBasePackageName(); 1242 final String name = DisplayProperties.debug_vri_package().orElse(null); 1243 mExtraDisplayListenerLogging = !TextUtils.isEmpty(name) && name.equals(mBasePackageName); 1244 mThread = Thread.currentThread(); 1245 mLocation = new WindowLeaked(null); 1246 mLocation.fillInStackTrace(); 1247 mWidth = -1; 1248 mHeight = -1; 1249 mDirty = new Rect(); 1250 mWinFrame = new Rect(); 1251 mLastLayoutFrame = new Rect(); 1252 mWindow = new W(this); 1253 mLeashToken = new Binder(); 1254 mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion; 1255 mViewVisibility = View.GONE; 1256 mTransparentRegion = new Region(); 1257 mPreviousTransparentRegion = new Region(); 1258 mFirst = true; // true for the first time the view is added 1259 mPerformContentCapture = true; // also true for the first time the view is added 1260 mAdded = false; 1261 mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this, 1262 context); 1263 mCompatibleVisibilityInfo = new SystemUiVisibilityInfo(); 1264 mAccessibilityManager = AccessibilityManager.getInstance(context); 1265 mHighContrastTextManager = new HighContrastTextManager(); 1266 mViewConfiguration = ViewConfiguration.get(context); 1267 mDensity = context.getResources().getDisplayMetrics().densityDpi; 1268 mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi; 1269 mFallbackEventHandler = new PhoneFallbackEventHandler(context); 1270 mChoreographer = Choreographer.getInstance(); 1271 mInsetsController = new InsetsController(new ViewRootInsetsControllerHost(this)); 1272 mImeBackAnimationController = new ImeBackAnimationController(this, mInsetsController); 1273 mHandwritingInitiator = new HandwritingInitiator( 1274 mViewConfiguration, 1275 mContext.getSystemService(InputMethodManager.class)); 1276 1277 mViewBoundsSandboxingEnabled = getViewBoundsSandboxingEnabled(); 1278 mIsStylusPointerIconEnabled = 1279 InputSettings.isStylusPointerIconEnabled(mContext); 1280 1281 String processorOverrideName = context.getResources().getString( 1282 R.string.config_inputEventCompatProcessorOverrideClassName); 1283 if (processorOverrideName.isEmpty()) { 1284 // No compatibility processor override, using default. 1285 mInputCompatProcessor = new InputEventCompatProcessor(context); 1286 } else { 1287 InputEventCompatProcessor compatProcessor = null; 1288 try { 1289 final Class<? extends InputEventCompatProcessor> klass = 1290 (Class<? extends InputEventCompatProcessor>) Class.forName( 1291 processorOverrideName); 1292 compatProcessor = klass.getConstructor(Context.class).newInstance(context); 1293 } catch (Exception e) { 1294 Log.e(TAG, "Unable to create the InputEventCompatProcessor. ", e); 1295 } finally { 1296 mInputCompatProcessor = compatProcessor; 1297 } 1298 } 1299 1300 if (!sCompatibilityDone) { 1301 sAlwaysAssignFocus = mTargetSdkVersion < Build.VERSION_CODES.P; 1302 1303 sCompatibilityDone = true; 1304 } 1305 1306 loadSystemProperties(); 1307 mImeFocusController = new ImeFocusController(this); 1308 1309 mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS; 1310 mOnBackInvokedDispatcher = new WindowOnBackInvokedDispatcher(context, Looper.myLooper()); 1311 if (sensitiveContentAppProtection()) { 1312 mSensitiveContentProtectionService = 1313 ISensitiveContentProtectionManager.Stub.asInterface( 1314 ServiceManager.getService(Context.SENSITIVE_CONTENT_PROTECTION_SERVICE)); 1315 if (mSensitiveContentProtectionService == null) { 1316 Log.e(TAG, "SensitiveContentProtectionService shouldn't be null"); 1317 } 1318 } else { 1319 mSensitiveContentProtectionService = null; 1320 } 1321 1322 mAppStartInfoTimestampsFlagValue = android.app.Flags.appStartInfoTimestamps(); 1323 } 1324 1325 public static void addFirstDrawHandler(Runnable callback) { 1326 synchronized (sFirstDrawHandlers) { 1327 if (!sFirstDrawComplete) { 1328 sFirstDrawHandlers.add(callback); 1329 } 1330 } 1331 } 1332 1333 /** Add static config callback to be notified about global config changes. */ 1334 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 1335 public static void addConfigCallback(ConfigChangedCallback callback) { 1336 synchronized (sConfigCallbacks) { 1337 sConfigCallbacks.add(callback); 1338 } 1339 } 1340 1341 /** Remove a static config callback. */ 1342 public static void removeConfigCallback(ConfigChangedCallback callback) { 1343 synchronized (sConfigCallbacks) { 1344 sConfigCallbacks.remove(callback); 1345 } 1346 } 1347 1348 /** 1349 * Add activity config callback to be notified about override config changes and camera 1350 * compat control state updates. 1351 */ 1352 public void setActivityConfigCallback(@Nullable ActivityConfigCallback callback) { 1353 mActivityConfigCallback = callback; 1354 if (!activityWindowInfoFlag()) { 1355 return; 1356 } 1357 if (callback == null) { 1358 mPendingActivityWindowInfo = null; 1359 mLastReportedActivityWindowInfo = null; 1360 } else { 1361 mPendingActivityWindowInfo = new ActivityWindowInfo(); 1362 mLastReportedActivityWindowInfo = new ActivityWindowInfo(); 1363 } 1364 } 1365 1366 public void setOnContentApplyWindowInsetsListener(OnContentApplyWindowInsetsListener listener) { 1367 mAttachInfo.mContentOnApplyWindowInsetsListener = listener; 1368 1369 // System windows will be fitted on first traversal, so no reason to request additional 1370 // (possibly getting executed after the first traversal). 1371 if (!mFirst) { 1372 requestFitSystemWindows(); 1373 } 1374 } 1375 1376 public void addWindowCallbacks(WindowCallbacks callback) { 1377 mWindowCallbacks.add(callback); 1378 } 1379 1380 public void removeWindowCallbacks(WindowCallbacks callback) { 1381 mWindowCallbacks.remove(callback); 1382 } 1383 1384 public void reportDrawFinish() { 1385 if (mWindowDrawCountDown != null) { 1386 mWindowDrawCountDown.countDown(); 1387 } 1388 } 1389 1390 // FIXME for perf testing only 1391 private boolean mProfile = false; 1392 1393 /** 1394 * Call this to profile the next traversal call. 1395 * FIXME for perf testing only. Remove eventually 1396 */ 1397 public void profile() { 1398 mProfile = true; 1399 } 1400 1401 private boolean isInTouchMode() { 1402 if (mAttachInfo == null) { 1403 return mContext.getResources().getBoolean(R.bool.config_defaultInTouchMode); 1404 } 1405 return mAttachInfo.mInTouchMode; 1406 } 1407 1408 /** 1409 * Notifies us that our child has been rebuilt, following 1410 * a window preservation operation. In these cases we 1411 * keep the same DecorView, but the activity controlling it 1412 * is a different instance, and we need to update our 1413 * callbacks. 1414 * 1415 * @hide 1416 */ 1417 public void notifyChildRebuilt() { 1418 if (mView instanceof RootViewSurfaceTaker) { 1419 if (mSurfaceHolderCallback != null) { 1420 mSurfaceHolder.removeCallback(mSurfaceHolderCallback); 1421 } 1422 1423 mSurfaceHolderCallback = 1424 ((RootViewSurfaceTaker)mView).willYouTakeTheSurface(); 1425 1426 if (mSurfaceHolderCallback != null) { 1427 mSurfaceHolder = new TakenSurfaceHolder(); 1428 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN); 1429 mSurfaceHolder.addCallback(mSurfaceHolderCallback); 1430 } else { 1431 mSurfaceHolder = null; 1432 } 1433 1434 mInputQueueCallback = 1435 ((RootViewSurfaceTaker)mView).willYouTakeTheInputQueue(); 1436 if (mInputQueueCallback != null) { 1437 mInputQueueCallback.onInputQueueCreated(mInputQueue); 1438 } 1439 } 1440 1441 // Update the last resource config in case the resource configuration was changed while 1442 // activity relaunched. 1443 updateLastConfigurationFromResources(getConfiguration()); 1444 // Make sure to report the completion of draw for relaunch with preserved window. 1445 reportNextDraw("rebuilt"); 1446 // Make sure to resume this root view when relaunching its host activity which was stopped. 1447 if (mStopped) { 1448 setWindowStopped(false); 1449 } 1450 } 1451 1452 private Configuration getConfiguration() { 1453 return mContext.getResources().getConfiguration(); 1454 } 1455 1456 private WindowConfiguration getCompatWindowConfiguration() { 1457 final WindowConfiguration winConfig = getConfiguration().windowConfiguration; 1458 if (mInvCompatScale == 1f) { 1459 return winConfig; 1460 } 1461 mTempWinConfig.setTo(winConfig); 1462 mTempWinConfig.scale(mInvCompatScale); 1463 return mTempWinConfig; 1464 } 1465 1466 /** 1467 * We have one child 1468 */ 1469 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { 1470 setView(view, attrs, panelParentView, UserHandle.myUserId()); 1471 } 1472 1473 /** 1474 * We have one child 1475 */ 1476 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, 1477 int userId) { 1478 synchronized (this) { 1479 if (mView == null) { 1480 mView = view; 1481 1482 mViewLayoutDirectionInitial = mView.getRawLayoutDirection(); 1483 mFallbackEventHandler.setView(view); 1484 mWindowAttributes.copyFrom(attrs); 1485 if (mWindowAttributes.packageName == null) { 1486 mWindowAttributes.packageName = mBasePackageName; 1487 } 1488 1489 attrs = mWindowAttributes; 1490 setTag(); 1491 mFpsTraceName = "FPS of " + getTitle(); 1492 mLargestViewTraceName = "Largest view percentage(per hundred) of " + getTitle(); 1493 1494 if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags 1495 & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0 1496 && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) { 1497 Slog.d(mTag, "setView: FLAG_KEEP_SCREEN_ON changed from true to false!"); 1498 } 1499 // Keep track of the actual window flags supplied by the client. 1500 mClientWindowLayoutFlags = attrs.flags; 1501 1502 adjustLayoutInDisplayCutoutMode(attrs); 1503 setAccessibilityFocus(null, null); 1504 1505 if (view instanceof RootViewSurfaceTaker) { 1506 mSurfaceHolderCallback = 1507 ((RootViewSurfaceTaker)view).willYouTakeTheSurface(); 1508 if (mSurfaceHolderCallback != null) { 1509 mSurfaceHolder = new TakenSurfaceHolder(); 1510 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN); 1511 mSurfaceHolder.addCallback(mSurfaceHolderCallback); 1512 } 1513 } 1514 1515 // Compute surface insets required to draw at specified Z value. 1516 // TODO: Use real shadow insets for a constant max Z. 1517 if (!attrs.hasManualSurfaceInsets) { 1518 attrs.setSurfaceInsets(view, false /*manual*/, true /*preservePrevious*/); 1519 } 1520 1521 CompatibilityInfo compatibilityInfo = 1522 mDisplay.getDisplayAdjustments().getCompatibilityInfo(); 1523 mTranslator = compatibilityInfo.getTranslator(); 1524 1525 // If the application owns the surface, don't enable hardware acceleration 1526 if (mSurfaceHolder == null) { 1527 // While this is supposed to enable only, it can effectively disable 1528 // the acceleration too. 1529 enableHardwareAcceleration(attrs); 1530 final boolean useMTRenderer = MT_RENDERER_AVAILABLE 1531 && mAttachInfo.mThreadedRenderer != null; 1532 if (mUseMTRenderer != useMTRenderer) { 1533 // Shouldn't be resizing, as it's done only in window setup, 1534 // but end just in case. 1535 endDragResizing(); 1536 mUseMTRenderer = useMTRenderer; 1537 } 1538 } 1539 1540 boolean restore = false; 1541 if (mTranslator != null) { 1542 mSurface.setCompatibilityTranslator(mTranslator); 1543 restore = true; 1544 attrs.backup(); 1545 mTranslator.translateWindowLayout(attrs); 1546 } 1547 if (DEBUG_LAYOUT) Log.d(mTag, "WindowLayout in setView:" + attrs); 1548 1549 mSoftInputMode = attrs.softInputMode; 1550 mWindowAttributesChanged = true; 1551 mAttachInfo.mRootView = view; 1552 mAttachInfo.mScalingRequired = mTranslator != null; 1553 mAttachInfo.mApplicationScale = 1554 mTranslator == null ? 1.0f : mTranslator.applicationScale; 1555 if (panelParentView != null) { 1556 mAttachInfo.mPanelParentWindowToken 1557 = panelParentView.getApplicationWindowToken(); 1558 } 1559 mAdded = true; 1560 int res; /* = WindowManagerImpl.ADD_OKAY; */ 1561 1562 // Schedule the first layout -before- adding to the window 1563 // manager, to make sure we do the relayout before receiving 1564 // any other events from the system. 1565 requestLayout(); 1566 InputChannel inputChannel = null; 1567 if ((mWindowAttributes.inputFeatures 1568 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) { 1569 inputChannel = new InputChannel(); 1570 } 1571 mForceDecorViewVisibility = (mWindowAttributes.privateFlags 1572 & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0; 1573 1574 if (mView instanceof RootViewSurfaceTaker) { 1575 PendingInsetsController pendingInsetsController = 1576 ((RootViewSurfaceTaker) mView).providePendingInsetsController(); 1577 if (pendingInsetsController != null) { 1578 pendingInsetsController.replayAndAttach(mInsetsController); 1579 } 1580 } 1581 if (mView instanceof DecorView) { 1582 mWindowAttributes.privateFlags |= PRIVATE_FLAG_APP_PROGRESS_GENERATION_ALLOWED; 1583 } 1584 1585 try { 1586 mOrigWindowType = mWindowAttributes.type; 1587 mAttachInfo.mRecomputeGlobalAttributes = true; 1588 collectViewAttributes(); 1589 adjustLayoutParamsForCompatibility(mWindowAttributes, 1590 mInsetsController.getAppearanceControlled(), 1591 mInsetsController.isBehaviorControlled()); 1592 controlInsetsForCompatibility(mWindowAttributes); 1593 1594 Rect attachedFrame = new Rect(); 1595 final float[] compatScale = { 1f }; 1596 res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes, 1597 getHostVisibility(), mDisplay.getDisplayId(), userId, 1598 mInsetsController.getRequestedVisibleTypes(), inputChannel, mTempInsets, 1599 mTempControls, attachedFrame, compatScale); 1600 if (!attachedFrame.isValid()) { 1601 attachedFrame = null; 1602 } 1603 if (mTranslator != null) { 1604 mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets); 1605 mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls.get()); 1606 mTranslator.translateRectInScreenToAppWindow(attachedFrame); 1607 } 1608 mTmpFrames.attachedFrame = attachedFrame; 1609 mTmpFrames.compatScale = compatScale[0]; 1610 mInvCompatScale = 1f / compatScale[0]; 1611 } catch (RemoteException | RuntimeException e) { 1612 mAdded = false; 1613 mView = null; 1614 mAttachInfo.mRootView = null; 1615 mFallbackEventHandler.setView(null); 1616 unscheduleTraversals(); 1617 setAccessibilityFocus(null, null); 1618 throw new RuntimeException("Adding window failed", e); 1619 } finally { 1620 if (restore) { 1621 attrs.restore(); 1622 } 1623 } 1624 1625 mAttachInfo.mAlwaysConsumeSystemBars = 1626 (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS) != 0; 1627 mPendingAlwaysConsumeSystemBars = mAttachInfo.mAlwaysConsumeSystemBars; 1628 mInsetsController.onStateChanged(mTempInsets); 1629 mInsetsController.onControlsChanged(mTempControls.get()); 1630 final InsetsState state = mInsetsController.getState(); 1631 final Rect displayCutoutSafe = mTempRect; 1632 state.getDisplayCutoutSafe(displayCutoutSafe); 1633 final WindowConfiguration winConfig = getCompatWindowConfiguration(); 1634 mWindowLayout.computeFrames(mWindowAttributes, state, 1635 displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(), 1636 UNSPECIFIED_LENGTH, UNSPECIFIED_LENGTH, 1637 mInsetsController.getRequestedVisibleTypes(), 1f /* compactScale */, 1638 mTmpFrames); 1639 setFrame(mTmpFrames.frame, true /* withinRelayout */); 1640 registerBackCallbackOnWindow(); 1641 if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow); 1642 if (res < WindowManagerGlobal.ADD_OKAY) { 1643 mAttachInfo.mRootView = null; 1644 mAdded = false; 1645 mFallbackEventHandler.setView(null); 1646 unscheduleTraversals(); 1647 setAccessibilityFocus(null, null); 1648 switch (res) { 1649 case WindowManagerGlobal.ADD_BAD_APP_TOKEN: 1650 case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN: 1651 throw new WindowManager.BadTokenException( 1652 "Unable to add window -- token " + attrs.token 1653 + " is not valid; is your activity running?"); 1654 case WindowManagerGlobal.ADD_NOT_APP_TOKEN: 1655 throw new WindowManager.BadTokenException( 1656 "Unable to add window -- token " + attrs.token 1657 + " is not for an application"); 1658 case WindowManagerGlobal.ADD_APP_EXITING: 1659 throw new WindowManager.BadTokenException( 1660 "Unable to add window -- app for token " + attrs.token 1661 + " is exiting"); 1662 case WindowManagerGlobal.ADD_DUPLICATE_ADD: 1663 throw new WindowManager.BadTokenException( 1664 "Unable to add window -- window " + mWindow 1665 + " has already been added"); 1666 case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED: 1667 // Silently ignore -- we would have just removed it 1668 // right away, anyway. 1669 return; 1670 case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON: 1671 throw new WindowManager.BadTokenException("Unable to add window " 1672 + mWindow + " -- another window of type " 1673 + mWindowAttributes.type + " already exists"); 1674 case WindowManagerGlobal.ADD_PERMISSION_DENIED: 1675 throw new WindowManager.BadTokenException("Unable to add window " 1676 + mWindow + " -- permission denied for window type " 1677 + mWindowAttributes.type); 1678 case WindowManagerGlobal.ADD_INVALID_DISPLAY: 1679 throw new WindowManager.InvalidDisplayException("Unable to add window " 1680 + mWindow + " -- the specified display can not be found"); 1681 case WindowManagerGlobal.ADD_INVALID_TYPE: 1682 throw new WindowManager.InvalidDisplayException("Unable to add window " 1683 + mWindow + " -- the specified window type " 1684 + mWindowAttributes.type + " is not valid"); 1685 case WindowManagerGlobal.ADD_INVALID_USER: 1686 throw new WindowManager.BadTokenException("Unable to add Window " 1687 + mWindow + " -- requested userId is not valid"); 1688 } 1689 throw new RuntimeException( 1690 "Unable to add window -- unknown error code " + res); 1691 } 1692 1693 registerListeners(); 1694 // We should update mAttachInfo.mDisplayState after registerDisplayListener 1695 // because displayState might be changed before registerDisplayListener. 1696 mAttachInfo.mDisplayState = mDisplay.getState(); 1697 if (mExtraDisplayListenerLogging) { 1698 Slog.i(mTag, "(" + mBasePackageName + ") Initial DisplayState: " 1699 + mAttachInfo.mDisplayState, new Throwable()); 1700 } 1701 1702 if (view instanceof RootViewSurfaceTaker) { 1703 mInputQueueCallback = 1704 ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue(); 1705 } 1706 if (inputChannel != null) { 1707 if (mInputQueueCallback != null) { 1708 mInputQueue = new InputQueue(); 1709 mInputQueueCallback.onInputQueueCreated(mInputQueue); 1710 } 1711 mInputEventReceiver = new WindowInputEventReceiver(inputChannel, 1712 Looper.myLooper()); 1713 1714 if (ENABLE_INPUT_LATENCY_TRACKING && mAttachInfo.mThreadedRenderer != null) { 1715 InputMetricsListener listener = new InputMetricsListener(); 1716 mHardwareRendererObserver = new HardwareRendererObserver( 1717 listener, listener.data, mHandler, true /*waitForPresentTime*/); 1718 mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver); 1719 } 1720 // Update unbuffered request when set the root view. 1721 mUnbufferedInputSource = mView.mUnbufferedInputSource; 1722 } 1723 1724 view.assignParent(this); 1725 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0; 1726 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0; 1727 1728 if (mAccessibilityManager.isEnabled()) { 1729 mAccessibilityInteractionConnectionManager.ensureConnection(); 1730 setAccessibilityWindowAttributesIfNeeded(); 1731 } 1732 1733 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 1734 view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); 1735 } 1736 1737 // Set up the input pipeline. 1738 CharSequence counterSuffix = attrs.getTitle(); 1739 mSyntheticInputStage = new SyntheticInputStage(); 1740 InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage); 1741 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage, 1742 "aq:native-post-ime:" + counterSuffix); 1743 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage); 1744 InputStage imeStage = new ImeInputStage(earlyPostImeStage, 1745 "aq:ime:" + counterSuffix); 1746 InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage); 1747 InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage, 1748 "aq:native-pre-ime:" + counterSuffix); 1749 1750 mFirstInputStage = nativePreImeStage; 1751 mFirstPostImeInputStage = earlyPostImeStage; 1752 mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix; 1753 1754 if (!mRemoved || !mAppVisible) { 1755 AnimationHandler.requestAnimatorsEnabled(mAppVisible, this); 1756 } else if (LOCAL_LOGV) { 1757 Log.v(mTag, "setView() enabling visibility when removed"); 1758 } 1759 } 1760 } 1761 } 1762 1763 private void setAccessibilityWindowAttributesIfNeeded() { 1764 final boolean registered = mAttachInfo.mAccessibilityWindowId 1765 != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 1766 if (registered) { 1767 final AccessibilityWindowAttributes attributes = new AccessibilityWindowAttributes( 1768 mWindowAttributes, mContext.getResources().getConfiguration().getLocales()); 1769 if (!attributes.equals(mAccessibilityWindowAttributes)) { 1770 mAccessibilityWindowAttributes = attributes; 1771 mAccessibilityManager.setAccessibilityWindowAttributes(getDisplayId(), 1772 mAttachInfo.mAccessibilityWindowId, attributes); 1773 } 1774 1775 } 1776 } 1777 1778 private boolean isForceInvertEnabled() { 1779 if (mForceInvertEnabled == INVALID_VALUE) { 1780 reloadForceInvertEnabled(); 1781 } 1782 return mForceInvertEnabled == 1; 1783 } 1784 1785 private void reloadForceInvertEnabled() { 1786 if (forceInvertColor()) { 1787 mForceInvertEnabled = Settings.Secure.getIntForUser( 1788 mContext.getContentResolver(), 1789 Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED, 1790 /* def= */ 0, 1791 UserHandle.myUserId()); 1792 } 1793 } 1794 1795 /** 1796 * Register any kind of listeners if setView was success. 1797 */ 1798 private void registerListeners() { 1799 if (mExtraDisplayListenerLogging) { 1800 Slog.i(mTag, "Register listeners: " + mBasePackageName); 1801 } 1802 mAccessibilityManager.addAccessibilityStateChangeListener( 1803 mAccessibilityInteractionConnectionManager, mHandler); 1804 mAccessibilityManager.addHighTextContrastStateChangeListener( 1805 mHighContrastTextManager, mHandler); 1806 DisplayManagerGlobal 1807 .getInstance() 1808 .registerDisplayListener( 1809 mDisplayListener, 1810 mHandler, 1811 DisplayManager.EVENT_FLAG_DISPLAY_ADDED 1812 | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED 1813 | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED, 1814 mBasePackageName); 1815 1816 if (forceInvertColor()) { 1817 if (mForceInvertObserver == null) { 1818 mForceInvertObserver = new ContentObserver(mHandler) { 1819 @Override 1820 public void onChange(boolean selfChange) { 1821 reloadForceInvertEnabled(); 1822 updateForceDarkMode(); 1823 } 1824 }; 1825 mContext.getContentResolver().registerContentObserver( 1826 Settings.Secure.getUriFor( 1827 Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED 1828 ), 1829 false, 1830 mForceInvertObserver, 1831 UserHandle.myUserId()); 1832 } 1833 } 1834 } 1835 1836 /** 1837 * Unregister all listeners while detachedFromWindow. 1838 */ 1839 private void unregisterListeners() { 1840 mAccessibilityManager.removeAccessibilityStateChangeListener( 1841 mAccessibilityInteractionConnectionManager); 1842 mAccessibilityManager.removeHighTextContrastStateChangeListener( 1843 mHighContrastTextManager); 1844 DisplayManagerGlobal 1845 .getInstance() 1846 .unregisterDisplayListener(mDisplayListener); 1847 1848 if (forceInvertColor()) { 1849 if (mForceInvertObserver != null) { 1850 mContext.getContentResolver().unregisterContentObserver(mForceInvertObserver); 1851 mForceInvertObserver = null; 1852 } 1853 } 1854 1855 if (mExtraDisplayListenerLogging) { 1856 Slog.w(mTag, "Unregister listeners: " + mBasePackageName, new Throwable()); 1857 } 1858 } 1859 1860 private void setTag() { 1861 final String[] split = mWindowAttributes.getTitle().toString().split("\\."); 1862 if (split.length > 0) { 1863 mTag = "VRI[" + split[split.length - 1] + "]"; 1864 } 1865 } 1866 1867 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 1868 public int getWindowFlags() { 1869 return mWindowAttributes.flags; 1870 } 1871 1872 public int getDisplayId() { 1873 return mDisplay.getDisplayId(); 1874 } 1875 1876 public CharSequence getTitle() { 1877 return mWindowAttributes.getTitle(); 1878 } 1879 1880 /** 1881 * @return the width of the root view. Note that this will return {@code -1} until the first 1882 * layout traversal, when the width is set. 1883 * 1884 * @hide 1885 */ 1886 public int getWidth() { 1887 return mWidth; 1888 } 1889 1890 /** 1891 * @return the height of the root view. Note that this will return {@code -1} until the first 1892 * layout traversal, when the height is set. 1893 * 1894 * @hide 1895 */ 1896 public int getHeight() { 1897 return mHeight; 1898 } 1899 1900 /** 1901 * Destroys hardware rendering resources for this ViewRootImpl 1902 * 1903 * May be called on any thread 1904 */ 1905 @AnyThread 1906 void destroyHardwareResources() { 1907 final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer; 1908 if (renderer != null) { 1909 // This is called by WindowManagerGlobal which may or may not be on the right thread 1910 if (Looper.myLooper() != mAttachInfo.mHandler.getLooper()) { 1911 mAttachInfo.mHandler.postAtFrontOfQueue(this::destroyHardwareResources); 1912 return; 1913 } 1914 renderer.destroyHardwareResources(mView); 1915 renderer.destroy(); 1916 } 1917 } 1918 1919 /** 1920 * Does nothing; Here only because of @UnsupportedAppUsage 1921 */ 1922 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, 1923 publicAlternatives = "Use {@link android.webkit.WebView} instead") 1924 public void detachFunctor(long functor) { } 1925 1926 /** 1927 * Does nothing; Here only because of @UnsupportedAppUsage 1928 */ 1929 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, 1930 publicAlternatives = "Use {@link android.webkit.WebView} instead") 1931 public static void invokeFunctor(long functor, boolean waitForCompletion) { } 1932 1933 /** 1934 * @param animator animator to register with the hardware renderer 1935 */ 1936 public void registerAnimatingRenderNode(RenderNode animator) { 1937 if (mAttachInfo.mThreadedRenderer != null) { 1938 mAttachInfo.mThreadedRenderer.registerAnimatingRenderNode(animator); 1939 } else { 1940 if (mAttachInfo.mPendingAnimatingRenderNodes == null) { 1941 mAttachInfo.mPendingAnimatingRenderNodes = new ArrayList<RenderNode>(); 1942 } 1943 mAttachInfo.mPendingAnimatingRenderNodes.add(animator); 1944 } 1945 } 1946 1947 /** 1948 * @param animator animator to register with the hardware renderer 1949 */ 1950 public void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator) { 1951 if (mAttachInfo.mThreadedRenderer != null) { 1952 mAttachInfo.mThreadedRenderer.registerVectorDrawableAnimator(animator); 1953 } 1954 } 1955 1956 /** 1957 * Registers a callback to be executed when the next frame is being drawn on RenderThread. This 1958 * callback will be executed on a RenderThread worker thread, and only used for the next frame 1959 * and thus it will only fire once. 1960 * 1961 * @param callback The callback to register. 1962 */ 1963 public void registerRtFrameCallback(@NonNull FrameDrawingCallback callback) { 1964 if (mAttachInfo.mThreadedRenderer != null) { 1965 mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() { 1966 @Override 1967 public void onFrameDraw(long frame) { 1968 } 1969 1970 @Override 1971 public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, 1972 long frame) { 1973 try { 1974 return callback.onFrameDraw(syncResult, frame); 1975 } catch (Exception e) { 1976 Log.e(TAG, "Exception while executing onFrameDraw", e); 1977 } 1978 return null; 1979 } 1980 }); 1981 } 1982 } 1983 1984 @UnsupportedAppUsage 1985 private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) { 1986 mAttachInfo.mHardwareAccelerated = false; 1987 mAttachInfo.mHardwareAccelerationRequested = false; 1988 1989 // Don't enable hardware acceleration when the application is in compatibility mode 1990 if (mTranslator != null) return; 1991 1992 // Try to enable hardware acceleration if requested 1993 final boolean hardwareAccelerated = 1994 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0; 1995 1996 if (hardwareAccelerated) { 1997 // Persistent processes (including the system) should not do 1998 // accelerated rendering on low-end devices. In that case, 1999 // sRendererDisabled will be set. In addition, the system process 2000 // itself should never do accelerated rendering. In that case, both 2001 // sRendererDisabled and sSystemRendererDisabled are set. When 2002 // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED 2003 // can be used by code on the system process to escape that and enable 2004 // HW accelerated drawing. (This is basically for the lock screen.) 2005 2006 final boolean forceHwAccelerated = (attrs.privateFlags & 2007 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0; 2008 2009 if (ThreadedRenderer.sRendererEnabled || forceHwAccelerated) { 2010 if (mAttachInfo.mThreadedRenderer != null) { 2011 mAttachInfo.mThreadedRenderer.destroy(); 2012 } 2013 2014 final Rect insets = attrs.surfaceInsets; 2015 final boolean hasSurfaceInsets = insets.left != 0 || insets.right != 0 2016 || insets.top != 0 || insets.bottom != 0; 2017 final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets; 2018 final ThreadedRenderer renderer = ThreadedRenderer.create(mContext, translucent, 2019 attrs.getTitle().toString()); 2020 mAttachInfo.mThreadedRenderer = renderer; 2021 renderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue); 2022 updateColorModeIfNeeded(attrs.getColorMode(), attrs.getDesiredHdrHeadroom()); 2023 mHdrRenderState.forceUpdateHdrSdrRatio(); 2024 updateForceDarkMode(); 2025 mAttachInfo.mHardwareAccelerated = true; 2026 mAttachInfo.mHardwareAccelerationRequested = true; 2027 if (mHardwareRendererObserver != null) { 2028 renderer.addObserver(mHardwareRendererObserver); 2029 } 2030 } 2031 } 2032 } 2033 2034 private int getNightMode() { 2035 return getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; 2036 } 2037 2038 /** Returns true if force dark should be enabled according to various settings */ 2039 @VisibleForTesting 2040 public @ForceDarkType.ForceDarkTypeDef int determineForceDarkType() { 2041 if (forceInvertColor()) { 2042 // Force invert ignores all developer opt-outs. 2043 // We also ignore dark theme, since the app developer can override the user's preference 2044 // for dark mode in configuration.uiMode. Instead, we assume that the force invert 2045 // setting will be enabled at the same time dark theme is in the Settings app. 2046 if (isForceInvertEnabled()) { 2047 return ForceDarkType.FORCE_INVERT_COLOR_DARK; 2048 } 2049 } 2050 2051 boolean useAutoDark = getNightMode() == Configuration.UI_MODE_NIGHT_YES; 2052 2053 if (useAutoDark) { 2054 boolean forceDarkAllowedDefault = 2055 SystemProperties.getBoolean(ThreadedRenderer.DEBUG_FORCE_DARK, false); 2056 TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme); 2057 useAutoDark = a.getBoolean(R.styleable.Theme_isLightTheme, true) 2058 && a.getBoolean(R.styleable.Theme_forceDarkAllowed, forceDarkAllowedDefault); 2059 a.recycle(); 2060 } 2061 return useAutoDark ? ForceDarkType.FORCE_DARK : ForceDarkType.NONE; 2062 } 2063 2064 private void updateForceDarkMode() { 2065 if (mAttachInfo.mThreadedRenderer == null) return; 2066 if (mAttachInfo.mThreadedRenderer.setForceDark(determineForceDarkType())) { 2067 // TODO: Don't require regenerating all display lists to apply this setting 2068 invalidateWorld(mView); 2069 } 2070 } 2071 2072 @UnsupportedAppUsage 2073 public View getView() { 2074 return mView; 2075 } 2076 2077 final WindowLeaked getLocation() { 2078 return mLocation; 2079 } 2080 2081 @VisibleForTesting 2082 public void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) { 2083 synchronized (this) { 2084 final int oldInsetLeft = mWindowAttributes.surfaceInsets.left; 2085 final int oldInsetTop = mWindowAttributes.surfaceInsets.top; 2086 final int oldInsetRight = mWindowAttributes.surfaceInsets.right; 2087 final int oldInsetBottom = mWindowAttributes.surfaceInsets.bottom; 2088 final int oldSoftInputMode = mWindowAttributes.softInputMode; 2089 final boolean oldHasManualSurfaceInsets = mWindowAttributes.hasManualSurfaceInsets; 2090 2091 if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags 2092 & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0 2093 && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) { 2094 Slog.d(mTag, "setLayoutParams: FLAG_KEEP_SCREEN_ON from true to false!"); 2095 } 2096 2097 // Keep track of the actual window flags supplied by the client. 2098 mClientWindowLayoutFlags = attrs.flags; 2099 2100 // Preserve system UI visibility. 2101 final int systemUiVisibility = mWindowAttributes.systemUiVisibility; 2102 final int subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility; 2103 2104 // Preserve appearance and behavior. 2105 final int appearance = mWindowAttributes.insetsFlags.appearance; 2106 final int behavior = mWindowAttributes.insetsFlags.behavior; 2107 2108 // Calling this before copying prevents redundant LAYOUT_CHANGED. 2109 final int layoutInDisplayCutoutModeFromCaller = adjustLayoutInDisplayCutoutMode(attrs); 2110 2111 final int changes = mWindowAttributes.copyFrom(attrs); 2112 if ((changes & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) { 2113 // Recompute system ui visibility. 2114 mAttachInfo.mRecomputeGlobalAttributes = true; 2115 } 2116 if ((changes & WindowManager.LayoutParams.LAYOUT_CHANGED) != 0) { 2117 // Request to update light center. 2118 mAttachInfo.mNeedsUpdateLightCenter = true; 2119 } 2120 if ((changes & WindowManager.LayoutParams.COLOR_MODE_CHANGED) != 0) { 2121 invalidate(); 2122 } 2123 if (mWindowAttributes.packageName == null) { 2124 mWindowAttributes.packageName = mBasePackageName; 2125 } 2126 2127 // Restore the layoutInDisplayCutoutMode of the caller; 2128 attrs.layoutInDisplayCutoutMode = layoutInDisplayCutoutModeFromCaller; 2129 2130 // Restore preserved flags. 2131 mWindowAttributes.systemUiVisibility = systemUiVisibility; 2132 mWindowAttributes.subtreeSystemUiVisibility = subtreeSystemUiVisibility; 2133 mWindowAttributes.insetsFlags.appearance = appearance; 2134 mWindowAttributes.insetsFlags.behavior = behavior; 2135 2136 if (mWindowAttributes.preservePreviousSurfaceInsets) { 2137 // Restore old surface insets. 2138 mWindowAttributes.surfaceInsets.set( 2139 oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom); 2140 mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets; 2141 } else if (mWindowAttributes.surfaceInsets.left != oldInsetLeft 2142 || mWindowAttributes.surfaceInsets.top != oldInsetTop 2143 || mWindowAttributes.surfaceInsets.right != oldInsetRight 2144 || mWindowAttributes.surfaceInsets.bottom != oldInsetBottom) { 2145 mNeedsRendererSetup = true; 2146 } 2147 2148 applyKeepScreenOnFlag(mWindowAttributes); 2149 2150 if (newView) { 2151 mSoftInputMode = attrs.softInputMode; 2152 requestLayout(); 2153 } 2154 2155 // Don't lose the mode we last auto-computed. 2156 if ((attrs.softInputMode & SOFT_INPUT_MASK_ADJUST) 2157 == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) { 2158 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode 2159 & ~SOFT_INPUT_MASK_ADJUST) | (oldSoftInputMode & SOFT_INPUT_MASK_ADJUST); 2160 } 2161 2162 if (mWindowAttributes.softInputMode != oldSoftInputMode) { 2163 requestFitSystemWindows(); 2164 } 2165 2166 mWindowAttributesChanged = true; 2167 scheduleTraversals(); 2168 setAccessibilityWindowAttributesIfNeeded(); 2169 } 2170 } 2171 2172 private int adjustLayoutInDisplayCutoutMode(WindowManager.LayoutParams attrs) { 2173 final int originalMode = attrs.layoutInDisplayCutoutMode; 2174 if ((attrs.privateFlags & (PRIVATE_FLAG_EDGE_TO_EDGE_ENFORCED 2175 | PRIVATE_FLAG_OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE)) != 0 2176 && attrs.isFullscreen() 2177 && attrs.getFitInsetsTypes() == 0 2178 && attrs.getFitInsetsSides() == 0) { 2179 if (originalMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) { 2180 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; 2181 } 2182 } 2183 return originalMode; 2184 } 2185 2186 void handleAppVisibility(boolean visible) { 2187 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 2188 Trace.instant(Trace.TRACE_TAG_VIEW, TextUtils.formatSimple( 2189 "%s visibilityChanged oldVisibility=%b newVisibility=%b", mTag, 2190 mAppVisible, visible)); 2191 } 2192 if (mAppVisible != visible) { 2193 final boolean previousVisible = getHostVisibility() == View.VISIBLE; 2194 mAppVisible = visible; 2195 final boolean currentVisible = getHostVisibility() == View.VISIBLE; 2196 // Root view only cares about whether it is visible or not. 2197 if (previousVisible != currentVisible) { 2198 Log.d(mTag, "visibilityChanged oldVisibility=" + previousVisible + " newVisibility=" 2199 + currentVisible); 2200 mAppVisibilityChanged = true; 2201 scheduleTraversals(); 2202 } 2203 // Only enable if the window is not already removed (via earlier call to doDie()) 2204 if (!mRemoved || !mAppVisible) { 2205 AnimationHandler.requestAnimatorsEnabled(mAppVisible, this); 2206 } else if (LOCAL_LOGV) { 2207 Log.v(mTag, "handleAppVisibility() enabling visibility when removed"); 2208 } 2209 } 2210 } 2211 2212 void handleGetNewSurface() { 2213 mNewSurfaceNeeded = true; 2214 mFullRedrawNeeded = true; 2215 scheduleTraversals(); 2216 } 2217 2218 /** Handles messages {@link #MSG_RESIZED} and {@link #MSG_RESIZED_REPORT}. */ 2219 private void handleResized(ClientWindowFrames frames, boolean reportDraw, 2220 MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout, 2221 boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing, 2222 @Nullable ActivityWindowInfo activityWindowInfo) { 2223 if (!mAdded) { 2224 return; 2225 } 2226 2227 CompatibilityInfo.applyOverrideScaleIfNeeded(mergedConfiguration); 2228 final Rect frame = frames.frame; 2229 final Rect displayFrame = frames.displayFrame; 2230 final Rect attachedFrame = frames.attachedFrame; 2231 if (mTranslator != null) { 2232 mTranslator.translateInsetsStateInScreenToAppWindow(insetsState); 2233 mTranslator.translateRectInScreenToAppWindow(frame); 2234 mTranslator.translateRectInScreenToAppWindow(displayFrame); 2235 mTranslator.translateRectInScreenToAppWindow(attachedFrame); 2236 } 2237 mInsetsController.onStateChanged(insetsState); 2238 final float compatScale = frames.compatScale; 2239 final boolean frameChanged = !mWinFrame.equals(frame); 2240 final boolean shouldReportActivityWindowInfoChanged = 2241 // Can be null if callbacks is not set 2242 mLastReportedActivityWindowInfo != null 2243 // Can be null if not activity window 2244 && activityWindowInfo != null 2245 && !mLastReportedActivityWindowInfo.equals(activityWindowInfo); 2246 final boolean configChanged = !mLastReportedMergedConfiguration.equals(mergedConfiguration) 2247 || shouldReportActivityWindowInfoChanged; 2248 final boolean attachedFrameChanged = 2249 !Objects.equals(mTmpFrames.attachedFrame, attachedFrame); 2250 final boolean displayChanged = mDisplay.getDisplayId() != displayId; 2251 final boolean compatScaleChanged = mTmpFrames.compatScale != compatScale; 2252 final boolean dragResizingChanged = mPendingDragResizing != dragResizing; 2253 if (!reportDraw && !frameChanged && !configChanged && !attachedFrameChanged 2254 && !displayChanged && !forceLayout 2255 && !compatScaleChanged && !dragResizingChanged) { 2256 return; 2257 } 2258 2259 mPendingDragResizing = dragResizing; 2260 mTmpFrames.compatScale = compatScale; 2261 mInvCompatScale = 1f / compatScale; 2262 2263 if (configChanged) { 2264 // If configuration changed - notify about that and, maybe, about move to display. 2265 performConfigurationChange(mergedConfiguration, false /* force */, 2266 displayChanged ? displayId : INVALID_DISPLAY /* same display */, 2267 activityWindowInfo); 2268 } else if (displayChanged) { 2269 // Moved to display without config change - report last applied one. 2270 onMovedToDisplay(displayId, mLastConfigurationFromResources); 2271 } 2272 2273 setFrame(frame, false /* withinRelayout */); 2274 mTmpFrames.displayFrame.set(displayFrame); 2275 if (mTmpFrames.attachedFrame != null && attachedFrame != null) { 2276 mTmpFrames.attachedFrame.set(attachedFrame); 2277 } 2278 2279 if (mDragResizing && mUseMTRenderer) { 2280 boolean fullscreen = frame.equals(mPendingBackDropFrame); 2281 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { 2282 mWindowCallbacks.get(i).onWindowSizeIsChanging(mPendingBackDropFrame, fullscreen, 2283 mAttachInfo.mVisibleInsets, mAttachInfo.mStableInsets); 2284 } 2285 } 2286 2287 mForceNextWindowRelayout |= forceLayout; 2288 mPendingAlwaysConsumeSystemBars = alwaysConsumeSystemBars; 2289 mSyncSeqId = syncSeqId > mSyncSeqId ? syncSeqId : mSyncSeqId; 2290 2291 if (reportDraw) { 2292 reportNextDraw("resized"); 2293 } 2294 2295 if (mView != null && (frameChanged || configChanged)) { 2296 forceLayout(mView); 2297 } 2298 requestLayout(); 2299 } 2300 2301 /** Handles messages {@link #MSG_INSETS_CONTROL_CHANGED}. */ handleInsetsControlChanged(@onNull InsetsState insetsState, @NonNull InsetsSourceControl.Array activeControls)2302 private void handleInsetsControlChanged(@NonNull InsetsState insetsState, 2303 @NonNull InsetsSourceControl.Array activeControls) { 2304 final InsetsSourceControl[] controls = activeControls.get(); 2305 2306 if (mTranslator != null) { 2307 mTranslator.translateInsetsStateInScreenToAppWindow(insetsState); 2308 mTranslator.translateSourceControlsInScreenToAppWindow(controls); 2309 } 2310 2311 // Deliver state change before control change, such that: 2312 // a) When gaining control, controller can compare with server state to evaluate 2313 // whether it needs to run animation. 2314 // b) When loosing control, controller can restore server state by taking last 2315 // dispatched state as truth. 2316 mInsetsController.onStateChanged(insetsState); 2317 if (mAdded) { 2318 mInsetsController.onControlsChanged(controls); 2319 } else { 2320 activeControls.release(); 2321 } 2322 } 2323 2324 private final DisplayListener mDisplayListener = new DisplayListener() { 2325 @Override 2326 public void onDisplayChanged(int displayId) { 2327 if (mExtraDisplayListenerLogging) { 2328 Slog.i(mTag, "Received onDisplayChanged - " + mView); 2329 } 2330 if (mView != null && mDisplay.getDisplayId() == displayId) { 2331 final int oldDisplayState = mAttachInfo.mDisplayState; 2332 final int newDisplayState = mDisplay.getState(); 2333 if (mExtraDisplayListenerLogging) { 2334 Slog.i(mTag, "DisplayState - old: " + oldDisplayState 2335 + ", new: " + newDisplayState); 2336 } 2337 if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) { 2338 Trace.traceCounter(Trace.TRACE_TAG_WINDOW_MANAGER, 2339 "vri#screenState[" + mTag + "] state=", newDisplayState); 2340 } 2341 if (oldDisplayState != newDisplayState) { 2342 mAttachInfo.mDisplayState = newDisplayState; 2343 pokeDrawLockIfNeeded(); 2344 if (oldDisplayState != Display.STATE_UNKNOWN) { 2345 final int oldScreenState = toViewScreenState(oldDisplayState); 2346 final int newScreenState = toViewScreenState(newDisplayState); 2347 if (oldScreenState != newScreenState) { 2348 mView.dispatchScreenStateChanged(newScreenState); 2349 } 2350 if (oldDisplayState == Display.STATE_OFF) { 2351 // Draw was suppressed so we need to for it to happen here. 2352 mFullRedrawNeeded = true; 2353 scheduleTraversals(); 2354 } 2355 } 2356 } 2357 } 2358 } 2359 2360 @Override 2361 public void onDisplayRemoved(int displayId) { 2362 } 2363 2364 @Override 2365 public void onDisplayAdded(int displayId) { 2366 } 2367 2368 private int toViewScreenState(int displayState) { 2369 return displayState == Display.STATE_OFF ? 2370 View.SCREEN_STATE_OFF : View.SCREEN_STATE_ON; 2371 } 2372 }; 2373 2374 /** 2375 * Notify about move to a different display. 2376 * @param displayId The id of the display where this view root is moved to. 2377 * @param config Configuration of the resources on new display after move. 2378 * 2379 * @hide 2380 */ onMovedToDisplay(int displayId, Configuration config)2381 public void onMovedToDisplay(int displayId, Configuration config) { 2382 if (mDisplay.getDisplayId() == displayId) { 2383 return; 2384 } 2385 2386 // Get new instance of display based on current display adjustments. It may be updated later 2387 // if moving between the displays also involved a configuration change. 2388 updateInternalDisplay(displayId, mView.getResources()); 2389 mImeFocusController.onMovedToDisplay(); 2390 mAttachInfo.mDisplayState = mDisplay.getState(); 2391 // Internal state updated, now notify the view hierarchy. 2392 mView.dispatchMovedToDisplay(mDisplay, config); 2393 } 2394 2395 /** 2396 * Updates {@link #mDisplay} to the display object corresponding to {@param displayId}. 2397 * Uses DEFAULT_DISPLAY if there isn't a display object in the system corresponding 2398 * to {@param displayId}. 2399 */ updateInternalDisplay(int displayId, Resources resources)2400 private void updateInternalDisplay(int displayId, Resources resources) { 2401 final Display preferredDisplay = 2402 ResourcesManager.getInstance().getAdjustedDisplay(displayId, resources); 2403 mHdrRenderState.stopListening(); 2404 if (preferredDisplay == null) { 2405 // Fallback to use default display. 2406 Slog.w(TAG, "Cannot get desired display with Id: " + displayId); 2407 mDisplay = ResourcesManager.getInstance() 2408 .getAdjustedDisplay(DEFAULT_DISPLAY, resources); 2409 } else { 2410 mDisplay = preferredDisplay; 2411 } 2412 mHdrRenderState.startListening(); 2413 mContext.updateDisplay(mDisplay.getDisplayId()); 2414 } 2415 pokeDrawLockIfNeeded()2416 void pokeDrawLockIfNeeded() { 2417 if (!Display.isDozeState(mAttachInfo.mDisplayState)) { 2418 // Only need to acquire wake lock for DOZE state. 2419 return; 2420 } 2421 if (mWindowAttributes.type != WindowManager.LayoutParams.TYPE_BASE_APPLICATION) { 2422 // Non-activity windows should be responsible to hold wake lock by themself, because 2423 // usually they are system windows. 2424 return; 2425 } 2426 if (mAdded && mTraversalScheduled && mAttachInfo.mHasWindowFocus) { 2427 try { 2428 mWindowSession.pokeDrawLock(mWindow); 2429 } catch (RemoteException ex) { 2430 // System server died, oh well. 2431 } 2432 } 2433 } 2434 2435 @Override requestFitSystemWindows()2436 public void requestFitSystemWindows() { 2437 checkThread(); 2438 mApplyInsetsRequested = true; 2439 scheduleTraversals(); 2440 } 2441 notifyInsetsChanged()2442 void notifyInsetsChanged() { 2443 mApplyInsetsRequested = true; 2444 requestLayout(); 2445 2446 // See comment for View.sForceLayoutWhenInsetsChanged 2447 if (View.sForceLayoutWhenInsetsChanged && mView != null 2448 && (mWindowAttributes.softInputMode & SOFT_INPUT_MASK_ADJUST) 2449 == SOFT_INPUT_ADJUST_RESIZE) { 2450 forceLayout(mView); 2451 } 2452 2453 // If this changes during traversal, no need to schedule another one as it will dispatch it 2454 // during the current traversal. 2455 if (!mIsInTraversal) { 2456 scheduleTraversals(); 2457 } 2458 } 2459 2460 /** 2461 * Notify the when the running state of a insets animation changed. 2462 */ 2463 @VisibleForTesting notifyInsetsAnimationRunningStateChanged(boolean running)2464 public void notifyInsetsAnimationRunningStateChanged(boolean running) { 2465 if (sToolkitSetFrameRateReadOnlyFlagValue) { 2466 mInsetsAnimationRunning = running; 2467 } 2468 } 2469 2470 @Override requestLayout()2471 public void requestLayout() { 2472 if (!mHandlingLayoutInLayoutRequest) { 2473 checkThread(); 2474 mLayoutRequested = true; 2475 scheduleTraversals(); 2476 } 2477 } 2478 2479 @Override isLayoutRequested()2480 public boolean isLayoutRequested() { 2481 return mLayoutRequested; 2482 } 2483 2484 @Override onDescendantInvalidated(@onNull View child, @NonNull View descendant)2485 public void onDescendantInvalidated(@NonNull View child, @NonNull View descendant) { 2486 if (sToolkitEnableInvalidateCheckThreadFlagValue) { 2487 checkThread(); 2488 } 2489 if ((descendant.mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 2490 mIsAnimating = true; 2491 } 2492 invalidate(); 2493 } 2494 2495 @UnsupportedAppUsage invalidate()2496 void invalidate() { 2497 mDirty.set(0, 0, mWidth, mHeight); 2498 if (!mWillDrawSoon) { 2499 scheduleTraversals(); 2500 } 2501 } 2502 invalidateWorld(View view)2503 void invalidateWorld(View view) { 2504 view.invalidate(); 2505 if (view instanceof ViewGroup) { 2506 ViewGroup parent = (ViewGroup) view; 2507 for (int i = 0; i < parent.getChildCount(); i++) { 2508 invalidateWorld(parent.getChildAt(i)); 2509 } 2510 } 2511 } 2512 2513 @Override invalidateChild(View child, Rect dirty)2514 public void invalidateChild(View child, Rect dirty) { 2515 invalidateChildInParent(null, dirty); 2516 } 2517 2518 @Override invalidateChildInParent(int[] location, Rect dirty)2519 public ViewParent invalidateChildInParent(int[] location, Rect dirty) { 2520 checkThread(); 2521 if (DEBUG_DRAW) Log.v(mTag, "Invalidate child: " + dirty); 2522 2523 if (dirty == null) { 2524 invalidate(); 2525 return null; 2526 } else if (dirty.isEmpty() && !mIsAnimating) { 2527 return null; 2528 } 2529 2530 if (mCurScrollY != 0 || mTranslator != null) { 2531 mTempRect.set(dirty); 2532 dirty = mTempRect; 2533 if (mCurScrollY != 0) { 2534 dirty.offset(0, -mCurScrollY); 2535 } 2536 if (mTranslator != null) { 2537 mTranslator.translateRectInAppWindowToScreen(dirty); 2538 } 2539 if (mAttachInfo.mScalingRequired) { 2540 dirty.inset(-1, -1); 2541 } 2542 } 2543 2544 invalidateRectOnScreen(dirty); 2545 2546 return null; 2547 } 2548 invalidateRectOnScreen(Rect dirty)2549 private void invalidateRectOnScreen(Rect dirty) { 2550 if (DEBUG_DRAW) Log.v(mTag, "invalidateRectOnScreen: " + dirty); 2551 final Rect localDirty = mDirty; 2552 2553 // Add the new dirty rect to the current one 2554 localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom); 2555 // Intersect with the bounds of the window to skip 2556 // updates that lie outside of the visible region 2557 final float appScale = mAttachInfo.mApplicationScale; 2558 final boolean intersected = localDirty.intersect(0, 0, 2559 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f)); 2560 if (!intersected) { 2561 localDirty.setEmpty(); 2562 } 2563 if (!mWillDrawSoon && (intersected || mIsAnimating)) { 2564 scheduleTraversals(); 2565 } 2566 } 2567 setIsAmbientMode(boolean ambient)2568 public void setIsAmbientMode(boolean ambient) { 2569 mIsAmbientMode = ambient; 2570 } 2571 setWindowStopped(boolean stopped)2572 void setWindowStopped(boolean stopped) { 2573 checkThread(); 2574 if (mStopped != stopped) { 2575 mStopped = stopped; 2576 final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer; 2577 if (renderer != null) { 2578 if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped); 2579 renderer.setStopped(mStopped); 2580 } 2581 if (!mStopped) { 2582 // Make sure that relayoutWindow will be called to get valid surface because 2583 // the previous surface may have been released. 2584 mAppVisibilityChanged = true; 2585 scheduleTraversals(); 2586 } else { 2587 if (renderer != null) { 2588 renderer.destroyHardwareResources(mView); 2589 } 2590 2591 if (mSurface.isValid()) { 2592 if (mSurfaceHolder != null) { 2593 notifyHolderSurfaceDestroyed(); 2594 } 2595 notifySurfaceDestroyed(); 2596 } 2597 destroySurface(); 2598 2599 // Reset so they can be sent again for warm starts. 2600 mAppStartTimestampsSent = false; 2601 mAppStartTrackingStarted = false; 2602 mRenderThreadDrawStartTimeNs = -1; 2603 mFirstFramePresentedTimeNs = -1; 2604 } 2605 } 2606 } 2607 2608 2609 /** Register callbacks to be notified when the ViewRootImpl surface changes. */ 2610 public interface SurfaceChangedCallback { surfaceCreated(Transaction t)2611 void surfaceCreated(Transaction t); surfaceReplaced(Transaction t)2612 void surfaceReplaced(Transaction t); surfaceDestroyed()2613 void surfaceDestroyed(); vriDrawStarted(boolean isWmSync)2614 default void vriDrawStarted(boolean isWmSync) {}; 2615 } 2616 2617 private final ArrayList<SurfaceChangedCallback> mSurfaceChangedCallbacks = new ArrayList<>(); addSurfaceChangedCallback(SurfaceChangedCallback c)2618 public void addSurfaceChangedCallback(SurfaceChangedCallback c) { 2619 mSurfaceChangedCallbacks.add(c); 2620 } 2621 removeSurfaceChangedCallback(SurfaceChangedCallback c)2622 public void removeSurfaceChangedCallback(SurfaceChangedCallback c) { 2623 mSurfaceChangedCallbacks.remove(c); 2624 } 2625 notifySurfaceCreated(Transaction t)2626 private void notifySurfaceCreated(Transaction t) { 2627 for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) { 2628 mSurfaceChangedCallbacks.get(i).surfaceCreated(t); 2629 } 2630 } 2631 2632 /** 2633 * Notify listeners when the ViewRootImpl surface has been replaced. This callback will not be 2634 * called if a new surface is created, only if the valid surface has been replaced with another 2635 * valid surface. 2636 */ notifySurfaceReplaced(Transaction t)2637 private void notifySurfaceReplaced(Transaction t) { 2638 for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) { 2639 mSurfaceChangedCallbacks.get(i).surfaceReplaced(t); 2640 } 2641 } 2642 notifySurfaceDestroyed()2643 private void notifySurfaceDestroyed() { 2644 for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) { 2645 mSurfaceChangedCallbacks.get(i).surfaceDestroyed(); 2646 } 2647 } 2648 notifyDrawStarted(boolean isWmSync)2649 private void notifyDrawStarted(boolean isWmSync) { 2650 for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) { 2651 mSurfaceChangedCallbacks.get(i).vriDrawStarted(isWmSync); 2652 } 2653 } 2654 2655 /** 2656 * @return child layer with the same bounds as its parent {@code mSurface} and cropped to the 2657 * surface insets. If the layer does not exist, it is created. 2658 * 2659 * <p>Parenting to this layer will ensure that its children are cropped by the view's surface 2660 * insets. 2661 */ updateAndGetBoundsLayer(Transaction t)2662 public SurfaceControl updateAndGetBoundsLayer(Transaction t) { 2663 if (mBoundsLayer == null) { 2664 mBoundsLayer = new SurfaceControl.Builder(mSurfaceSession) 2665 .setContainerLayer() 2666 .setName("Bounds for - " + getTitle().toString()) 2667 .setParent(getSurfaceControl()) 2668 .setCallsite("ViewRootImpl.getBoundsLayer") 2669 .build(); 2670 setBoundsLayerCrop(t); 2671 t.show(mBoundsLayer); 2672 } 2673 return mBoundsLayer; 2674 } 2675 updateBlastSurfaceIfNeeded()2676 void updateBlastSurfaceIfNeeded() { 2677 if (!mSurfaceControl.isValid()) { 2678 return; 2679 } 2680 2681 if (mBlastBufferQueue != null && mBlastBufferQueue.isSameSurfaceControl(mSurfaceControl)) { 2682 mBlastBufferQueue.update(mSurfaceControl, 2683 mSurfaceSize.x, mSurfaceSize.y, 2684 mWindowAttributes.format); 2685 return; 2686 } 2687 2688 // If the SurfaceControl has been updated, destroy and recreate the BBQ to reset the BQ and 2689 // BBQ states. 2690 if (mBlastBufferQueue != null) { 2691 mBlastBufferQueue.destroy(); 2692 } 2693 mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl, 2694 mSurfaceSize.x, mSurfaceSize.y, mWindowAttributes.format); 2695 mBlastBufferQueue.setTransactionHangCallback(sTransactionHangCallback); 2696 Surface blastSurface; 2697 if (addSchandleToVriSurface()) { 2698 blastSurface = mBlastBufferQueue.createSurfaceWithHandle(); 2699 } else { 2700 blastSurface = mBlastBufferQueue.createSurface(); 2701 } 2702 // Only call transferFrom if the surface has changed to prevent inc the generation ID and 2703 // causing EGL resources to be recreated. 2704 mSurface.transferFrom(blastSurface); 2705 } 2706 setBoundsLayerCrop(Transaction t)2707 private void setBoundsLayerCrop(Transaction t) { 2708 // Adjust of insets and update the bounds layer so child surfaces do not draw into 2709 // the surface inset region. 2710 mTempRect.set(0, 0, mSurfaceSize.x, mSurfaceSize.y); 2711 mTempRect.inset(mWindowAttributes.surfaceInsets.left, 2712 mWindowAttributes.surfaceInsets.top, 2713 mWindowAttributes.surfaceInsets.right, mWindowAttributes.surfaceInsets.bottom); 2714 mTempRect.inset(mChildBoundingInsets.left, mChildBoundingInsets.top, 2715 mChildBoundingInsets.right, mChildBoundingInsets.bottom); 2716 t.setWindowCrop(mBoundsLayer, mTempRect); 2717 } 2718 2719 /** 2720 * Called after window layout to update the bounds surface. If the surface insets have changed 2721 * or the surface has resized, update the bounds surface. 2722 */ updateBoundsLayer(SurfaceControl.Transaction t)2723 private boolean updateBoundsLayer(SurfaceControl.Transaction t) { 2724 if (mBoundsLayer != null) { 2725 setBoundsLayerCrop(t); 2726 return true; 2727 } 2728 return false; 2729 } 2730 prepareSurfaces()2731 private void prepareSurfaces() { 2732 final SurfaceControl.Transaction t = mTransaction; 2733 final SurfaceControl sc = getSurfaceControl(); 2734 if (!sc.isValid()) return; 2735 2736 if (updateBoundsLayer(t)) { 2737 applyTransactionOnDraw(t); 2738 } 2739 2740 // Set the frame rate selection strategy to FRAME_RATE_SELECTION_STRATEGY_SELF 2741 // This strategy ensures that the frame rate specifications do not cascade down to 2742 // the descendant layers. This is particularly important for applications like Chrome, 2743 // where child surfaces should adhere to default behavior instead of no preference. 2744 // This issue only happens when ViewRootImpl calls setFrameRateCategory. This is 2745 // no longer needed if the dVRR feature is disabled. 2746 if (shouldEnableDvrr()) { 2747 try { 2748 if (sToolkitFrameRateFunctionEnablingReadOnlyFlagValue) { 2749 mFrameRateTransaction.setFrameRateSelectionStrategy(sc, 2750 sc.FRAME_RATE_SELECTION_STRATEGY_SELF).applyAsyncUnsafe(); 2751 } 2752 } catch (Exception e) { 2753 Log.e(mTag, "Unable to set frame rate selection strategy ", e); 2754 } 2755 } 2756 } 2757 destroySurface()2758 private void destroySurface() { 2759 if (mBoundsLayer != null) { 2760 mBoundsLayer.release(); 2761 mBoundsLayer = null; 2762 } 2763 mSurface.release(); 2764 mSurfaceControl.release(); 2765 2766 if (mBlastBufferQueue != null) { 2767 mBlastBufferQueue.destroy(); 2768 mBlastBufferQueue = null; 2769 } 2770 2771 if (mAttachInfo.mThreadedRenderer != null) { 2772 mAttachInfo.mThreadedRenderer.setSurfaceControl(null, null); 2773 } 2774 } 2775 2776 /** 2777 * Block the input events during an Activity Transition. The KEYCODE_BACK event is allowed 2778 * through to allow quick reversal of the Activity Transition. 2779 * 2780 * @param paused true to pause, false to resume. 2781 */ setPausedForTransition(boolean paused)2782 public void setPausedForTransition(boolean paused) { 2783 mPausedForTransition = paused; 2784 } 2785 2786 @Override getParent()2787 public ViewParent getParent() { 2788 return null; 2789 } 2790 2791 @Override getChildVisibleRect(View child, Rect r, android.graphics.Point offset)2792 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) { 2793 if (child != mView) { 2794 throw new RuntimeException("child is not mine, honest!"); 2795 } 2796 // Note: don't apply scroll offset, because we want to know its 2797 // visibility in the virtual canvas being given to the view hierarchy. 2798 return r.intersect(0, 0, mWidth, mHeight); 2799 } 2800 2801 @Override getChildLocalHitRegion(@onNull View child, @NonNull Region region, @NonNull Matrix matrix, boolean isHover)2802 public boolean getChildLocalHitRegion(@NonNull View child, @NonNull Region region, 2803 @NonNull Matrix matrix, boolean isHover) { 2804 if (child != mView) { 2805 throw new IllegalArgumentException("child " + child + " is not the root view " 2806 + mView + " managed by this ViewRootImpl"); 2807 } 2808 2809 RectF rectF = new RectF(0, 0, mWidth, mHeight); 2810 matrix.mapRect(rectF); 2811 // Note: don't apply scroll offset, because we want to know its 2812 // visibility in the virtual canvas being given to the view hierarchy. 2813 return region.op(Math.round(rectF.left), Math.round(rectF.top), 2814 Math.round(rectF.right), Math.round(rectF.bottom), Region.Op.INTERSECT); 2815 } 2816 2817 @Override bringChildToFront(View child)2818 public void bringChildToFront(View child) { 2819 } 2820 2821 // keep in sync with getHostVisibilityReason getHostVisibility()2822 int getHostVisibility() { 2823 return mView != null && (mAppVisible || mForceDecorViewVisibility) 2824 ? mView.getVisibility() : View.GONE; 2825 } 2826 getHostVisibilityReason()2827 String getHostVisibilityReason() { 2828 if (mView == null) { 2829 return "mView is null"; 2830 } 2831 if (!mAppVisible && !mForceDecorViewVisibility) { 2832 return "!mAppVisible && !mForceDecorViewVisibility"; 2833 } 2834 switch (mView.getVisibility()) { 2835 case View.VISIBLE: return "View.VISIBLE"; 2836 case View.GONE: return "View.GONE"; 2837 case View.INVISIBLE: return "View.INVISIBLE"; 2838 default: return ""; 2839 } 2840 } 2841 2842 /** 2843 * Add LayoutTransition to the list of transitions to be started in the next traversal. 2844 * This list will be cleared after the transitions on the list are start()'ed. These 2845 * transitionsa re added by LayoutTransition itself when it sets up animations. The setup 2846 * happens during the layout phase of traversal, which we want to complete before any of the 2847 * animations are started (because those animations may side-effect properties that layout 2848 * depends upon, like the bounding rectangles of the affected views). So we add the transition 2849 * to the list and it is started just prior to starting the drawing phase of traversal. 2850 * 2851 * @param transition The LayoutTransition to be started on the next traversal. 2852 * 2853 * @hide 2854 */ requestTransitionStart(LayoutTransition transition)2855 public void requestTransitionStart(LayoutTransition transition) { 2856 if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) { 2857 if (mPendingTransitions == null) { 2858 mPendingTransitions = new ArrayList<LayoutTransition>(); 2859 } 2860 mPendingTransitions.add(transition); 2861 } 2862 } 2863 2864 /** 2865 * Notifies the HardwareRenderer that a new frame will be coming soon. 2866 * Currently only {@link ThreadedRenderer} cares about this, and uses 2867 * this knowledge to adjust the scheduling of off-thread animations 2868 */ notifyRendererOfFramePending()2869 void notifyRendererOfFramePending() { 2870 if (mAttachInfo.mThreadedRenderer != null) { 2871 mAttachInfo.mThreadedRenderer.notifyFramePending(); 2872 } 2873 } 2874 2875 /** 2876 * Notifies the HardwareRenderer of an expensive upcoming frame, to 2877 * allow better handling of power and scheduling requirements. 2878 * 2879 * @hide 2880 */ notifyRendererOfExpensiveFrame()2881 public void notifyRendererOfExpensiveFrame() { 2882 if (mAttachInfo.mThreadedRenderer != null) { 2883 mAttachInfo.mThreadedRenderer.notifyExpensiveFrame(); 2884 } 2885 } 2886 2887 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) scheduleTraversals()2888 void scheduleTraversals() { 2889 if (!mTraversalScheduled) { 2890 mTraversalScheduled = true; 2891 mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); 2892 mChoreographer.postCallback( 2893 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); 2894 notifyRendererOfFramePending(); 2895 pokeDrawLockIfNeeded(); 2896 } 2897 } 2898 unscheduleTraversals()2899 void unscheduleTraversals() { 2900 if (mTraversalScheduled) { 2901 mTraversalScheduled = false; 2902 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); 2903 mChoreographer.removeCallbacks( 2904 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); 2905 } 2906 } 2907 doTraversal()2908 void doTraversal() { 2909 if (mTraversalScheduled) { 2910 mTraversalScheduled = false; 2911 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); 2912 2913 if (mProfile) { 2914 Debug.startMethodTracing("ViewAncestor"); 2915 } 2916 2917 performTraversals(); 2918 2919 if (mProfile) { 2920 Debug.stopMethodTracing(); 2921 mProfile = false; 2922 } 2923 } 2924 } 2925 applyKeepScreenOnFlag(WindowManager.LayoutParams params)2926 private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) { 2927 // Update window's global keep screen on flag: if a view has requested 2928 // that the screen be kept on, then it is always set; otherwise, it is 2929 // set to whatever the client last requested for the global state. 2930 if (mAttachInfo.mKeepScreenOn) { 2931 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; 2932 } else { 2933 params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) 2934 | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 2935 } 2936 } 2937 collectViewAttributes()2938 private boolean collectViewAttributes() { 2939 if (mAttachInfo.mRecomputeGlobalAttributes) { 2940 //Log.i(mTag, "Computing view hierarchy attributes!"); 2941 mAttachInfo.mRecomputeGlobalAttributes = false; 2942 boolean oldScreenOn = mAttachInfo.mKeepScreenOn; 2943 mAttachInfo.mKeepScreenOn = false; 2944 mAttachInfo.mSystemUiVisibility = 0; 2945 mAttachInfo.mHasSystemUiListeners = false; 2946 mView.dispatchCollectViewAttributes(mAttachInfo, 0); 2947 mAttachInfo.mSystemUiVisibility &= ~mAttachInfo.mDisabledSystemUiVisibility; 2948 WindowManager.LayoutParams params = mWindowAttributes; 2949 mAttachInfo.mSystemUiVisibility |= getImpliedSystemUiVisibility(params); 2950 mCompatibleVisibilityInfo.globalVisibility = 2951 (mCompatibleVisibilityInfo.globalVisibility & ~View.SYSTEM_UI_FLAG_LOW_PROFILE) 2952 | (mAttachInfo.mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE); 2953 dispatchDispatchSystemUiVisibilityChanged(); 2954 if (mAttachInfo.mKeepScreenOn != oldScreenOn 2955 || mAttachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility 2956 || mAttachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) { 2957 applyKeepScreenOnFlag(params); 2958 params.subtreeSystemUiVisibility = mAttachInfo.mSystemUiVisibility; 2959 params.hasSystemUiListeners = mAttachInfo.mHasSystemUiListeners; 2960 mView.dispatchWindowSystemUiVisiblityChanged(mAttachInfo.mSystemUiVisibility); 2961 return true; 2962 } 2963 } 2964 return false; 2965 } 2966 getImpliedSystemUiVisibility(WindowManager.LayoutParams params)2967 private int getImpliedSystemUiVisibility(WindowManager.LayoutParams params) { 2968 int vis = 0; 2969 // Translucent decor window flags imply stable system ui visibility. 2970 if ((params.flags & FLAG_TRANSLUCENT_STATUS) != 0) { 2971 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 2972 } 2973 if ((params.flags & FLAG_TRANSLUCENT_NAVIGATION) != 0) { 2974 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; 2975 } 2976 return vis; 2977 } 2978 2979 /** 2980 * Update the compatible system UI visibility for dispatching it to the legacy app. 2981 */ updateCompatSysUiVisibility(@nsetsType int visibleTypes, @InsetsType int requestedVisibleTypes, @InsetsType int controllableTypes)2982 void updateCompatSysUiVisibility(@InsetsType int visibleTypes, 2983 @InsetsType int requestedVisibleTypes, @InsetsType int controllableTypes) { 2984 // If a type is controllable, the visibility is overridden by the requested visibility. 2985 visibleTypes = 2986 (requestedVisibleTypes & controllableTypes) | (visibleTypes & ~controllableTypes); 2987 2988 updateCompatSystemUiVisibilityInfo(SYSTEM_UI_FLAG_FULLSCREEN, Type.statusBars(), 2989 visibleTypes, controllableTypes); 2990 updateCompatSystemUiVisibilityInfo(SYSTEM_UI_FLAG_HIDE_NAVIGATION, Type.navigationBars(), 2991 visibleTypes, controllableTypes); 2992 dispatchDispatchSystemUiVisibilityChanged(); 2993 } 2994 updateCompatSystemUiVisibilityInfo(int systemUiFlag, @InsetsType int insetsType, @InsetsType int visibleTypes, @InsetsType int controllableTypes)2995 private void updateCompatSystemUiVisibilityInfo(int systemUiFlag, @InsetsType int insetsType, 2996 @InsetsType int visibleTypes, @InsetsType int controllableTypes) { 2997 final SystemUiVisibilityInfo info = mCompatibleVisibilityInfo; 2998 final boolean willBeVisible = (visibleTypes & insetsType) != 0; 2999 final boolean hasControl = (controllableTypes & insetsType) != 0; 3000 final boolean wasInvisible = (mAttachInfo.mSystemUiVisibility & systemUiFlag) != 0; 3001 if (willBeVisible) { 3002 info.globalVisibility &= ~systemUiFlag; 3003 if (hasControl && wasInvisible) { 3004 // The local system UI visibility can only be cleared while we have the control. 3005 info.localChanges |= systemUiFlag; 3006 } 3007 } else { 3008 info.globalVisibility |= systemUiFlag; 3009 info.localChanges &= ~systemUiFlag; 3010 } 3011 } 3012 3013 /** 3014 * If the system is forcing showing any system bar, the legacy low profile flag should be 3015 * cleared for compatibility. 3016 * 3017 * @param showTypes {@link InsetsType types} shown by the system. 3018 * @param fromIme {@code true} if the invocation is from IME. 3019 */ clearLowProfileModeIfNeeded(@nsetsType int showTypes, boolean fromIme)3020 private void clearLowProfileModeIfNeeded(@InsetsType int showTypes, boolean fromIme) { 3021 final SystemUiVisibilityInfo info = mCompatibleVisibilityInfo; 3022 if ((showTypes & Type.systemBars()) != 0 && !fromIme 3023 && (info.globalVisibility & SYSTEM_UI_FLAG_LOW_PROFILE) != 0) { 3024 info.globalVisibility &= ~SYSTEM_UI_FLAG_LOW_PROFILE; 3025 info.localChanges |= SYSTEM_UI_FLAG_LOW_PROFILE; 3026 dispatchDispatchSystemUiVisibilityChanged(); 3027 } 3028 } 3029 dispatchDispatchSystemUiVisibilityChanged()3030 private void dispatchDispatchSystemUiVisibilityChanged() { 3031 if (mDispatchedSystemUiVisibility != mCompatibleVisibilityInfo.globalVisibility) { 3032 mHandler.removeMessages(MSG_DISPATCH_SYSTEM_UI_VISIBILITY); 3033 mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY)); 3034 } 3035 } 3036 handleDispatchSystemUiVisibilityChanged()3037 private void handleDispatchSystemUiVisibilityChanged() { 3038 if (mView == null) { 3039 return; 3040 } 3041 final SystemUiVisibilityInfo info = mCompatibleVisibilityInfo; 3042 if (info.localChanges != 0) { 3043 mView.updateLocalSystemUiVisibility(info.localValue, info.localChanges); 3044 info.localChanges = 0; 3045 } 3046 3047 final int visibility = info.globalVisibility & View.SYSTEM_UI_CLEARABLE_FLAGS; 3048 if (mDispatchedSystemUiVisibility != visibility) { 3049 mDispatchedSystemUiVisibility = visibility; 3050 mView.dispatchSystemUiVisibilityChanged(visibility); 3051 } 3052 } 3053 3054 @VisibleForTesting adjustLayoutParamsForCompatibility(WindowManager.LayoutParams inOutParams, @Appearance int appearanceControlled, boolean behaviorControlled)3055 public static void adjustLayoutParamsForCompatibility(WindowManager.LayoutParams inOutParams, 3056 @Appearance int appearanceControlled, boolean behaviorControlled) { 3057 final int sysUiVis = inOutParams.systemUiVisibility | inOutParams.subtreeSystemUiVisibility; 3058 final int flags = inOutParams.flags; 3059 final int type = inOutParams.type; 3060 final int adjust = inOutParams.softInputMode & SOFT_INPUT_MASK_ADJUST; 3061 3062 @Appearance int appearance = inOutParams.insetsFlags.appearance; 3063 if ((appearanceControlled & APPEARANCE_LOW_PROFILE_BARS) == 0) { 3064 appearance &= ~APPEARANCE_LOW_PROFILE_BARS; 3065 appearance |= (sysUiVis & SYSTEM_UI_FLAG_LOW_PROFILE) != 0 3066 ? APPEARANCE_LOW_PROFILE_BARS 3067 : 0; 3068 } 3069 if ((appearanceControlled & APPEARANCE_LIGHT_STATUS_BARS) == 0) { 3070 appearance &= ~APPEARANCE_LIGHT_STATUS_BARS; 3071 appearance |= (sysUiVis & SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0 3072 ? APPEARANCE_LIGHT_STATUS_BARS 3073 : 0; 3074 } 3075 if ((appearanceControlled & APPEARANCE_LIGHT_NAVIGATION_BARS) == 0) { 3076 appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS; 3077 appearance |= (sysUiVis & SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0 3078 ? APPEARANCE_LIGHT_NAVIGATION_BARS 3079 : 0; 3080 } 3081 inOutParams.insetsFlags.appearance = appearance; 3082 3083 if (!behaviorControlled) { 3084 if ((sysUiVis & SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0 3085 || (flags & FLAG_FULLSCREEN) != 0) { 3086 inOutParams.insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; 3087 } else { 3088 inOutParams.insetsFlags.behavior = BEHAVIOR_DEFAULT; 3089 } 3090 } 3091 3092 inOutParams.privateFlags &= ~PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME; 3093 3094 if ((inOutParams.privateFlags & PRIVATE_FLAG_FIT_INSETS_CONTROLLED) != 0) { 3095 return; 3096 } 3097 3098 int types = inOutParams.getFitInsetsTypes(); 3099 boolean ignoreVis = inOutParams.isFitInsetsIgnoringVisibility(); 3100 3101 if (((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0 3102 || (flags & FLAG_LAYOUT_IN_SCREEN) != 0) 3103 || (flags & FLAG_TRANSLUCENT_STATUS) != 0) { 3104 types &= ~Type.statusBars(); 3105 } 3106 if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0 3107 || (flags & FLAG_TRANSLUCENT_NAVIGATION) != 0) { 3108 types &= ~Type.systemBars(); 3109 } 3110 if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) { 3111 ignoreVis = true; 3112 } else if ((types & Type.systemBars()) == Type.systemBars()) { 3113 if (adjust == SOFT_INPUT_ADJUST_RESIZE) { 3114 types |= Type.ime(); 3115 } else { 3116 inOutParams.privateFlags |= PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME; 3117 } 3118 } 3119 inOutParams.setFitInsetsTypes(types); 3120 inOutParams.setFitInsetsIgnoringVisibility(ignoreVis); 3121 3122 // The fitting of insets are not really controlled by the clients, so we remove the flag. 3123 inOutParams.privateFlags &= ~PRIVATE_FLAG_FIT_INSETS_CONTROLLED; 3124 } 3125 controlInsetsForCompatibility(WindowManager.LayoutParams params)3126 private void controlInsetsForCompatibility(WindowManager.LayoutParams params) { 3127 final int sysUiVis = params.systemUiVisibility | params.subtreeSystemUiVisibility; 3128 final int flags = params.flags; 3129 final boolean matchParent = params.width == MATCH_PARENT && params.height == MATCH_PARENT; 3130 final boolean nonAttachedAppWindow = params.type >= FIRST_APPLICATION_WINDOW 3131 && params.type <= LAST_APPLICATION_WINDOW; 3132 final boolean statusWasHiddenByFlags = (mTypesHiddenByFlags & Type.statusBars()) != 0; 3133 final boolean statusIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_FULLSCREEN) != 0 3134 || ((flags & FLAG_FULLSCREEN) != 0 && matchParent && nonAttachedAppWindow); 3135 final boolean navWasHiddenByFlags = (mTypesHiddenByFlags & Type.navigationBars()) != 0; 3136 final boolean navIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0; 3137 3138 @InsetsType int typesToHide = 0; 3139 @InsetsType int typesToShow = 0; 3140 if (statusIsHiddenByFlags && !statusWasHiddenByFlags) { 3141 typesToHide |= Type.statusBars(); 3142 } else if (!statusIsHiddenByFlags && statusWasHiddenByFlags) { 3143 typesToShow |= Type.statusBars(); 3144 } 3145 if (navIsHiddenByFlags && !navWasHiddenByFlags) { 3146 typesToHide |= Type.navigationBars(); 3147 } else if (!navIsHiddenByFlags && navWasHiddenByFlags) { 3148 typesToShow |= Type.navigationBars(); 3149 } 3150 if (typesToHide != 0) { 3151 getInsetsController().hide(typesToHide); 3152 } 3153 if (typesToShow != 0) { 3154 getInsetsController().show(typesToShow); 3155 } 3156 mTypesHiddenByFlags |= typesToHide; 3157 mTypesHiddenByFlags &= ~typesToShow; 3158 } 3159 measureHierarchy(final View host, final WindowManager.LayoutParams lp, final Resources res, final int desiredWindowWidth, final int desiredWindowHeight, boolean forRootSizeOnly)3160 private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp, 3161 final Resources res, final int desiredWindowWidth, final int desiredWindowHeight, 3162 boolean forRootSizeOnly) { 3163 int childWidthMeasureSpec; 3164 int childHeightMeasureSpec; 3165 boolean windowSizeMayChange = false; 3166 3167 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(mTag, 3168 "Measuring " + host + " in display " + desiredWindowWidth 3169 + "x" + desiredWindowHeight + "..."); 3170 3171 boolean goodMeasure = false; 3172 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) { 3173 // On large screens, we don't want to allow dialogs to just 3174 // stretch to fill the entire width of the screen to display 3175 // one line of text. First try doing the layout at a smaller 3176 // size to see if it will fit. 3177 final DisplayMetrics packageMetrics = res.getDisplayMetrics(); 3178 res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true); 3179 int baseSize = 0; 3180 if (mTmpValue.type == TypedValue.TYPE_DIMENSION) { 3181 baseSize = (int)mTmpValue.getDimension(packageMetrics); 3182 } 3183 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": baseSize=" + baseSize 3184 + ", desiredWindowWidth=" + desiredWindowWidth); 3185 if (baseSize != 0 && desiredWindowWidth > baseSize) { 3186 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width, lp.privateFlags); 3187 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height, 3188 lp.privateFlags); 3189 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 3190 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured (" 3191 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() 3192 + ") from width spec: " + MeasureSpec.toString(childWidthMeasureSpec) 3193 + " and height spec: " + MeasureSpec.toString(childHeightMeasureSpec)); 3194 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) { 3195 goodMeasure = true; 3196 } else { 3197 // Didn't fit in that size... try expanding a bit. 3198 baseSize = (baseSize+desiredWindowWidth)/2; 3199 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": next baseSize=" 3200 + baseSize); 3201 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width, lp.privateFlags); 3202 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 3203 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured (" 3204 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")"); 3205 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) { 3206 if (DEBUG_DIALOG) Log.v(mTag, "Good!"); 3207 goodMeasure = true; 3208 } 3209 } 3210 } 3211 } 3212 3213 if (!goodMeasure) { 3214 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width, 3215 lp.privateFlags); 3216 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height, 3217 lp.privateFlags); 3218 if (!forRootSizeOnly || !setMeasuredRootSizeFromSpec( 3219 childWidthMeasureSpec, childHeightMeasureSpec)) { 3220 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 3221 } else { 3222 // We already know how big the window should be before measuring the views. 3223 // We can measure the views before laying out them. This is to avoid unnecessary 3224 // measure. 3225 mViewMeasureDeferred = true; 3226 } 3227 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) { 3228 windowSizeMayChange = true; 3229 } 3230 } 3231 3232 if (DBG) { 3233 System.out.println("======================================"); 3234 System.out.println("performTraversals -- after measure"); 3235 host.debug(); 3236 } 3237 3238 return windowSizeMayChange; 3239 } 3240 3241 /** 3242 * Sets the measured root size for requesting the window frame. 3243 * 3244 * @param widthMeasureSpec contains the size and the mode of the width. 3245 * @param heightMeasureSpec contains the size and the mode of the height. 3246 * @return {@code true} if we actually set the measured size; {@code false} otherwise. 3247 */ setMeasuredRootSizeFromSpec(int widthMeasureSpec, int heightMeasureSpec)3248 private boolean setMeasuredRootSizeFromSpec(int widthMeasureSpec, int heightMeasureSpec) { 3249 final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 3250 final int heightMode = MeasureSpec.getMode(heightMeasureSpec); 3251 if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) { 3252 // We don't know the exact size. We need to measure the hierarchy to know that. 3253 return false; 3254 } 3255 mMeasuredWidth = MeasureSpec.getSize(widthMeasureSpec); 3256 mMeasuredHeight = MeasureSpec.getSize(heightMeasureSpec); 3257 return true; 3258 } 3259 3260 /** 3261 * Modifies the input matrix such that it maps view-local coordinates to 3262 * on-screen coordinates. 3263 * 3264 * @param m input matrix to modify 3265 */ transformMatrixToGlobal(Matrix m)3266 void transformMatrixToGlobal(Matrix m) { 3267 m.preTranslate(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 3268 } 3269 3270 /** 3271 * Modifies the input matrix such that it maps on-screen coordinates to 3272 * view-local coordinates. 3273 * 3274 * @param m input matrix to modify 3275 */ transformMatrixToLocal(Matrix m)3276 void transformMatrixToLocal(Matrix m) { 3277 m.postTranslate(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop); 3278 } 3279 getWindowInsets(boolean forceConstruct)3280 /* package */ WindowInsets getWindowInsets(boolean forceConstruct) { 3281 if (mLastWindowInsets == null || forceConstruct) { 3282 final Configuration config = getConfiguration(); 3283 mLastWindowInsets = mInsetsController.calculateInsets( 3284 config.isScreenRound(), mWindowAttributes.type, 3285 config.windowConfiguration.getActivityType(), mWindowAttributes.softInputMode, 3286 mWindowAttributes.flags, (mWindowAttributes.systemUiVisibility 3287 | mWindowAttributes.subtreeSystemUiVisibility)); 3288 3289 mAttachInfo.mContentInsets.set(mLastWindowInsets.getSystemWindowInsets().toRect()); 3290 mAttachInfo.mStableInsets.set(mLastWindowInsets.getStableInsets().toRect()); 3291 mAttachInfo.mVisibleInsets.set(mInsetsController.calculateVisibleInsets( 3292 mWindowAttributes.type, config.windowConfiguration.getActivityType(), 3293 mWindowAttributes.softInputMode, mWindowAttributes.flags).toRect()); 3294 } 3295 return mLastWindowInsets; 3296 } 3297 dispatchApplyInsets(View host)3298 public void dispatchApplyInsets(View host) { 3299 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchApplyInsets"); 3300 mApplyInsetsRequested = false; 3301 WindowInsets insets = getWindowInsets(true /* forceConstruct */); 3302 if (!shouldDispatchCutout()) { 3303 // Window is either not laid out in cutout or the status bar inset takes care of 3304 // clearing the cutout, so we don't need to dispatch the cutout to the hierarchy. 3305 insets = insets.consumeDisplayCutout(); 3306 } 3307 host.dispatchApplyWindowInsets(insets); 3308 mAttachInfo.delayNotifyContentCaptureInsetsEvent(insets.getInsets(Type.all())); 3309 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 3310 } 3311 shouldDispatchCutout()3312 private boolean shouldDispatchCutout() { 3313 return mWindowAttributes.layoutInDisplayCutoutMode 3314 == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS 3315 || mWindowAttributes.layoutInDisplayCutoutMode 3316 == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; 3317 } 3318 getInsetsController()3319 public InsetsController getInsetsController() { 3320 return mInsetsController; 3321 } 3322 shouldUseDisplaySize(final WindowManager.LayoutParams lp)3323 private static boolean shouldUseDisplaySize(final WindowManager.LayoutParams lp) { 3324 return lp.type == TYPE_STATUS_BAR_ADDITIONAL 3325 || lp.type == TYPE_INPUT_METHOD 3326 || lp.type == TYPE_VOLUME_OVERLAY; 3327 } 3328 3329 /** 3330 * @return {@code true} if we should reduce unnecessary measure for the window. 3331 * TODO(b/260382739): Apply this to all windows. 3332 */ shouldOptimizeMeasure(final WindowManager.LayoutParams lp)3333 private static boolean shouldOptimizeMeasure(final WindowManager.LayoutParams lp) { 3334 return (lp.privateFlags & PRIVATE_FLAG_OPTIMIZE_MEASURE) != 0; 3335 } 3336 getWindowBoundsInsetSystemBars()3337 private Rect getWindowBoundsInsetSystemBars() { 3338 final Rect bounds = new Rect( 3339 mContext.getResources().getConfiguration().windowConfiguration.getBounds()); 3340 bounds.inset(mInsetsController.getState().calculateInsets( 3341 bounds, Type.systemBars(), false /* ignoreVisibility */)); 3342 return bounds; 3343 } 3344 dipToPx(int dip)3345 int dipToPx(int dip) { 3346 final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics(); 3347 return (int) (displayMetrics.density * dip + 0.5f); 3348 } 3349 performTraversals()3350 private void performTraversals() { 3351 mLastPerformTraversalsSkipDrawReason = null; 3352 3353 // cache mView since it is used so much below... 3354 final View host = mView; 3355 if (DBG) { 3356 System.out.println("======================================"); 3357 System.out.println("performTraversals"); 3358 host.debug(); 3359 } 3360 3361 if (host == null || !mAdded) { 3362 mLastPerformTraversalsSkipDrawReason = host == null ? "no_host" : "not_added"; 3363 return; 3364 } 3365 3366 if (mNumPausedForSync > 0) { 3367 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 3368 Trace.instant(Trace.TRACE_TAG_VIEW, 3369 TextUtils.formatSimple("performTraversals#mNumPausedForSync=%d", 3370 mNumPausedForSync)); 3371 } 3372 if (DEBUG_BLAST) { 3373 Log.d(mTag, "Skipping traversal due to sync " + mNumPausedForSync); 3374 } 3375 mLastPerformTraversalsSkipDrawReason = "paused_for_sync"; 3376 return; 3377 } 3378 3379 mIsInTraversal = true; 3380 mWillDrawSoon = true; 3381 boolean cancelDraw = false; 3382 String cancelReason = null; 3383 boolean isSyncRequest = false; 3384 3385 boolean windowSizeMayChange = false; 3386 WindowManager.LayoutParams lp = mWindowAttributes; 3387 3388 int desiredWindowWidth; 3389 int desiredWindowHeight; 3390 3391 final int viewVisibility = getHostVisibility(); 3392 final String viewVisibilityReason = getHostVisibilityReason(); 3393 final boolean viewVisibilityChanged = !mFirst 3394 && (mViewVisibility != viewVisibility || mNewSurfaceNeeded 3395 // Also check for possible double visibility update, which will make current 3396 // viewVisibility value equal to mViewVisibility and we may miss it. 3397 || mAppVisibilityChanged); 3398 mAppVisibilityChanged = false; 3399 final boolean viewUserVisibilityChanged = !mFirst && 3400 ((mViewVisibility == View.VISIBLE) != (viewVisibility == View.VISIBLE)); 3401 final boolean shouldOptimizeMeasure = shouldOptimizeMeasure(lp); 3402 3403 WindowManager.LayoutParams params = null; 3404 Rect frame = mWinFrame; 3405 if (mFirst) { 3406 mFullRedrawNeeded = true; 3407 mLayoutRequested = true; 3408 3409 final Configuration config = getConfiguration(); 3410 if (shouldUseDisplaySize(lp)) { 3411 // NOTE -- system code, won't try to do compat mode. 3412 Point size = new Point(); 3413 mDisplay.getRealSize(size); 3414 desiredWindowWidth = size.x; 3415 desiredWindowHeight = size.y; 3416 } else if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT 3417 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) { 3418 // For wrap content, we have to remeasure later on anyways. Use size consistent with 3419 // below so we get best use of the measure cache. 3420 final Rect bounds = getWindowBoundsInsetSystemBars(); 3421 desiredWindowWidth = bounds.width(); 3422 desiredWindowHeight = bounds.height(); 3423 } else { 3424 // After addToDisplay, the frame contains the frameHint from window manager, which 3425 // for most windows is going to be the same size as the result of relayoutWindow. 3426 // Using this here allows us to avoid remeasuring after relayoutWindow 3427 desiredWindowWidth = frame.width(); 3428 desiredWindowHeight = frame.height(); 3429 } 3430 3431 // We used to use the following condition to choose 32 bits drawing caches: 3432 // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888 3433 // However, windows are now always 32 bits by default, so choose 32 bits 3434 mAttachInfo.mUse32BitDrawingCache = true; 3435 mAttachInfo.mWindowVisibility = viewVisibility; 3436 mAttachInfo.mRecomputeGlobalAttributes = false; 3437 mLastConfigurationFromResources.setTo(config); 3438 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility; 3439 // Set the layout direction if it has not been set before (inherit is the default) 3440 if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) { 3441 host.setLayoutDirection(config.getLayoutDirection()); 3442 } 3443 host.dispatchAttachedToWindow(mAttachInfo, 0); 3444 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true); 3445 dispatchApplyInsets(host); 3446 if (!mOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled() 3447 // Don't register compat OnBackInvokedCallback for windowless window. 3448 // The onBackInvoked event by default should forward to host app, so the 3449 // host app can decide the behavior. 3450 && mWindowlessBackKeyCallback == null) { 3451 // For apps requesting legacy back behavior, we add a compat callback that 3452 // dispatches {@link KeyEvent#KEYCODE_BACK} to their root views. 3453 // This way from system point of view, these apps are providing custom 3454 // {@link OnBackInvokedCallback}s, and will not play system back animations 3455 // for them. 3456 registerCompatOnBackInvokedCallback(); 3457 } 3458 } else { 3459 desiredWindowWidth = frame.width(); 3460 desiredWindowHeight = frame.height(); 3461 if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) { 3462 if (DEBUG_ORIENTATION) Log.v(mTag, "View " + host + " resized to: " + frame); 3463 mFullRedrawNeeded = true; 3464 mLayoutRequested = true; 3465 windowSizeMayChange = true; 3466 } 3467 } 3468 3469 if (viewVisibilityChanged) { 3470 mAttachInfo.mWindowVisibility = viewVisibility; 3471 host.dispatchWindowVisibilityChanged(viewVisibility); 3472 mAttachInfo.mTreeObserver.dispatchOnWindowVisibilityChange(viewVisibility); 3473 if (viewUserVisibilityChanged) { 3474 host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE); 3475 } 3476 if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) { 3477 endDragResizing(); 3478 destroyHardwareResources(); 3479 } 3480 3481 if (shouldEnableDvrr() && viewVisibility == View.VISIBLE) { 3482 // Boost frame rate when the viewVisibility becomes true. 3483 // This is mainly for lanuchers that lanuch new windows. 3484 boostFrameRate(FRAME_RATE_BOOST_TIME); 3485 } 3486 } 3487 3488 // Non-visible windows can't hold accessibility focus. 3489 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 3490 host.clearAccessibilityFocus(); 3491 } 3492 3493 // Execute enqueued actions on every traversal in case a detached view enqueued an action 3494 getRunQueue().executeActions(mAttachInfo.mHandler); 3495 3496 if (mFirst) { 3497 // make sure touch mode code executes by setting cached value 3498 // to opposite of the added touch mode. 3499 mAttachInfo.mInTouchMode = !mAddedTouchMode; 3500 ensureTouchModeLocally(mAddedTouchMode); 3501 } 3502 3503 boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw); 3504 if (layoutRequested) { 3505 if (!mFirst) { 3506 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT 3507 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) { 3508 windowSizeMayChange = true; 3509 3510 if (shouldUseDisplaySize(lp)) { 3511 // NOTE -- system code, won't try to do compat mode. 3512 Point size = new Point(); 3513 mDisplay.getRealSize(size); 3514 desiredWindowWidth = size.x; 3515 desiredWindowHeight = size.y; 3516 } else { 3517 final Rect bounds = getWindowBoundsInsetSystemBars(); 3518 desiredWindowWidth = bounds.width(); 3519 desiredWindowHeight = bounds.height(); 3520 } 3521 } 3522 } 3523 3524 // Ask host how big it wants to be 3525 windowSizeMayChange |= measureHierarchy(host, lp, mView.getContext().getResources(), 3526 desiredWindowWidth, desiredWindowHeight, shouldOptimizeMeasure); 3527 } 3528 3529 if (collectViewAttributes()) { 3530 params = lp; 3531 } 3532 if (mAttachInfo.mForceReportNewAttributes) { 3533 mAttachInfo.mForceReportNewAttributes = false; 3534 params = lp; 3535 } 3536 3537 if (mFirst || mAttachInfo.mViewVisibilityChanged) { 3538 mAttachInfo.mViewVisibilityChanged = false; 3539 int resizeMode = mSoftInputMode & SOFT_INPUT_MASK_ADJUST; 3540 // If we are in auto resize mode, then we need to determine 3541 // what mode to use now. 3542 if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) { 3543 final int N = mAttachInfo.mScrollContainers.size(); 3544 for (int i=0; i<N; i++) { 3545 if (mAttachInfo.mScrollContainers.get(i).isShown()) { 3546 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; 3547 } 3548 } 3549 if (resizeMode == 0) { 3550 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN; 3551 } 3552 if ((lp.softInputMode & SOFT_INPUT_MASK_ADJUST) != resizeMode) { 3553 lp.softInputMode = (lp.softInputMode & ~SOFT_INPUT_MASK_ADJUST) | resizeMode; 3554 params = lp; 3555 } 3556 } 3557 } 3558 3559 if (mApplyInsetsRequested) { 3560 dispatchApplyInsets(host); 3561 if (mLayoutRequested) { 3562 // Short-circuit catching a new layout request here, so 3563 // we don't need to go through two layout passes when things 3564 // change due to fitting system windows, which can happen a lot. 3565 windowSizeMayChange |= measureHierarchy(host, lp, 3566 mView.getContext().getResources(), desiredWindowWidth, desiredWindowHeight, 3567 shouldOptimizeMeasure); 3568 } 3569 } 3570 3571 if (layoutRequested) { 3572 // Clear this now, so that if anything requests a layout in the 3573 // rest of this function we will catch it and re-run a full 3574 // layout pass. 3575 mLayoutRequested = false; 3576 } 3577 3578 boolean windowShouldResize = layoutRequested && windowSizeMayChange 3579 && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) 3580 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT && 3581 frame.width() < desiredWindowWidth && frame.width() != mWidth) 3582 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT && 3583 frame.height() < desiredWindowHeight && frame.height() != mHeight)); 3584 windowShouldResize |= mDragResizing && mPendingDragResizing; 3585 3586 // Determine whether to compute insets. 3587 // If there are no inset listeners remaining then we may still need to compute 3588 // insets in case the old insets were non-empty and must be reset. 3589 final boolean computesInternalInsets = 3590 mAttachInfo.mTreeObserver.hasComputeInternalInsetsListeners() 3591 || mAttachInfo.mHasNonEmptyGivenInternalInsets; 3592 3593 boolean insetsPending = false; 3594 int relayoutResult = 0; 3595 boolean updatedConfiguration = false; 3596 3597 final int surfaceGenerationId = mSurface.getGenerationId(); 3598 3599 final boolean isViewVisible = viewVisibility == View.VISIBLE; 3600 boolean surfaceSizeChanged = false; 3601 boolean surfaceCreated = false; 3602 boolean surfaceDestroyed = false; 3603 // True if surface generation id changes or relayout result is RELAYOUT_RES_SURFACE_CHANGED. 3604 boolean surfaceReplaced = false; 3605 3606 final boolean windowAttributesChanged = mWindowAttributesChanged; 3607 if (windowAttributesChanged) { 3608 mWindowAttributesChanged = false; 3609 params = lp; 3610 } 3611 3612 if (params != null) { 3613 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0 3614 && !PixelFormat.formatHasAlpha(params.format)) { 3615 params.format = PixelFormat.TRANSLUCENT; 3616 } 3617 adjustLayoutParamsForCompatibility(params, 3618 mInsetsController.getAppearanceControlled(), 3619 mInsetsController.isBehaviorControlled()); 3620 controlInsetsForCompatibility(params); 3621 if (mDispatchedSystemBarAppearance != params.insetsFlags.appearance) { 3622 mDispatchedSystemBarAppearance = params.insetsFlags.appearance; 3623 mView.onSystemBarAppearanceChanged(mDispatchedSystemBarAppearance); 3624 } 3625 } 3626 3627 if (mFirst || windowShouldResize || viewVisibilityChanged || params != null 3628 || mForceNextWindowRelayout) { 3629 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 3630 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 3631 TextUtils.formatSimple("%s-relayoutWindow#" 3632 + "first=%b/resize=%b/vis=%b/params=%b/force=%b", mTag, 3633 mFirst, windowShouldResize, viewVisibilityChanged, params != null, 3634 mForceNextWindowRelayout)); 3635 } 3636 3637 mForceNextWindowRelayout = false; 3638 3639 // If this window is giving internal insets to the window manager, then we want to first 3640 // make the provided insets unchanged during layout. This avoids it briefly causing 3641 // other windows to resize/move based on the raw frame of the window, waiting until we 3642 // can finish laying out this window and get back to the window manager with the 3643 // ultimately computed insets. 3644 insetsPending = computesInternalInsets 3645 // If this window provides insets via params, its insets source frame can be 3646 // updated directly without waiting for WindowSession#setInsets. 3647 && mWindowAttributes.providedInsets == null; 3648 3649 if (mSurfaceHolder != null) { 3650 mSurfaceHolder.mSurfaceLock.lock(); 3651 mDrawingAllowed = true; 3652 } 3653 3654 boolean hwInitialized = false; 3655 boolean dispatchApplyInsets = false; 3656 boolean hadSurface = mSurface.isValid(); 3657 3658 try { 3659 if (DEBUG_LAYOUT) { 3660 Log.i(mTag, "host=w:" + host.getMeasuredWidth() + ", h:" + 3661 host.getMeasuredHeight() + ", params=" + params); 3662 } 3663 3664 if (mFirst || viewVisibilityChanged) { 3665 mViewFrameInfo.flags |= FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED; 3666 } 3667 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending); 3668 cancelDraw = (relayoutResult & RELAYOUT_RES_CANCEL_AND_REDRAW) 3669 == RELAYOUT_RES_CANCEL_AND_REDRAW; 3670 cancelReason = "relayout"; 3671 final boolean dragResizing = mPendingDragResizing; 3672 if (mSyncSeqId > mLastSyncSeqId) { 3673 mLastSyncSeqId = mSyncSeqId; 3674 if (DEBUG_BLAST) { 3675 Log.d(mTag, "Relayout called with blastSync"); 3676 } 3677 reportNextDraw("relayout"); 3678 mSyncBuffer = true; 3679 isSyncRequest = true; 3680 if (!cancelDraw) { 3681 mDrewOnceForSync = false; 3682 } 3683 } 3684 3685 final boolean surfaceControlChanged = 3686 (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED) 3687 == RELAYOUT_RES_SURFACE_CHANGED; 3688 3689 if (mSurfaceControl.isValid()) { 3690 updateOpacity(mWindowAttributes, dragResizing, 3691 surfaceControlChanged /*forceUpdate */); 3692 // No need to updateDisplayDecoration if it's a new SurfaceControl and 3693 // mDisplayDecorationCached is false, since that's the default for a new 3694 // SurfaceControl. 3695 if (surfaceControlChanged && mDisplayDecorationCached) { 3696 updateDisplayDecoration(); 3697 } 3698 if (surfaceControlChanged 3699 && mWindowAttributes.type 3700 == WindowManager.LayoutParams.TYPE_STATUS_BAR) { 3701 mTransaction.setDefaultFrameRateCompatibility(mSurfaceControl, 3702 Surface.FRAME_RATE_COMPATIBILITY_NO_VOTE).apply(); 3703 } 3704 3705 if (setScPropertiesInClient()) { 3706 if (surfaceControlChanged || windowAttributesChanged) { 3707 boolean colorSpaceAgnostic = (lp.privateFlags 3708 & WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC) 3709 != 0; 3710 mTransaction.setColorSpaceAgnostic(mSurfaceControl, colorSpaceAgnostic) 3711 .apply(); 3712 } 3713 } 3714 } 3715 3716 if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString() 3717 + " surface=" + mSurface); 3718 3719 // If the pending {@link MergedConfiguration} handed back from 3720 // {@link #relayoutWindow} does not match the one last reported, 3721 // WindowManagerService has reported back a frame from a configuration not yet 3722 // handled by the client. In this case, we need to accept the configuration so we 3723 // do not lay out and draw with the wrong configuration. 3724 boolean shouldPerformConfigurationUpdate = 3725 !mPendingMergedConfiguration.equals(mLastReportedMergedConfiguration) 3726 || !Objects.equals(mPendingActivityWindowInfo, 3727 mLastReportedActivityWindowInfo); 3728 if (mRelayoutRequested && shouldPerformConfigurationUpdate) { 3729 if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: " 3730 + mPendingMergedConfiguration.getMergedConfiguration()); 3731 performConfigurationChange(new MergedConfiguration(mPendingMergedConfiguration), 3732 !mFirst, INVALID_DISPLAY /* same display */, 3733 mPendingActivityWindowInfo != null 3734 ? new ActivityWindowInfo(mPendingActivityWindowInfo) 3735 : null); 3736 updatedConfiguration = true; 3737 } 3738 final boolean updateSurfaceNeeded = mUpdateSurfaceNeeded; 3739 mUpdateSurfaceNeeded = false; 3740 3741 surfaceSizeChanged = false; 3742 if (!mLastSurfaceSize.equals(mSurfaceSize)) { 3743 surfaceSizeChanged = true; 3744 mLastSurfaceSize.set(mSurfaceSize.x, mSurfaceSize.y); 3745 } 3746 final boolean alwaysConsumeSystemBarsChanged = 3747 mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars; 3748 updateColorModeIfNeeded(lp.getColorMode(), lp.getDesiredHdrHeadroom()); 3749 surfaceCreated = !hadSurface && mSurface.isValid(); 3750 surfaceDestroyed = hadSurface && !mSurface.isValid(); 3751 3752 // When using Blast, the surface generation id may not change when there's a new 3753 // SurfaceControl. In that case, we also check relayout flag 3754 // RELAYOUT_RES_SURFACE_CHANGED since it should indicate that WMS created a new 3755 // SurfaceControl. 3756 surfaceReplaced = (surfaceGenerationId != mSurface.getGenerationId() 3757 || surfaceControlChanged) && mSurface.isValid(); 3758 if (surfaceReplaced) { 3759 mSurfaceSequenceId++; 3760 } 3761 if (alwaysConsumeSystemBarsChanged) { 3762 mAttachInfo.mAlwaysConsumeSystemBars = mPendingAlwaysConsumeSystemBars; 3763 dispatchApplyInsets = true; 3764 } 3765 if (dispatchApplyInsets || mLastSystemUiVisibility != 3766 mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested) { 3767 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility; 3768 dispatchApplyInsets(host); 3769 // We applied insets so force contentInsetsChanged to ensure the 3770 // hierarchy is measured below. 3771 dispatchApplyInsets = true; 3772 } 3773 3774 if (surfaceCreated) { 3775 // If we are creating a new surface, then we need to 3776 // completely redraw it. 3777 mFullRedrawNeeded = true; 3778 mPreviousTransparentRegion.setEmpty(); 3779 3780 // Only initialize up-front if transparent regions are not 3781 // requested, otherwise defer to see if the entire window 3782 // will be transparent 3783 if (mAttachInfo.mThreadedRenderer != null) { 3784 try { 3785 hwInitialized = mAttachInfo.mThreadedRenderer.initialize(mSurface); 3786 if (hwInitialized && (host.mPrivateFlags 3787 & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) { 3788 // Don't pre-allocate if transparent regions 3789 // are requested as they may not be needed 3790 mAttachInfo.mThreadedRenderer.allocateBuffers(); 3791 } 3792 } catch (OutOfResourcesException e) { 3793 handleOutOfResourcesException(e); 3794 mLastPerformTraversalsSkipDrawReason = "oom_initialize_renderer"; 3795 return; 3796 } 3797 } 3798 } else if (surfaceDestroyed) { 3799 // If the surface has been removed, then reset the scroll 3800 // positions. 3801 if (mLastScrolledFocus != null) { 3802 mLastScrolledFocus.clear(); 3803 } 3804 mScrollY = mCurScrollY = 0; 3805 if (mView instanceof RootViewSurfaceTaker) { 3806 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY); 3807 } 3808 if (mScroller != null) { 3809 mScroller.abortAnimation(); 3810 } 3811 // Our surface is gone 3812 if (isHardwareEnabled()) { 3813 mAttachInfo.mThreadedRenderer.destroy(); 3814 } 3815 } else if ((surfaceReplaced || surfaceSizeChanged || updateSurfaceNeeded) 3816 && mSurfaceHolder == null 3817 && mAttachInfo.mThreadedRenderer != null 3818 && mSurface.isValid()) { 3819 mFullRedrawNeeded = true; 3820 try { 3821 // Need to do updateSurface (which leads to CanvasContext::setSurface and 3822 // re-create the EGLSurface) if either the Surface changed (as indicated by 3823 // generation id), or WindowManager changed the surface size. The latter is 3824 // because on some chips, changing the consumer side's BufferQueue size may 3825 // not take effect immediately unless we create a new EGLSurface. 3826 // Note that frame size change doesn't always imply surface size change (eg. 3827 // drag resizing uses fullscreen surface), need to check surfaceSizeChanged 3828 // flag from WindowManager. 3829 mAttachInfo.mThreadedRenderer.updateSurface(mSurface); 3830 } catch (OutOfResourcesException e) { 3831 handleOutOfResourcesException(e); 3832 mLastPerformTraversalsSkipDrawReason = "oom_update_surface"; 3833 return; 3834 } 3835 } 3836 3837 if (mDragResizing != dragResizing) { 3838 if (dragResizing) { 3839 final boolean backdropSizeMatchesFrame = 3840 mWinFrame.width() == mPendingBackDropFrame.width() 3841 && mWinFrame.height() == mPendingBackDropFrame.height(); 3842 // TODO: Need cutout? 3843 startDragResizing(mPendingBackDropFrame, !backdropSizeMatchesFrame, 3844 mAttachInfo.mContentInsets, mAttachInfo.mStableInsets); 3845 } else { 3846 // We shouldn't come here, but if we come we should end the resize. 3847 endDragResizing(); 3848 } 3849 } 3850 if (!mUseMTRenderer) { 3851 if (dragResizing) { 3852 mCanvasOffsetX = mWinFrame.left; 3853 mCanvasOffsetY = mWinFrame.top; 3854 } else { 3855 mCanvasOffsetX = mCanvasOffsetY = 0; 3856 } 3857 } 3858 } catch (RemoteException e) { 3859 } finally { 3860 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 3861 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 3862 } 3863 } 3864 3865 if (DEBUG_ORIENTATION) Log.v( 3866 TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface); 3867 3868 mAttachInfo.mWindowLeft = frame.left; 3869 mAttachInfo.mWindowTop = frame.top; 3870 3871 // !!FIXME!! This next section handles the case where we did not get the 3872 // window size we asked for. We should avoid this by getting a maximum size from 3873 // the window session beforehand. 3874 if (mWidth != frame.width() || mHeight != frame.height()) { 3875 mWidth = frame.width(); 3876 mHeight = frame.height(); 3877 } 3878 3879 if (mSurfaceHolder != null) { 3880 // The app owns the surface; tell it about what is going on. 3881 if (mSurface.isValid()) { 3882 // XXX .copyFrom() doesn't work! 3883 //mSurfaceHolder.mSurface.copyFrom(mSurface); 3884 mSurfaceHolder.mSurface = mSurface; 3885 } 3886 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight); 3887 mSurfaceHolder.mSurfaceLock.unlock(); 3888 if (surfaceCreated) { 3889 mSurfaceHolder.ungetCallbacks(); 3890 3891 mIsCreating = true; 3892 SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks(); 3893 if (callbacks != null) { 3894 for (SurfaceHolder.Callback c : callbacks) { 3895 c.surfaceCreated(mSurfaceHolder); 3896 } 3897 } 3898 } 3899 3900 if ((surfaceCreated || surfaceReplaced || surfaceSizeChanged 3901 || windowAttributesChanged) && mSurface.isValid()) { 3902 SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks(); 3903 if (callbacks != null) { 3904 for (SurfaceHolder.Callback c : callbacks) { 3905 c.surfaceChanged(mSurfaceHolder, lp.format, 3906 mWidth, mHeight); 3907 } 3908 } 3909 mIsCreating = false; 3910 } 3911 3912 if (surfaceDestroyed) { 3913 notifyHolderSurfaceDestroyed(); 3914 mSurfaceHolder.mSurfaceLock.lock(); 3915 try { 3916 mSurfaceHolder.mSurface = new Surface(); 3917 } finally { 3918 mSurfaceHolder.mSurfaceLock.unlock(); 3919 } 3920 } 3921 } 3922 3923 final ThreadedRenderer threadedRenderer = mAttachInfo.mThreadedRenderer; 3924 if (threadedRenderer != null && threadedRenderer.isEnabled()) { 3925 if (hwInitialized 3926 || mWidth != threadedRenderer.getWidth() 3927 || mHeight != threadedRenderer.getHeight() 3928 || mNeedsRendererSetup) { 3929 threadedRenderer.setup(mWidth, mHeight, mAttachInfo, 3930 mWindowAttributes.surfaceInsets); 3931 mNeedsRendererSetup = false; 3932 } 3933 } 3934 3935 // TODO: In the CL "ViewRootImpl: Fix issue with early draw report in 3936 // seamless rotation". We moved processing of RELAYOUT_RES_BLAST_SYNC 3937 // earlier in the function, potentially triggering a call to 3938 // reportNextDraw(). That same CL changed this and the next reference 3939 // to wasReportNextDraw, such that this logic would remain undisturbed 3940 // (it continues to operate as if the code was never moved). This was 3941 // done to achieve a more hermetic fix for S, but it's entirely 3942 // possible that checking the most recent value is actually more 3943 // correct here. 3944 if (!mStopped || mReportNextDraw) { 3945 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight() 3946 || dispatchApplyInsets || updatedConfiguration) { 3947 int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width, 3948 lp.privateFlags); 3949 int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height, 3950 lp.privateFlags); 3951 3952 if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed! mWidth=" 3953 + mWidth + " measuredWidth=" + host.getMeasuredWidth() 3954 + " mHeight=" + mHeight 3955 + " measuredHeight=" + host.getMeasuredHeight() 3956 + " dispatchApplyInsets=" + dispatchApplyInsets); 3957 3958 // Ask host how big it wants to be 3959 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 3960 3961 // Implementation of weights from WindowManager.LayoutParams 3962 // We just grow the dimensions as needed and re-measure if 3963 // needs be 3964 int width = host.getMeasuredWidth(); 3965 int height = host.getMeasuredHeight(); 3966 boolean measureAgain = false; 3967 3968 if (lp.horizontalWeight > 0.0f) { 3969 width += (int) ((mWidth - width) * lp.horizontalWeight); 3970 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width, 3971 MeasureSpec.EXACTLY); 3972 measureAgain = true; 3973 } 3974 if (lp.verticalWeight > 0.0f) { 3975 height += (int) ((mHeight - height) * lp.verticalWeight); 3976 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, 3977 MeasureSpec.EXACTLY); 3978 measureAgain = true; 3979 } 3980 3981 if (measureAgain) { 3982 if (DEBUG_LAYOUT) Log.v(mTag, 3983 "And hey let's measure once more: width=" + width 3984 + " height=" + height); 3985 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 3986 } 3987 3988 layoutRequested = true; 3989 } 3990 } 3991 } else { 3992 // Not the first pass and no window/insets/visibility change but the window 3993 // may have moved and we need check that and if so to update the left and right 3994 // in the attach info. We translate only the window frame since on window move 3995 // the window manager tells us only for the new frame but the insets are the 3996 // same and we do not want to translate them more than once. 3997 maybeHandleWindowMove(frame); 3998 } 3999 4000 if (mViewMeasureDeferred) { 4001 // It's time to measure the views since we are going to layout them. 4002 performMeasure( 4003 MeasureSpec.makeMeasureSpec(frame.width(), MeasureSpec.EXACTLY), 4004 MeasureSpec.makeMeasureSpec(frame.height(), MeasureSpec.EXACTLY)); 4005 } 4006 4007 if (!mRelayoutRequested && mCheckIfCanDraw) { 4008 // We had a sync previously, but we didn't call IWindowSession#relayout in this 4009 // traversal. So we don't know if the sync is complete that we can continue to draw. 4010 // Here invokes cancelDraw to obtain the information. 4011 try { 4012 cancelDraw = mWindowSession.cancelDraw(mWindow); 4013 cancelReason = "wm_sync"; 4014 if (DEBUG_BLAST) { 4015 Log.d(mTag, "cancelDraw returned " + cancelDraw); 4016 } 4017 } catch (RemoteException e) { 4018 } 4019 } 4020 4021 if (surfaceSizeChanged || surfaceReplaced || surfaceCreated || 4022 windowAttributesChanged || mChildBoundingInsetsChanged) { 4023 // If the surface has been replaced, there's a chance the bounds layer is not parented 4024 // to the new layer. When updating bounds layer, also reparent to the main VRI 4025 // SurfaceControl to ensure it's correctly placed in the hierarchy. 4026 // 4027 // This needs to be done on the client side since WMS won't reparent the children to the 4028 // new surface if it thinks the app is closing. WMS gets the signal that the app is 4029 // stopping, but on the client side it doesn't get stopped since it's restarted quick 4030 // enough. WMS doesn't want to keep around old children since they will leak when the 4031 // client creates new children. 4032 prepareSurfaces(); 4033 mChildBoundingInsetsChanged = false; 4034 } 4035 4036 final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw); 4037 boolean triggerGlobalLayoutListener = didLayout 4038 || mAttachInfo.mRecomputeGlobalAttributes; 4039 if (didLayout) { 4040 performLayout(lp, mWidth, mHeight); 4041 4042 // By this point all views have been sized and positioned 4043 // We can compute the transparent area 4044 4045 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 4046 // start out transparent 4047 // TODO: AVOID THAT CALL BY CACHING THE RESULT? 4048 host.getLocationInWindow(mTmpLocation); 4049 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1], 4050 mTmpLocation[0] + host.mRight - host.mLeft, 4051 mTmpLocation[1] + host.mBottom - host.mTop); 4052 4053 host.gatherTransparentRegion(mTransparentRegion); 4054 final Rect bounds = mAttachInfo.mTmpInvalRect; 4055 if (getAccessibilityFocusedRect(bounds)) { 4056 host.applyDrawableToTransparentRegion(getAccessibilityFocusedDrawable(), 4057 mTransparentRegion); 4058 } 4059 if (mTranslator != null) { 4060 mTranslator.translateRegionInWindowToScreen(mTransparentRegion); 4061 } 4062 4063 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) { 4064 mPreviousTransparentRegion.set(mTransparentRegion); 4065 mFullRedrawNeeded = true; 4066 // TODO: Ideally we would do this in prepareSurfaces, 4067 // but prepareSurfaces is currently working under 4068 // the assumption that we paused the render thread 4069 // via the WM relayout code path. We probably eventually 4070 // want to synchronize transparent region hint changes 4071 // with draws. 4072 SurfaceControl sc = getSurfaceControl(); 4073 if (sc.isValid()) { 4074 mTransaction.setTransparentRegionHint(sc, mTransparentRegion).apply(); 4075 } 4076 } 4077 } 4078 4079 if (DBG) { 4080 System.out.println("======================================"); 4081 System.out.println("performTraversals -- after setFrame"); 4082 host.debug(); 4083 } 4084 } 4085 4086 boolean didUseTransaction = false; 4087 // These callbacks will trigger SurfaceView SurfaceHolder.Callbacks and must be invoked 4088 // after the measure pass. If its invoked before the measure pass and the app modifies 4089 // the view hierarchy in the callbacks, we could leave the views in a broken state. 4090 if (surfaceCreated) { 4091 notifySurfaceCreated(mTransaction); 4092 didUseTransaction = true; 4093 } else if (surfaceReplaced) { 4094 notifySurfaceReplaced(mTransaction); 4095 didUseTransaction = true; 4096 } else if (surfaceDestroyed) { 4097 notifySurfaceDestroyed(); 4098 } 4099 4100 if (didUseTransaction) { 4101 applyTransactionOnDraw(mTransaction); 4102 } 4103 4104 if (triggerGlobalLayoutListener) { 4105 mAttachInfo.mRecomputeGlobalAttributes = false; 4106 mAttachInfo.mTreeObserver.dispatchOnGlobalLayout(); 4107 } 4108 4109 Rect contentInsets = null; 4110 Rect visibleInsets = null; 4111 Region touchableRegion = null; 4112 int touchableInsetMode = TOUCHABLE_INSETS_REGION; 4113 boolean computedInternalInsets = false; 4114 if (computesInternalInsets) { 4115 final ViewTreeObserver.InternalInsetsInfo insets = mAttachInfo.mGivenInternalInsets; 4116 4117 // Clear the original insets. 4118 insets.reset(); 4119 4120 // Compute new insets in place. 4121 mAttachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets); 4122 mAttachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty(); 4123 4124 // Tell the window manager. 4125 if (insetsPending || !mLastGivenInsets.equals(insets)) { 4126 mLastGivenInsets.set(insets); 4127 4128 // Translate insets to screen coordinates if needed. 4129 if (mTranslator != null) { 4130 contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets); 4131 visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets); 4132 touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion); 4133 } else { 4134 contentInsets = insets.contentInsets; 4135 visibleInsets = insets.visibleInsets; 4136 touchableRegion = insets.touchableRegion; 4137 } 4138 computedInternalInsets = true; 4139 } 4140 touchableInsetMode = insets.mTouchableInsets; 4141 } 4142 boolean needsSetInsets = computedInternalInsets; 4143 needsSetInsets |= !Objects.equals(mPreviousTouchableRegion, mTouchableRegion) && 4144 (mTouchableRegion != null); 4145 if (needsSetInsets) { 4146 if (mTouchableRegion != null) { 4147 if (mPreviousTouchableRegion == null) { 4148 mPreviousTouchableRegion = new Region(); 4149 } 4150 mPreviousTouchableRegion.set(mTouchableRegion); 4151 if (touchableInsetMode != TOUCHABLE_INSETS_REGION) { 4152 Log.e(mTag, "Setting touchableInsetMode to non TOUCHABLE_INSETS_REGION" + 4153 " from OnComputeInternalInsets, while also using setTouchableRegion" + 4154 " causes setTouchableRegion to be ignored"); 4155 } 4156 } else { 4157 mPreviousTouchableRegion = null; 4158 } 4159 if (contentInsets == null) contentInsets = new Rect(0,0,0,0); 4160 if (visibleInsets == null) visibleInsets = new Rect(0,0,0,0); 4161 if (touchableRegion == null) { 4162 touchableRegion = mTouchableRegion; 4163 } else if (touchableRegion != null && mTouchableRegion != null) { 4164 touchableRegion.op(touchableRegion, mTouchableRegion, Region.Op.UNION); 4165 } 4166 try { 4167 mWindowSession.setInsets(mWindow, touchableInsetMode, 4168 contentInsets, visibleInsets, touchableRegion); 4169 } catch (RemoteException e) { 4170 throw e.rethrowFromSystemServer(); 4171 } 4172 } else if (mTouchableRegion == null && mPreviousTouchableRegion != null) { 4173 mPreviousTouchableRegion = null; 4174 try { 4175 mWindowSession.clearTouchableRegion(mWindow); 4176 } catch (RemoteException e) { 4177 throw e.rethrowFromSystemServer(); 4178 } 4179 } 4180 4181 if (mFirst) { 4182 if (sAlwaysAssignFocus || !isInTouchMode()) { 4183 // handle first focus request 4184 if (DEBUG_INPUT_RESIZE) { 4185 Log.v(mTag, "First: mView.hasFocus()=" + mView.hasFocus()); 4186 } 4187 if (mView != null) { 4188 if (!mView.hasFocus()) { 4189 mView.restoreDefaultFocus(); 4190 if (DEBUG_INPUT_RESIZE) { 4191 Log.v(mTag, "First: requested focused view=" + mView.findFocus()); 4192 } 4193 } else { 4194 if (DEBUG_INPUT_RESIZE) { 4195 Log.v(mTag, "First: existing focused view=" + mView.findFocus()); 4196 } 4197 } 4198 } 4199 } else { 4200 // Some views (like ScrollView) won't hand focus to descendants that aren't within 4201 // their viewport. Before layout, there's a good change these views are size 0 4202 // which means no children can get focus. After layout, this view now has size, but 4203 // is not guaranteed to hand-off focus to a focusable child (specifically, the edge- 4204 // case where the child has a size prior to layout and thus won't trigger 4205 // focusableViewAvailable). 4206 View focused = mView.findFocus(); 4207 if (focused instanceof ViewGroup 4208 && ((ViewGroup) focused).getDescendantFocusability() 4209 == ViewGroup.FOCUS_AFTER_DESCENDANTS) { 4210 focused.restoreDefaultFocus(); 4211 } 4212 } 4213 4214 if (shouldEnableDvrr()) { 4215 // Boost the frame rate when the ViewRootImpl first becomes available. 4216 boostFrameRate(FRAME_RATE_BOOST_TIME); 4217 } 4218 } 4219 4220 final boolean changedVisibility = (viewVisibilityChanged || mFirst) && isViewVisible; 4221 if (changedVisibility) { 4222 maybeFireAccessibilityWindowStateChangedEvent(); 4223 } 4224 4225 mFirst = false; 4226 mWillDrawSoon = false; 4227 mNewSurfaceNeeded = false; 4228 mViewVisibility = viewVisibility; 4229 4230 final boolean hasWindowFocus = mAttachInfo.mHasWindowFocus && isViewVisible; 4231 mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes); 4232 4233 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { 4234 reportNextDraw("first_relayout"); 4235 } 4236 4237 mCheckIfCanDraw = isSyncRequest || cancelDraw; 4238 4239 boolean cancelDueToPreDrawListener = mAttachInfo.mTreeObserver.dispatchOnPreDraw(); 4240 boolean cancelAndRedraw = cancelDueToPreDrawListener 4241 || (cancelDraw && mDrewOnceForSync); 4242 4243 if (!cancelAndRedraw) { 4244 // A sync was already requested before the WMS requested sync. This means we need to 4245 // sync the buffer, regardless if WMS wants to sync the buffer. 4246 if (mActiveSurfaceSyncGroup != null) { 4247 mSyncBuffer = true; 4248 } 4249 4250 createSyncIfNeeded(); 4251 notifyDrawStarted(isInWMSRequestedSync()); 4252 mDrewOnceForSync = true; 4253 4254 // If the active SSG is also requesting to sync a buffer, the following needs to happen 4255 // 1. Ensure we keep track of the number of active syncs to know when to disable RT 4256 // RT animations that conflict with syncing a buffer. 4257 // 2. Add a safeguard SSG to prevent multiple SSG that sync buffers from being submitted 4258 // out of order. 4259 if (mActiveSurfaceSyncGroup != null && mSyncBuffer) { 4260 updateSyncInProgressCount(mActiveSurfaceSyncGroup); 4261 safeguardOverlappingSyncs(mActiveSurfaceSyncGroup); 4262 } 4263 } 4264 4265 if (!isViewVisible) { 4266 if (mLastTraversalWasVisible) { 4267 logAndTrace("Not drawing due to not visible. Reason=" + viewVisibilityReason); 4268 } 4269 mLastPerformTraversalsSkipDrawReason = "view_not_visible"; 4270 if (mPendingTransitions != null && mPendingTransitions.size() > 0) { 4271 for (int i = 0; i < mPendingTransitions.size(); ++i) { 4272 mPendingTransitions.get(i).endChangingAnimations(); 4273 } 4274 mPendingTransitions.clear(); 4275 } 4276 4277 handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions, 4278 mPendingTransaction, "view not visible"); 4279 } else if (cancelAndRedraw) { 4280 if (!mWasLastDrawCanceled) { 4281 logAndTrace("Canceling draw." 4282 + " cancelDueToPreDrawListener=" + cancelDueToPreDrawListener 4283 + " cancelDueToSync=" + (cancelDraw && mDrewOnceForSync)); 4284 } 4285 mLastPerformTraversalsSkipDrawReason = cancelDueToPreDrawListener 4286 ? "predraw_" + mAttachInfo.mTreeObserver.getLastDispatchOnPreDrawCanceledReason() 4287 : "cancel_" + cancelReason; 4288 // Try again 4289 scheduleTraversals(); 4290 } else { 4291 if (mWasLastDrawCanceled) { 4292 logAndTrace("Draw frame after cancel"); 4293 } 4294 if (!mLastTraversalWasVisible) { 4295 logAndTrace("Start draw after previous draw not visible"); 4296 } 4297 if (mPendingTransitions != null && mPendingTransitions.size() > 0) { 4298 for (int i = 0; i < mPendingTransitions.size(); ++i) { 4299 mPendingTransitions.get(i).startChangingAnimations(); 4300 } 4301 mPendingTransitions.clear(); 4302 } 4303 if (!performDraw(mActiveSurfaceSyncGroup)) { 4304 handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions, 4305 mPendingTransaction, mLastPerformDrawSkippedReason); 4306 } 4307 } 4308 mWasLastDrawCanceled = cancelAndRedraw; 4309 mLastTraversalWasVisible = isViewVisible; 4310 4311 if (mAttachInfo.mContentCaptureEvents != null) { 4312 notifyContentCaptureEvents(); 4313 } 4314 4315 mIsInTraversal = false; 4316 mRelayoutRequested = false; 4317 4318 if (!cancelAndRedraw) { 4319 mReportNextDraw = false; 4320 mLastReportNextDrawReason = null; 4321 mActiveSurfaceSyncGroup = null; 4322 if (mHasPendingTransactions) { 4323 // TODO: We shouldn't ever actually hit this, it means mPendingTransaction wasn't 4324 // merged with a sync group or BLASTBufferQueue before making it to this point 4325 // But better a one or two frame flicker than steady-state broken from dropping 4326 // whatever is in this transaction 4327 mPendingTransaction.apply(); 4328 mHasPendingTransactions = false; 4329 } 4330 mSyncBuffer = false; 4331 if (isInWMSRequestedSync()) { 4332 mWmsRequestSyncGroup.markSyncReady(); 4333 mWmsRequestSyncGroup = null; 4334 mWmsRequestSyncGroupState = WMS_SYNC_NONE; 4335 } 4336 } 4337 4338 // For the variable refresh rate project. 4339 // We set the preferred frame rate and frame rate category at the end of performTraversals 4340 // when the values are applicable. 4341 if (mDrawnThisFrame) { 4342 mDrawnThisFrame = false; 4343 if (!mInvalidationIdleMessagePosted && sSurfaceFlingerBugfixFlagValue) { 4344 mInvalidationIdleMessagePosted = true; 4345 mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE, IDLE_TIME_MILLIS); 4346 } 4347 setCategoryFromCategoryCounts(); 4348 updateInfrequentCount(); 4349 updateFrameRateFromThreadedRendererViews(); 4350 setPreferredFrameRate(mPreferredFrameRate); 4351 setPreferredFrameRateCategory(mPreferredFrameRateCategory); 4352 if (mPreferredFrameRate > 0 4353 || (mLastPreferredFrameRate != 0 && mPreferredFrameRate == 0) 4354 ) { 4355 mHandler.removeMessages(MSG_FRAME_RATE_SETTING); 4356 mHandler.sendEmptyMessageDelayed(MSG_FRAME_RATE_SETTING, 4357 FRAME_RATE_SETTING_REEVALUATE_TIME); 4358 } 4359 mFrameRateCategoryHighCount = mFrameRateCategoryHighCount > 0 4360 ? mFrameRateCategoryHighCount - 1 : mFrameRateCategoryHighCount; 4361 mFrameRateCategoryNormalCount = mFrameRateCategoryNormalCount > 0 4362 ? mFrameRateCategoryNormalCount - 1 : mFrameRateCategoryNormalCount; 4363 mFrameRateCategoryLowCount = mFrameRateCategoryLowCount > 0 4364 ? mFrameRateCategoryLowCount - 1 : mFrameRateCategoryLowCount; 4365 mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_DEFAULT; 4366 mPreferredFrameRate = -1; 4367 mIsFrameRateConflicted = false; 4368 mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_UNKNOWN; 4369 } else if (mPreferredFrameRate == 0) { 4370 // From MSG_FRAME_RATE_SETTING, where mPreferredFrameRate is set to 0 4371 setPreferredFrameRate(0); 4372 mPreferredFrameRate = -1; 4373 } 4374 } 4375 createSyncIfNeeded()4376 private void createSyncIfNeeded() { 4377 // WMS requested sync already started or there's nothing needing to sync 4378 if (isInWMSRequestedSync() || !mReportNextDraw) { 4379 return; 4380 } 4381 4382 final int seqId = mSyncSeqId; 4383 mWmsRequestSyncGroupState = WMS_SYNC_PENDING; 4384 mWmsRequestSyncGroup = new SurfaceSyncGroup("wmsSync-" + mTag, t -> { 4385 mWmsRequestSyncGroupState = WMS_SYNC_MERGED; 4386 // See b/286355097. If the current process is not system, then invoking finishDraw on 4387 // any thread is fine since once it calls into system process, finishDrawing will run 4388 // on a different thread. However, when the current process is system, the finishDraw in 4389 // system server will be run on the current thread, which could result in a deadlock. 4390 if (mWindowSession instanceof Binder) { 4391 // The transaction should be copied to a local reference when posting onto a new 4392 // thread because up until now the SSG is holding a lock on the transaction. Once 4393 // the call jumps onto a new thread, the lock is no longer held and the transaction 4394 // send back may be modified or used again. 4395 Transaction transactionCopy = new Transaction(); 4396 transactionCopy.merge(t); 4397 mHandler.postAtFrontOfQueue(() -> reportDrawFinished(transactionCopy, seqId)); 4398 } else { 4399 reportDrawFinished(t, seqId); 4400 } 4401 }); 4402 4403 // Only trigger once per {@link ViewRootImpl} instance, so don't add listener if 4404 // {link mTransactionCompletedTimeNs} has already been set. 4405 if (mAppStartInfoTimestampsFlagValue && !mAppStartTrackingStarted) { 4406 mAppStartTrackingStarted = true; 4407 Transaction transaction = new Transaction(); 4408 transaction.addTransactionCompletedListener(mSimpleExecutor, 4409 new Consumer<TransactionStats>() { 4410 @Override 4411 public void accept(TransactionStats transactionStats) { 4412 SyncFence presentFence = transactionStats.getPresentFence(); 4413 if (presentFence.awaitForever()) { 4414 if (mFirstFramePresentedTimeNs == -1) { 4415 // Only trigger once per {@link ViewRootImpl} instance. 4416 mFirstFramePresentedTimeNs = presentFence.getSignalTime(); 4417 maybeSendAppStartTimes(); 4418 } 4419 } 4420 presentFence.close(); 4421 } 4422 }); 4423 applyTransactionOnDraw(transaction); 4424 } 4425 4426 if (DEBUG_BLAST) { 4427 Log.d(mTag, "Setup new sync=" + mWmsRequestSyncGroup.getName()); 4428 } 4429 4430 mWmsRequestSyncGroup.add(this, null /* runnable */); 4431 } 4432 maybeSendAppStartTimes()4433 private void maybeSendAppStartTimes() { 4434 synchronized (this) { 4435 if (mAppStartTimestampsSent) { 4436 // Don't send timestamps more than once. 4437 return; 4438 } 4439 4440 // If we already have {@link mRenderThreadDrawStartTimeNs} then pass it through, if not 4441 // post to main thread and check if we have it there. 4442 if (mRenderThreadDrawStartTimeNs != -1) { 4443 sendAppStartTimesLocked(); 4444 } else { 4445 mHandler.post(new Runnable() { 4446 @Override 4447 public void run() { 4448 synchronized (ViewRootImpl.this) { 4449 if (mRenderThreadDrawStartTimeNs == -1) { 4450 return; 4451 } 4452 sendAppStartTimesLocked(); 4453 } 4454 } 4455 }); 4456 } 4457 } 4458 } 4459 4460 @GuardedBy("this") sendAppStartTimesLocked()4461 private void sendAppStartTimesLocked() { 4462 try { 4463 ActivityManager.getService().reportStartInfoViewTimestamps( 4464 mRenderThreadDrawStartTimeNs, mFirstFramePresentedTimeNs); 4465 mAppStartTimestampsSent = true; 4466 } catch (RemoteException e) { 4467 // Ignore, timestamps may be lost. 4468 if (DBG) Log.d(TAG, "Exception attempting to report start timestamps.", e); 4469 } 4470 } 4471 4472 /** 4473 * Helper used to notify the service to block projection when a sensitive 4474 * view (the view displays sensitive content) is attached to the window. 4475 * The window manager service is also notified to unblock projection when 4476 * no attached view (to the window) displays sensitive content. 4477 * 4478 * <ol> 4479 * <li>It should only notify service to block projection when first sensitive view is 4480 * attached to the window. 4481 * <li>It should only notify service to unblock projection when all sensitive view are 4482 * removed from the window. 4483 * </ol> 4484 * 4485 * @param enableProtection if true, the protection is enabled for this window. 4486 * if false, the protection is removed for this window. 4487 */ applySensitiveContentAppProtection(boolean enableProtection)4488 private void applySensitiveContentAppProtection(boolean enableProtection) { 4489 try { 4490 if (mSensitiveContentProtectionService == null) { 4491 return; 4492 } 4493 if (DEBUG_SENSITIVE_CONTENT) { 4494 Log.d(TAG, "Notify sensitive content, package=" + mContext.getPackageName() 4495 + ", token=" + getWindowToken() + ", flag=" + enableProtection); 4496 } 4497 // The window would be blocked during screen share if it shows sensitive content. 4498 mSensitiveContentProtectionService.setSensitiveContentProtection( 4499 getWindowToken(), mContext.getPackageName(), enableProtection); 4500 } catch (RemoteException ex) { 4501 Log.e(TAG, "Unable to protect sensitive content during screen share", ex); 4502 } 4503 } 4504 4505 /** 4506 * Add sensitive content protection, when there are one or more visible sensitive views. 4507 */ addSensitiveContentAppProtection()4508 void addSensitiveContentAppProtection() { 4509 applySensitiveContentAppProtection(true); 4510 } 4511 4512 /** 4513 * Remove sensitive content protection, when there is no visible sensitive view. 4514 */ removeSensitiveContentAppProtection()4515 void removeSensitiveContentAppProtection() { 4516 if (!sensitiveContentPrematureProtectionRemovedFix()) { 4517 applySensitiveContentAppProtection(false); 4518 return; 4519 } 4520 if (DEBUG_SENSITIVE_CONTENT) { 4521 Log.d(TAG, "Add transaction to remove sensitive content protection, package=" 4522 + mContext.getPackageName() + ", token=" + getWindowToken()); 4523 } 4524 Transaction t = new Transaction(); 4525 t.addTransactionCommittedListener(mExecutor, () -> { 4526 if (mAttachInfo.mSensitiveViewsCount == 0) { 4527 applySensitiveContentAppProtection(false); 4528 } 4529 }); 4530 applyTransactionOnDraw(t); 4531 } 4532 notifyContentCaptureEvents()4533 private void notifyContentCaptureEvents() { 4534 if (!isContentCaptureEnabled()) { 4535 if (DEBUG_CONTENT_CAPTURE) { 4536 Log.d(mTag, "notifyContentCaptureEvents while disabled"); 4537 } 4538 mAttachInfo.mContentCaptureEvents = null; 4539 return; 4540 } 4541 4542 final ContentCaptureManager manager = mAttachInfo.mContentCaptureManager; 4543 if (manager != null && mAttachInfo.mContentCaptureEvents != null) { 4544 final ContentCaptureSession session = manager.getMainContentCaptureSession(); 4545 session.notifyContentCaptureEvents(mAttachInfo.mContentCaptureEvents); 4546 } 4547 mAttachInfo.mContentCaptureEvents = null; 4548 } 4549 notifyHolderSurfaceDestroyed()4550 private void notifyHolderSurfaceDestroyed() { 4551 mSurfaceHolder.ungetCallbacks(); 4552 SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks(); 4553 if (callbacks != null) { 4554 for (SurfaceHolder.Callback c : callbacks) { 4555 c.surfaceDestroyed(mSurfaceHolder); 4556 } 4557 } 4558 } 4559 maybeHandleWindowMove(Rect frame)4560 private void maybeHandleWindowMove(Rect frame) { 4561 // TODO: Well, we are checking whether the frame has changed similarly 4562 // to how this is done for the insets. This is however incorrect since 4563 // the insets and the frame are translated. For example, the old frame 4564 // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new 4565 // reported frame is (2, 2 - 2, 2) which implies no change but this is not 4566 // true since we are comparing a not translated value to a translated one. 4567 // This scenario is rare but we may want to fix that. 4568 4569 final boolean windowMoved = mAttachInfo.mWindowLeft != frame.left 4570 || mAttachInfo.mWindowTop != frame.top; 4571 if (windowMoved) { 4572 mAttachInfo.mWindowLeft = frame.left; 4573 mAttachInfo.mWindowTop = frame.top; 4574 } 4575 if (windowMoved || mAttachInfo.mNeedsUpdateLightCenter) { 4576 // Update the light position for the new offsets. 4577 if (mAttachInfo.mThreadedRenderer != null) { 4578 mAttachInfo.mThreadedRenderer.setLightCenter(mAttachInfo); 4579 } 4580 mAttachInfo.mNeedsUpdateLightCenter = false; 4581 } 4582 } 4583 handleWindowFocusChanged()4584 private void handleWindowFocusChanged() { 4585 final boolean hasWindowFocus; 4586 synchronized (this) { 4587 if (!mWindowFocusChanged) { 4588 return; 4589 } 4590 mWindowFocusChanged = false; 4591 hasWindowFocus = mUpcomingWindowFocus; 4592 } 4593 if (hasWindowFocus) { 4594 mInsetsController.onWindowFocusGained( 4595 getFocusedViewOrNull() != null /* hasViewFocused */); 4596 } else { 4597 mInsetsController.onWindowFocusLost(); 4598 } 4599 4600 if (mAdded) { 4601 dispatchFocusEvent(hasWindowFocus, false /* fakeFocus */); 4602 // Note: must be done after the focus change callbacks, 4603 // so all of the view state is set up correctly. 4604 mImeFocusController.onPostWindowFocus( 4605 getFocusedViewOrNull(), hasWindowFocus, mWindowAttributes); 4606 4607 if (hasWindowFocus) { 4608 // Clear the forward bit. We can just do this directly, since 4609 // the window manager doesn't care about it. 4610 mWindowAttributes.softInputMode &= 4611 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; 4612 ((WindowManager.LayoutParams) mView.getLayoutParams()) 4613 .softInputMode &= 4614 ~WindowManager.LayoutParams 4615 .SOFT_INPUT_IS_FORWARD_NAVIGATION; 4616 4617 maybeFireAccessibilityWindowStateChangedEvent(); 4618 4619 // Refocusing a window that has a focused view should fire a 4620 // focus event for the view since the global focused view changed. 4621 fireAccessibilityFocusEventIfHasFocusedNode(); 4622 } else { 4623 if (mPointerCapture) { 4624 handlePointerCaptureChanged(false); 4625 } 4626 } 4627 } 4628 mFirstInputStage.onWindowFocusChanged(hasWindowFocus); 4629 4630 // NOTE: there's no view visibility (appeared / disapparead) events when the windows focus 4631 // is lost, so we don't need to to force a flush - there might be other events such as 4632 // text changes, but these should be flushed independently. 4633 if (hasWindowFocus) { 4634 handleContentCaptureFlush(); 4635 } 4636 } 4637 4638 /** 4639 * Send a fake focus event for unfocused apps in split screen as some game engines wait to 4640 * get focus before drawing the content of the app. This will be used so that apps do not get 4641 * blacked out when they are resumed and do not have focus yet. 4642 * 4643 * {@hide} 4644 */ 4645 // TODO(b/263094829): Investigate dispatching this for onPause as well dispatchCompatFakeFocus()4646 public void dispatchCompatFakeFocus() { 4647 boolean aboutToHaveFocus = false; 4648 synchronized (this) { 4649 aboutToHaveFocus = mWindowFocusChanged && mUpcomingWindowFocus; 4650 } 4651 final boolean alreadyHaveFocus = mAttachInfo.mHasWindowFocus; 4652 if (aboutToHaveFocus || alreadyHaveFocus) { 4653 // Do not need to toggle focus if app doesn't need it, or has focus. 4654 return; 4655 } 4656 EventLog.writeEvent(LOGTAG_INPUT_FOCUS, 4657 "Giving fake focus to " + mBasePackageName, "reason=unity bug workaround"); 4658 dispatchFocusEvent(true /* hasWindowFocus */, true /* fakeFocus */); 4659 EventLog.writeEvent(LOGTAG_INPUT_FOCUS, 4660 "Removing fake focus from " + mBasePackageName, "reason=timeout callback"); 4661 dispatchFocusEvent(false /* hasWindowFocus */, true /* fakeFocus */); 4662 } 4663 dispatchFocusEvent(boolean hasWindowFocus, boolean fakeFocus)4664 private void dispatchFocusEvent(boolean hasWindowFocus, boolean fakeFocus) { 4665 profileRendering(hasWindowFocus); 4666 if (hasWindowFocus && mAttachInfo.mThreadedRenderer != null && mSurface.isValid()) { 4667 mFullRedrawNeeded = true; 4668 try { 4669 final Rect surfaceInsets = mWindowAttributes.surfaceInsets; 4670 mAttachInfo.mThreadedRenderer.initializeIfNeeded( 4671 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets); 4672 } catch (OutOfResourcesException e) { 4673 Log.e(mTag, "OutOfResourcesException locking surface", e); 4674 try { 4675 if (!mWindowSession.outOfMemory(mWindow)) { 4676 Slog.w(mTag, "No processes killed for memory;" 4677 + " killing self"); 4678 Process.killProcess(Process.myPid()); 4679 } 4680 } catch (RemoteException ex) { 4681 } 4682 // Retry in a bit. 4683 mHandler.sendMessageDelayed(mHandler.obtainMessage( 4684 MSG_WINDOW_FOCUS_CHANGED), 500); 4685 return; 4686 } 4687 } 4688 4689 mAttachInfo.mHasWindowFocus = hasWindowFocus; 4690 4691 if (!fakeFocus) { 4692 mImeFocusController.onPreWindowFocus(hasWindowFocus, mWindowAttributes); 4693 } 4694 4695 if (mView != null) { 4696 mAttachInfo.mKeyDispatchState.reset(); 4697 mView.dispatchWindowFocusChanged(hasWindowFocus); 4698 mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus); 4699 if (mAttachInfo.mTooltipHost != null) { 4700 mAttachInfo.mTooltipHost.hideTooltip(); 4701 } 4702 } 4703 } 4704 handleWindowTouchModeChanged()4705 private void handleWindowTouchModeChanged() { 4706 final boolean inTouchMode; 4707 synchronized (this) { 4708 inTouchMode = mUpcomingInTouchMode; 4709 } 4710 ensureTouchModeLocally(inTouchMode); 4711 } 4712 maybeFireAccessibilityWindowStateChangedEvent()4713 private void maybeFireAccessibilityWindowStateChangedEvent() { 4714 // Toasts are presented as notifications - don't present them as windows as well. 4715 boolean isToast = mWindowAttributes != null && (mWindowAttributes.type == TYPE_TOAST); 4716 if (!isToast && mView != null) { 4717 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 4718 } 4719 } 4720 fireAccessibilityFocusEventIfHasFocusedNode()4721 private void fireAccessibilityFocusEventIfHasFocusedNode() { 4722 if (!mAccessibilityManager.isEnabled()) { 4723 return; 4724 } 4725 final View focusedView = mView.findFocus(); 4726 if (focusedView == null) { 4727 return; 4728 } 4729 final AccessibilityNodeProvider provider = focusedView.getAccessibilityNodeProvider(); 4730 if (provider == null) { 4731 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 4732 } else { 4733 final AccessibilityNodeInfo focusedNode = findFocusedVirtualNode(provider); 4734 if (focusedNode != null) { 4735 final int virtualId = AccessibilityNodeInfo.getVirtualDescendantId( 4736 focusedNode.getSourceNodeId()); 4737 // This is a best effort since clearing and setting the focus via the 4738 // provider APIs could have side effects. We don't have a provider API 4739 // similar to that on View to ask a given event to be fired. 4740 final AccessibilityEvent event = AccessibilityEvent.obtain( 4741 AccessibilityEvent.TYPE_VIEW_FOCUSED); 4742 event.setSource(focusedView, virtualId); 4743 event.setPackageName(focusedNode.getPackageName()); 4744 event.setChecked(focusedNode.isChecked()); 4745 event.setContentDescription(focusedNode.getContentDescription()); 4746 event.setPassword(focusedNode.isPassword()); 4747 event.getText().add(focusedNode.getText()); 4748 event.setEnabled(focusedNode.isEnabled()); 4749 focusedView.getParent().requestSendAccessibilityEvent(focusedView, event); 4750 focusedNode.recycle(); 4751 } 4752 } 4753 } 4754 findFocusedVirtualNode(AccessibilityNodeProvider provider)4755 private AccessibilityNodeInfo findFocusedVirtualNode(AccessibilityNodeProvider provider) { 4756 AccessibilityNodeInfo focusedNode = provider.findFocus( 4757 AccessibilityNodeInfo.FOCUS_INPUT); 4758 if (focusedNode != null) { 4759 return focusedNode; 4760 } 4761 4762 if (!mContext.isAutofillCompatibilityEnabled()) { 4763 return null; 4764 } 4765 4766 // Unfortunately some provider implementations don't properly 4767 // implement AccessibilityNodeProvider#findFocus 4768 AccessibilityNodeInfo current = provider.createAccessibilityNodeInfo( 4769 AccessibilityNodeProvider.HOST_VIEW_ID); 4770 if (current == null) { 4771 return null; 4772 } 4773 if (current.isFocused()) { 4774 return current; 4775 } 4776 4777 final Queue<AccessibilityNodeInfo> fringe = new ArrayDeque<>(); 4778 fringe.offer(current); 4779 4780 while (!fringe.isEmpty()) { 4781 current = fringe.poll(); 4782 final LongArray childNodeIds = current.getChildNodeIds(); 4783 if (childNodeIds== null || childNodeIds.size() <= 0) { 4784 continue; 4785 } 4786 final int childCount = childNodeIds.size(); 4787 for (int i = 0; i < childCount; i++) { 4788 final int virtualId = AccessibilityNodeInfo.getVirtualDescendantId( 4789 childNodeIds.get(i)); 4790 final AccessibilityNodeInfo child = provider.createAccessibilityNodeInfo(virtualId); 4791 if (child != null) { 4792 if (child.isFocused()) { 4793 return child; 4794 } 4795 fringe.offer(child); 4796 } 4797 } 4798 current.recycle(); 4799 } 4800 4801 return null; 4802 } 4803 handleOutOfResourcesException(Surface.OutOfResourcesException e)4804 private void handleOutOfResourcesException(Surface.OutOfResourcesException e) { 4805 Log.e(mTag, "OutOfResourcesException initializing HW surface", e); 4806 try { 4807 if (!mWindowSession.outOfMemory(mWindow) && 4808 Process.myUid() != Process.SYSTEM_UID) { 4809 Slog.w(mTag, "No processes killed for memory; killing self"); 4810 Process.killProcess(Process.myPid()); 4811 } 4812 } catch (RemoteException ex) { 4813 } 4814 mLayoutRequested = true; // ask wm for a new surface next time. 4815 } 4816 performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec)4817 private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) { 4818 if (mView == null) { 4819 return; 4820 } 4821 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure"); 4822 try { 4823 mView.measure(childWidthMeasureSpec, childHeightMeasureSpec); 4824 } finally { 4825 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 4826 } 4827 mMeasuredWidth = mView.getMeasuredWidth(); 4828 mMeasuredHeight = mView.getMeasuredHeight(); 4829 mViewMeasureDeferred = false; 4830 } 4831 4832 /** 4833 * Called by {@link android.view.View#isInLayout()} to determine whether the view hierarchy 4834 * is currently undergoing a layout pass. 4835 * 4836 * @return whether the view hierarchy is currently undergoing a layout pass 4837 */ isInLayout()4838 boolean isInLayout() { 4839 return mInLayout; 4840 } 4841 4842 /** 4843 * Called by {@link android.view.View#requestLayout()} if the view hierarchy is currently 4844 * undergoing a layout pass. requestLayout() should not generally be called during layout, 4845 * unless the container hierarchy knows what it is doing (i.e., it is fine as long as 4846 * all children in that container hierarchy are measured and laid out at the end of the layout 4847 * pass for that container). If requestLayout() is called anyway, we handle it correctly 4848 * by registering all requesters during a frame as it proceeds. At the end of the frame, 4849 * we check all of those views to see if any still have pending layout requests, which 4850 * indicates that they were not correctly handled by their container hierarchy. If that is 4851 * the case, we clear all such flags in the tree, to remove the buggy flag state that leads 4852 * to blank containers, and force a second request/measure/layout pass in this frame. If 4853 * more requestLayout() calls are received during that second layout pass, we post those 4854 * requests to the next frame to avoid possible infinite loops. 4855 * 4856 * <p>The return value from this method indicates whether the request should proceed 4857 * (if it is a request during the first layout pass) or should be skipped and posted to the 4858 * next frame (if it is a request during the second layout pass).</p> 4859 * 4860 * @param view the view that requested the layout. 4861 * 4862 * @return true if request should proceed, false otherwise. 4863 */ requestLayoutDuringLayout(final View view)4864 boolean requestLayoutDuringLayout(final View view) { 4865 if (view.mParent == null || view.mAttachInfo == null) { 4866 // Would not normally trigger another layout, so just let it pass through as usual 4867 return true; 4868 } 4869 if (!mLayoutRequesters.contains(view)) { 4870 mLayoutRequesters.add(view); 4871 } 4872 if (!mHandlingLayoutInLayoutRequest) { 4873 // Let the request proceed normally; it will be processed in a second layout pass 4874 // if necessary 4875 return true; 4876 } else { 4877 // Don't let the request proceed during the second layout pass. 4878 // It will post to the next frame instead. 4879 return false; 4880 } 4881 } 4882 performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, int desiredWindowHeight)4883 private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, 4884 int desiredWindowHeight) { 4885 mScrollMayChange = true; 4886 mInLayout = true; 4887 4888 final View host = mView; 4889 if (host == null) { 4890 return; 4891 } 4892 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) { 4893 Log.v(mTag, "Laying out " + host + " to (" + 4894 host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")"); 4895 } 4896 4897 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout"); 4898 try { 4899 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight()); 4900 4901 mInLayout = false; 4902 int numViewsRequestingLayout = mLayoutRequesters.size(); 4903 if (numViewsRequestingLayout > 0) { 4904 // requestLayout() was called during layout. 4905 // If no layout-request flags are set on the requesting views, there is no problem. 4906 // If some requests are still pending, then we need to clear those flags and do 4907 // a full request/measure/layout pass to handle this situation. 4908 ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, 4909 false); 4910 if (validLayoutRequesters != null) { 4911 // Set this flag to indicate that any further requests are happening during 4912 // the second pass, which may result in posting those requests to the next 4913 // frame instead 4914 mHandlingLayoutInLayoutRequest = true; 4915 4916 // Process fresh layout requests, then measure and layout 4917 int numValidRequests = validLayoutRequesters.size(); 4918 for (int i = 0; i < numValidRequests; ++i) { 4919 final View view = validLayoutRequesters.get(i); 4920 Log.w("View", "requestLayout() improperly called by " + view + 4921 " during layout: running second layout pass"); 4922 view.requestLayout(); 4923 } 4924 measureHierarchy(host, lp, mView.getContext().getResources(), 4925 desiredWindowWidth, desiredWindowHeight, false /* forRootSizeOnly */); 4926 mInLayout = true; 4927 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight()); 4928 4929 mHandlingLayoutInLayoutRequest = false; 4930 4931 // Check the valid requests again, this time without checking/clearing the 4932 // layout flags, since requests happening during the second pass get noop'd 4933 validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true); 4934 if (validLayoutRequesters != null) { 4935 final ArrayList<View> finalRequesters = validLayoutRequesters; 4936 // Post second-pass requests to the next frame 4937 getRunQueue().post(new Runnable() { 4938 @Override 4939 public void run() { 4940 int numValidRequests = finalRequesters.size(); 4941 for (int i = 0; i < numValidRequests; ++i) { 4942 final View view = finalRequesters.get(i); 4943 Log.w("View", "requestLayout() improperly called by " + view + 4944 " during second layout pass: posting in next frame"); 4945 view.requestLayout(); 4946 } 4947 } 4948 }); 4949 } 4950 } 4951 4952 } 4953 } finally { 4954 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 4955 } 4956 mInLayout = false; 4957 } 4958 4959 /** 4960 * This method is called during layout when there have been calls to requestLayout() during 4961 * layout. It walks through the list of views that requested layout to determine which ones 4962 * still need it, based on visibility in the hierarchy and whether they have already been 4963 * handled (as is usually the case with ListView children). 4964 * 4965 * @param layoutRequesters The list of views that requested layout during layout 4966 * @param secondLayoutRequests Whether the requests were issued during the second layout pass. 4967 * If so, the FORCE_LAYOUT flag was not set on requesters. 4968 * @return A list of the actual views that still need to be laid out. 4969 */ getValidLayoutRequesters(ArrayList<View> layoutRequesters, boolean secondLayoutRequests)4970 private ArrayList<View> getValidLayoutRequesters(ArrayList<View> layoutRequesters, 4971 boolean secondLayoutRequests) { 4972 4973 int numViewsRequestingLayout = layoutRequesters.size(); 4974 ArrayList<View> validLayoutRequesters = null; 4975 for (int i = 0; i < numViewsRequestingLayout; ++i) { 4976 View view = layoutRequesters.get(i); 4977 if (view != null && view.mAttachInfo != null && view.mParent != null && 4978 (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) == 4979 View.PFLAG_FORCE_LAYOUT)) { 4980 boolean gone = false; 4981 View parent = view; 4982 // Only trigger new requests for views in a non-GONE hierarchy 4983 while (parent != null) { 4984 if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) { 4985 gone = true; 4986 break; 4987 } 4988 if (parent.mParent instanceof View) { 4989 parent = (View) parent.mParent; 4990 } else { 4991 parent = null; 4992 } 4993 } 4994 if (!gone) { 4995 if (validLayoutRequesters == null) { 4996 validLayoutRequesters = new ArrayList<View>(); 4997 } 4998 validLayoutRequesters.add(view); 4999 } 5000 } 5001 } 5002 if (!secondLayoutRequests) { 5003 // If we're checking the layout flags, then we need to clean them up also 5004 for (int i = 0; i < numViewsRequestingLayout; ++i) { 5005 View view = layoutRequesters.get(i); 5006 while (view != null && 5007 (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) { 5008 view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT; 5009 if (view.mParent instanceof View) { 5010 view = (View) view.mParent; 5011 } else { 5012 view = null; 5013 } 5014 } 5015 } 5016 } 5017 layoutRequesters.clear(); 5018 return validLayoutRequesters; 5019 } 5020 5021 @Override requestTransparentRegion(View child)5022 public void requestTransparentRegion(View child) { 5023 // the test below should not fail unless someone is messing with us 5024 checkThread(); 5025 if (mView != child) { 5026 return; 5027 } 5028 5029 if ((mView.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) { 5030 mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS; 5031 // Need to make sure we re-evaluate the window attributes next 5032 // time around, to ensure the window has the correct format. 5033 mWindowAttributesChanged = true; 5034 } 5035 5036 // Always request layout to apply the latest transparent region. 5037 requestLayout(); 5038 } 5039 5040 /** 5041 * Figures out the measure spec for the root view in a window based on it's 5042 * layout params. 5043 * 5044 * @param windowSize The available width or height of the window. 5045 * @param measurement The layout width or height requested in the layout params. 5046 * @param privateFlags The private flags in the layout params of the window. 5047 * @return The measure spec to use to measure the root view. 5048 */ getRootMeasureSpec(int windowSize, int measurement, int privateFlags)5049 private static int getRootMeasureSpec(int windowSize, int measurement, int privateFlags) { 5050 int measureSpec; 5051 final int rootDimension = (privateFlags & PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT) != 0 5052 ? MATCH_PARENT : measurement; 5053 switch (rootDimension) { 5054 case ViewGroup.LayoutParams.MATCH_PARENT: 5055 // Window can't resize. Force root view to be windowSize. 5056 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY); 5057 break; 5058 case ViewGroup.LayoutParams.WRAP_CONTENT: 5059 // Window can resize. Set max size for root view. 5060 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST); 5061 break; 5062 default: 5063 // Window wants to be an exact size. Force root view to be that size. 5064 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY); 5065 break; 5066 } 5067 return measureSpec; 5068 } 5069 5070 int mHardwareXOffset; 5071 int mHardwareYOffset; 5072 5073 @Override onPreDraw(RecordingCanvas canvas)5074 public void onPreDraw(RecordingCanvas canvas) { 5075 // If mCurScrollY is not 0 then this influences the hardwareYOffset. The end result is we 5076 // can apply offsets that are not handled by anything else, resulting in underdraw as 5077 // the View is shifted (thus shifting the window background) exposing unpainted 5078 // content. To handle this with minimal glitches we just clear to BLACK if the window 5079 // is opaque. If it's not opaque then HWUI already internally does a glClear to 5080 // transparent, so there's no risk of underdraw on non-opaque surfaces. 5081 if (mCurScrollY != 0 && mHardwareYOffset != 0 && mAttachInfo.mThreadedRenderer.isOpaque()) { 5082 canvas.drawColor(Color.BLACK); 5083 } 5084 canvas.translate(-mHardwareXOffset, -mHardwareYOffset); 5085 } 5086 5087 @Override onPostDraw(RecordingCanvas canvas)5088 public void onPostDraw(RecordingCanvas canvas) { 5089 drawAccessibilityFocusedDrawableIfNeeded(canvas); 5090 if (mUseMTRenderer) { 5091 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { 5092 mWindowCallbacks.get(i).onPostDraw(canvas); 5093 } 5094 } 5095 } 5096 5097 /** 5098 * @hide 5099 */ outputDisplayList(View view)5100 void outputDisplayList(View view) { 5101 view.mRenderNode.output(); 5102 } 5103 5104 /** 5105 * @see #PROPERTY_PROFILE_RENDERING 5106 */ profileRendering(boolean enabled)5107 private void profileRendering(boolean enabled) { 5108 if (mProfileRendering) { 5109 mRenderProfilingEnabled = enabled; 5110 5111 if (mRenderProfiler != null) { 5112 mChoreographer.removeFrameCallback(mRenderProfiler); 5113 } 5114 if (mRenderProfilingEnabled) { 5115 if (mRenderProfiler == null) { 5116 mRenderProfiler = new Choreographer.FrameCallback() { 5117 @Override 5118 public void doFrame(long frameTimeNanos) { 5119 mDirty.set(0, 0, mWidth, mHeight); 5120 scheduleTraversals(); 5121 if (mRenderProfilingEnabled) { 5122 mChoreographer.postFrameCallback(mRenderProfiler); 5123 } 5124 } 5125 }; 5126 } 5127 mChoreographer.postFrameCallback(mRenderProfiler); 5128 } else { 5129 mRenderProfiler = null; 5130 } 5131 } 5132 } 5133 5134 /** 5135 * Called from draw() when DEBUG_FPS is enabled 5136 */ trackFPS()5137 private void trackFPS() { 5138 // Tracks frames per second drawn. First value in a series of draws may be bogus 5139 // because it down not account for the intervening idle time 5140 long nowTime = System.currentTimeMillis(); 5141 if (mFpsStartTime < 0) { 5142 mFpsStartTime = mFpsPrevTime = nowTime; 5143 mFpsNumFrames = 0; 5144 } else { 5145 ++mFpsNumFrames; 5146 String thisHash = Integer.toHexString(System.identityHashCode(this)); 5147 long frameTime = nowTime - mFpsPrevTime; 5148 long totalTime = nowTime - mFpsStartTime; 5149 Log.v(mTag, "0x" + thisHash + "\tFrame time:\t" + frameTime); 5150 mFpsPrevTime = nowTime; 5151 if (totalTime > 1000) { 5152 float fps = (float) mFpsNumFrames * 1000 / totalTime; 5153 Log.v(mTag, "0x" + thisHash + "\tFPS:\t" + fps); 5154 mFpsStartTime = nowTime; 5155 mFpsNumFrames = 0; 5156 } 5157 } 5158 } 5159 5160 /** 5161 * Called from draw() to collect metrics for frame rate decision. 5162 */ collectFrameRateDecisionMetrics()5163 private void collectFrameRateDecisionMetrics() { 5164 if (!Trace.isEnabled()) { 5165 if (mPreviousFrameDrawnTime > 0) mPreviousFrameDrawnTime = -1; 5166 return; 5167 } 5168 5169 if (mPreviousFrameDrawnTime < 0) { 5170 mPreviousFrameDrawnTime = mChoreographer.getExpectedPresentationTimeNanos(); 5171 return; 5172 } 5173 5174 long expectedDrawnTime = mChoreographer.getExpectedPresentationTimeNanos(); 5175 long timeDiff = expectedDrawnTime - mPreviousFrameDrawnTime; 5176 if (timeDiff <= 0) { 5177 return; 5178 } 5179 5180 long fps = NANOS_PER_SEC / timeDiff; 5181 Trace.setCounter(mFpsTraceName, fps); 5182 mPreviousFrameDrawnTime = expectedDrawnTime; 5183 5184 long percentage = (long) (mLargestChildPercentage * 100); 5185 Trace.setCounter(mLargestViewTraceName, percentage); 5186 mLargestChildPercentage = 0.0f; 5187 } 5188 reportDrawFinished(@ullable Transaction t, int seqId)5189 private void reportDrawFinished(@Nullable Transaction t, int seqId) { 5190 logAndTrace("reportDrawFinished seqId=" + seqId); 5191 try { 5192 mWindowSession.finishDrawing(mWindow, t, seqId); 5193 } catch (RemoteException e) { 5194 Log.e(mTag, "Unable to report draw finished", e); 5195 if (t != null) { 5196 t.apply(); 5197 } 5198 } finally { 5199 if (t != null) { 5200 t.clear(); 5201 } 5202 } 5203 } 5204 5205 /** 5206 * @hide 5207 */ isHardwareEnabled()5208 public boolean isHardwareEnabled() { 5209 return mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled(); 5210 } 5211 5212 /** 5213 * This VRI is currently in the middle of a sync request that was initiated by WMS. 5214 */ isInWMSRequestedSync()5215 public boolean isInWMSRequestedSync() { 5216 return mWmsRequestSyncGroup != null; 5217 } 5218 addFrameCommitCallbackIfNeeded()5219 private void addFrameCommitCallbackIfNeeded() { 5220 if (!isHardwareEnabled()) { 5221 return; 5222 } 5223 5224 ArrayList<Runnable> commitCallbacks = mAttachInfo.mTreeObserver 5225 .captureFrameCommitCallbacks(); 5226 final boolean needFrameCommitCallback = 5227 (commitCallbacks != null && commitCallbacks.size() > 0); 5228 if (!needFrameCommitCallback) { 5229 return; 5230 } 5231 5232 if (DEBUG_DRAW) { 5233 Log.d(mTag, "Creating frameCommitCallback" 5234 + " commitCallbacks size=" + commitCallbacks.size()); 5235 } 5236 mAttachInfo.mThreadedRenderer.setFrameCommitCallback(didProduceBuffer -> { 5237 if (DEBUG_DRAW) { 5238 Log.d(mTag, "Received frameCommitCallback didProduceBuffer=" + didProduceBuffer); 5239 } 5240 5241 mHandler.postAtFrontOfQueue(() -> { 5242 for (int i = 0; i < commitCallbacks.size(); i++) { 5243 commitCallbacks.get(i).run(); 5244 } 5245 }); 5246 }); 5247 } 5248 5249 /** 5250 * These callbacks check if the draw failed for any reason and apply 5251 * those transactions directly so they don't get stuck forever. 5252 */ registerCallbackForPendingTransactions()5253 private void registerCallbackForPendingTransactions() { 5254 Transaction t = new Transaction(); 5255 t.merge(mPendingTransaction); 5256 5257 registerRtFrameCallback(new FrameDrawingCallback() { 5258 @Override 5259 public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) { 5260 mergeWithNextTransaction(t, frame); 5261 if ((syncResult 5262 & (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) { 5263 mBlastBufferQueue.applyPendingTransactions(frame); 5264 return null; 5265 } 5266 5267 return didProduceBuffer -> { 5268 if (!didProduceBuffer) { 5269 logAndTrace("Transaction not synced due to no frame drawn"); 5270 mBlastBufferQueue.applyPendingTransactions(frame); 5271 } 5272 }; 5273 5274 } 5275 5276 @Override 5277 public void onFrameDraw(long frame) { 5278 } 5279 }); 5280 } 5281 performDraw(@ullable SurfaceSyncGroup surfaceSyncGroup)5282 private boolean performDraw(@Nullable SurfaceSyncGroup surfaceSyncGroup) { 5283 mLastPerformDrawSkippedReason = null; 5284 if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) { 5285 mLastPerformDrawSkippedReason = "screen_off"; 5286 if (!mLastDrawScreenOff) { 5287 logAndTrace("Not drawing due to screen off"); 5288 } 5289 mLastDrawScreenOff = true; 5290 return false; 5291 } else if (mView == null) { 5292 mLastPerformDrawSkippedReason = "no_root_view"; 5293 return false; 5294 } 5295 5296 if (mLastDrawScreenOff) { 5297 logAndTrace("Resumed drawing after screen turned on"); 5298 mLastDrawScreenOff = false; 5299 } 5300 5301 final boolean fullRedrawNeeded = mFullRedrawNeeded || surfaceSyncGroup != null; 5302 mFullRedrawNeeded = false; 5303 5304 mIsDrawing = true; 5305 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw-" + mTag); 5306 5307 addFrameCommitCallbackIfNeeded(); 5308 5309 boolean usingAsyncReport; 5310 5311 try { 5312 usingAsyncReport = draw(fullRedrawNeeded, surfaceSyncGroup, mSyncBuffer); 5313 if (mAttachInfo.mThreadedRenderer != null && !usingAsyncReport) { 5314 mAttachInfo.mThreadedRenderer.setFrameCallback(null); 5315 } 5316 } finally { 5317 mIsDrawing = false; 5318 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 5319 } 5320 5321 // For whatever reason we didn't create a HardwareRenderer, end any 5322 // hardware animations that are now dangling 5323 if (mAttachInfo.mPendingAnimatingRenderNodes != null) { 5324 final int count = mAttachInfo.mPendingAnimatingRenderNodes.size(); 5325 for (int i = 0; i < count; i++) { 5326 mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators(); 5327 } 5328 mAttachInfo.mPendingAnimatingRenderNodes.clear(); 5329 } 5330 5331 final Transaction pendingTransaction; 5332 if (!usingAsyncReport && mHasPendingTransactions) { 5333 pendingTransaction = new Transaction(); 5334 pendingTransaction.merge(mPendingTransaction); 5335 } else { 5336 pendingTransaction = null; 5337 } 5338 5339 if (mReportNextDraw) { 5340 // if we're using multi-thread renderer, wait for the window frame draws 5341 if (mWindowDrawCountDown != null) { 5342 try { 5343 mWindowDrawCountDown.await(); 5344 } catch (InterruptedException e) { 5345 Log.e(mTag, "Window redraw count down interrupted!"); 5346 } 5347 mWindowDrawCountDown = null; 5348 } 5349 5350 if (mAttachInfo.mThreadedRenderer != null) { 5351 mAttachInfo.mThreadedRenderer.setStopped(mStopped); 5352 } 5353 5354 if (LOCAL_LOGV) { 5355 Log.v(mTag, "FINISHED DRAWING: " + mWindowAttributes.getTitle()); 5356 } 5357 5358 if (mSurfaceHolder != null && mSurface.isValid()) { 5359 usingAsyncReport = true; 5360 SurfaceCallbackHelper sch = new SurfaceCallbackHelper(() -> { 5361 handleSyncRequestWhenNoAsyncDraw(surfaceSyncGroup, pendingTransaction != null, 5362 pendingTransaction, "SurfaceHolder"); 5363 }); 5364 5365 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); 5366 5367 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks); 5368 } else if (!usingAsyncReport) { 5369 if (mAttachInfo.mThreadedRenderer != null) { 5370 mAttachInfo.mThreadedRenderer.fence(); 5371 } 5372 } 5373 } 5374 5375 if (!usingAsyncReport) { 5376 handleSyncRequestWhenNoAsyncDraw(surfaceSyncGroup, pendingTransaction != null, 5377 pendingTransaction, "no async report"); 5378 } 5379 5380 if (mPerformContentCapture) { 5381 performContentCaptureInitialReport(); 5382 } 5383 return true; 5384 } 5385 handleSyncRequestWhenNoAsyncDraw(SurfaceSyncGroup surfaceSyncGroup, boolean hasPendingTransaction, @Nullable Transaction pendingTransaction, String logReason)5386 private void handleSyncRequestWhenNoAsyncDraw(SurfaceSyncGroup surfaceSyncGroup, 5387 boolean hasPendingTransaction, @Nullable Transaction pendingTransaction, 5388 String logReason) { 5389 if (surfaceSyncGroup != null) { 5390 if (hasPendingTransaction && pendingTransaction != null) { 5391 surfaceSyncGroup.addTransaction(pendingTransaction); 5392 } 5393 surfaceSyncGroup.markSyncReady(); 5394 } else if (hasPendingTransaction && pendingTransaction != null) { 5395 Trace.instant(Trace.TRACE_TAG_VIEW, 5396 "Transaction not synced due to " + logReason + "-" + mTag); 5397 if (DEBUG_BLAST) { 5398 Log.d(mTag, "Pending transaction will not be applied in sync with a draw due to " 5399 + logReason); 5400 } 5401 pendingTransaction.apply(); 5402 } 5403 } 5404 /** 5405 * Checks (and caches) if content capture is enabled for this context. 5406 */ isContentCaptureEnabled()5407 private boolean isContentCaptureEnabled() { 5408 switch (mContentCaptureEnabled) { 5409 case CONTENT_CAPTURE_ENABLED_TRUE: 5410 return true; 5411 case CONTENT_CAPTURE_ENABLED_FALSE: 5412 return false; 5413 case CONTENT_CAPTURE_ENABLED_NOT_CHECKED: 5414 final boolean reallyEnabled = isContentCaptureReallyEnabled(); 5415 mContentCaptureEnabled = reallyEnabled ? CONTENT_CAPTURE_ENABLED_TRUE 5416 : CONTENT_CAPTURE_ENABLED_FALSE; 5417 return reallyEnabled; 5418 default: 5419 Log.w(TAG, "isContentCaptureEnabled(): invalid state " + mContentCaptureEnabled); 5420 return false; 5421 } 5422 5423 } 5424 5425 /** 5426 * Checks (without caching) if content capture is enabled for this context. 5427 */ isContentCaptureReallyEnabled()5428 private boolean isContentCaptureReallyEnabled() { 5429 // First check if context supports it, so it saves a service lookup when it doesn't 5430 if (mContext.getContentCaptureOptions() == null) return false; 5431 5432 final ContentCaptureManager ccm = mAttachInfo.getContentCaptureManager(mContext); 5433 // Then check if it's enabled in the contex itself. 5434 if (ccm == null || !ccm.isContentCaptureEnabled()) return false; 5435 5436 return true; 5437 } 5438 performContentCaptureInitialReport()5439 private void performContentCaptureInitialReport() { 5440 mPerformContentCapture = false; // One-time offer! 5441 final View rootView = mView; 5442 if (DEBUG_CONTENT_CAPTURE) { 5443 Log.v(mTag, "performContentCaptureInitialReport() on " + rootView); 5444 } 5445 boolean traceDispatchCapture = false; 5446 try { 5447 if (!isContentCaptureEnabled()) return; 5448 5449 traceDispatchCapture = Trace.isTagEnabled(Trace.TRACE_TAG_VIEW); 5450 if (traceDispatchCapture) { 5451 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchContentCapture() for " 5452 + getClass().getSimpleName()); 5453 } 5454 5455 // Initial dispatch of window bounds to content capture 5456 if (mAttachInfo.mContentCaptureManager != null) { 5457 ContentCaptureSession session = 5458 mAttachInfo.mContentCaptureManager.getMainContentCaptureSession(); 5459 session.notifyWindowBoundsChanged(session.getId(), 5460 getConfiguration().windowConfiguration.getBounds()); 5461 } 5462 5463 // Content capture is a go! 5464 rootView.dispatchInitialProvideContentCaptureStructure(); 5465 } finally { 5466 if (traceDispatchCapture) { 5467 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 5468 } 5469 } 5470 } 5471 handleContentCaptureFlush()5472 private void handleContentCaptureFlush() { 5473 if (DEBUG_CONTENT_CAPTURE) { 5474 Log.v(mTag, "handleContentCaptureFlush()"); 5475 } 5476 boolean traceFlushContentCapture = false; 5477 try { 5478 if (!isContentCaptureEnabled()) return; 5479 5480 traceFlushContentCapture = Trace.isTagEnabled(Trace.TRACE_TAG_VIEW); 5481 if (traceFlushContentCapture) { 5482 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "flushContentCapture for " 5483 + getClass().getSimpleName()); 5484 } 5485 5486 final ContentCaptureManager ccm = mAttachInfo.mContentCaptureManager; 5487 if (ccm == null) { 5488 Log.w(TAG, "No ContentCapture on AttachInfo"); 5489 return; 5490 } 5491 ccm.flush(ContentCaptureSession.FLUSH_REASON_VIEW_ROOT_ENTERED); 5492 } finally { 5493 if (traceFlushContentCapture) { 5494 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 5495 } 5496 } 5497 } 5498 draw(boolean fullRedrawNeeded, @Nullable SurfaceSyncGroup activeSyncGroup, boolean syncBuffer)5499 private boolean draw(boolean fullRedrawNeeded, @Nullable SurfaceSyncGroup activeSyncGroup, 5500 boolean syncBuffer) { 5501 Surface surface = mSurface; 5502 if (!surface.isValid()) { 5503 return false; 5504 } 5505 5506 if (DEBUG_FPS) { 5507 trackFPS(); 5508 } 5509 5510 if (sToolkitMetricsForFrameRateDecisionFlagValue) { 5511 collectFrameRateDecisionMetrics(); 5512 } 5513 5514 if (!sFirstDrawComplete) { 5515 synchronized (sFirstDrawHandlers) { 5516 sFirstDrawComplete = true; 5517 final int count = sFirstDrawHandlers.size(); 5518 for (int i = 0; i< count; i++) { 5519 mHandler.post(sFirstDrawHandlers.get(i)); 5520 } 5521 } 5522 } 5523 5524 scrollToRectOrFocus(null, false); 5525 5526 if (mAttachInfo.mViewScrollChanged) { 5527 mAttachInfo.mViewScrollChanged = false; 5528 mAttachInfo.mTreeObserver.dispatchOnScrollChanged(); 5529 } 5530 5531 boolean animating = mScroller != null && mScroller.computeScrollOffset(); 5532 final int curScrollY; 5533 if (animating) { 5534 curScrollY = mScroller.getCurrY(); 5535 } else { 5536 curScrollY = mScrollY; 5537 } 5538 if (mCurScrollY != curScrollY) { 5539 mCurScrollY = curScrollY; 5540 fullRedrawNeeded = true; 5541 if (mView instanceof RootViewSurfaceTaker) { 5542 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY); 5543 } 5544 } 5545 5546 final float appScale = mAttachInfo.mApplicationScale; 5547 final boolean scalingRequired = mAttachInfo.mScalingRequired; 5548 5549 final Rect dirty = mDirty; 5550 if (mSurfaceHolder != null) { 5551 // The app owns the surface, we won't draw. 5552 dirty.setEmpty(); 5553 if (animating && mScroller != null) { 5554 mScroller.abortAnimation(); 5555 } 5556 return false; 5557 } 5558 5559 if (fullRedrawNeeded) { 5560 dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f)); 5561 } 5562 5563 if (DEBUG_ORIENTATION || DEBUG_DRAW) { 5564 Log.v(mTag, "Draw " + mView + "/" 5565 + mWindowAttributes.getTitle() 5566 + ": dirty={" + dirty.left + "," + dirty.top 5567 + "," + dirty.right + "," + dirty.bottom + "} surface=" 5568 + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" + 5569 appScale + ", width=" + mWidth + ", height=" + mHeight); 5570 } 5571 5572 mAttachInfo.mTreeObserver.dispatchOnDraw(); 5573 5574 int xOffset = -mCanvasOffsetX; 5575 int yOffset = -mCanvasOffsetY + curScrollY; 5576 final WindowManager.LayoutParams params = mWindowAttributes; 5577 final Rect surfaceInsets = params != null ? params.surfaceInsets : null; 5578 if (surfaceInsets != null) { 5579 xOffset -= surfaceInsets.left; 5580 yOffset -= surfaceInsets.top; 5581 5582 // Offset dirty rect for surface insets. 5583 dirty.offset(surfaceInsets.left, surfaceInsets.top); 5584 } 5585 5586 boolean accessibilityFocusDirty = isAccessibilityFocusDirty(); 5587 5588 // Force recalculation of transparent regions 5589 if (accessibilityFocusDirty) { 5590 final Rect bounds = mAttachInfo.mTmpInvalRect; 5591 if (getAccessibilityFocusedRect(bounds)) { 5592 requestLayout(); 5593 } 5594 } 5595 5596 mAttachInfo.mDrawingTime = 5597 mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS; 5598 5599 boolean useAsyncReport = false; 5600 if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) { 5601 if (isHardwareEnabled()) { 5602 // If accessibility focus moved, always invalidate the root. 5603 boolean invalidateRoot = accessibilityFocusDirty || mInvalidateRootRequested; 5604 mInvalidateRootRequested = false; 5605 5606 // Draw with hardware renderer. 5607 mIsAnimating = false; 5608 5609 if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) { 5610 mHardwareYOffset = yOffset; 5611 mHardwareXOffset = xOffset; 5612 invalidateRoot = true; 5613 } 5614 5615 if (invalidateRoot) { 5616 mAttachInfo.mThreadedRenderer.invalidateRoot(); 5617 } 5618 5619 dirty.setEmpty(); 5620 5621 // Stage the content drawn size now. It will be transferred to the renderer 5622 // shortly before the draw commands get send to the renderer. 5623 final boolean updated = updateContentDrawBounds(); 5624 5625 if (mReportNextDraw) { 5626 // report next draw overrides setStopped() 5627 // This value is re-sync'd to the value of mStopped 5628 // in the handling of mReportNextDraw post-draw. 5629 mAttachInfo.mThreadedRenderer.setStopped(false); 5630 } 5631 5632 if (updated) { 5633 requestDrawWindow(); 5634 } 5635 5636 useAsyncReport = true; 5637 5638 if (mHdrRenderState.updateForFrame(mAttachInfo.mDrawingTime)) { 5639 final float renderRatio = mHdrRenderState.getRenderHdrSdrRatio(); 5640 applyTransactionOnDraw(mTransaction.setExtendedRangeBrightness( 5641 getSurfaceControl(), renderRatio, 5642 mHdrRenderState.getDesiredHdrSdrRatio())); 5643 mAttachInfo.mThreadedRenderer.setTargetHdrSdrRatio(renderRatio); 5644 } 5645 5646 if (activeSyncGroup != null) { 5647 registerCallbacksForSync(syncBuffer, activeSyncGroup); 5648 if (syncBuffer) { 5649 mAttachInfo.mThreadedRenderer.forceDrawNextFrame(); 5650 } 5651 } else if (mHasPendingTransactions) { 5652 // Register a callback if there's no sync involved but there were calls to 5653 // applyTransactionOnDraw. If there is a sync involved, the sync callback will 5654 // handle merging the pending transaction. 5655 registerCallbackForPendingTransactions(); 5656 } 5657 5658 long timeNs = SystemClock.uptimeNanos(); 5659 mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this); 5660 5661 // Only trigger once per {@link ViewRootImpl} instance. 5662 if (mAppStartInfoTimestampsFlagValue && mRenderThreadDrawStartTimeNs == -1) { 5663 mRenderThreadDrawStartTimeNs = timeNs; 5664 } 5665 } else { 5666 // If we get here with a disabled & requested hardware renderer, something went 5667 // wrong (an invalidate posted right before we destroyed the hardware surface 5668 // for instance) so we should just bail out. Locking the surface with software 5669 // rendering at this point would lock it forever and prevent hardware renderer 5670 // from doing its job when it comes back. 5671 // Before we request a new frame we must however attempt to reinitiliaze the 5672 // hardware renderer if it's in requested state. This would happen after an 5673 // eglTerminate() for instance. 5674 if (mAttachInfo.mThreadedRenderer != null && 5675 !mAttachInfo.mThreadedRenderer.isEnabled() && 5676 mAttachInfo.mThreadedRenderer.isRequested() && 5677 mSurface.isValid()) { 5678 5679 try { 5680 mAttachInfo.mThreadedRenderer.initializeIfNeeded( 5681 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets); 5682 } catch (OutOfResourcesException e) { 5683 handleOutOfResourcesException(e); 5684 return false; 5685 } 5686 5687 mFullRedrawNeeded = true; 5688 scheduleTraversals(); 5689 return false; 5690 } 5691 5692 if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, 5693 scalingRequired, dirty, surfaceInsets)) { 5694 return false; 5695 } 5696 } 5697 } 5698 5699 if (animating) { 5700 mFullRedrawNeeded = true; 5701 scheduleTraversals(); 5702 } 5703 return useAsyncReport; 5704 } 5705 5706 /** 5707 * @return true if drawing was successful, false if an error occurred 5708 */ drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, boolean scalingRequired, Rect dirty, Rect surfaceInsets)5709 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, 5710 boolean scalingRequired, Rect dirty, Rect surfaceInsets) { 5711 5712 // Draw with software renderer. 5713 final Canvas canvas; 5714 5715 try { 5716 canvas = mSurface.lockCanvas(dirty); 5717 canvas.setDensity(mDensity); 5718 } catch (Surface.OutOfResourcesException e) { 5719 handleOutOfResourcesException(e); 5720 return false; 5721 } catch (IllegalArgumentException e) { 5722 Log.e(mTag, "Could not lock surface", e); 5723 // Don't assume this is due to out of memory, it could be 5724 // something else, and if it is something else then we could 5725 // kill stuff (or ourself) for no reason. 5726 mLayoutRequested = true; // ask wm for a new surface next time. 5727 return false; 5728 } 5729 5730 try { 5731 if (DEBUG_ORIENTATION || DEBUG_DRAW) { 5732 Log.v(mTag, "Surface " + surface + " drawing to bitmap w=" 5733 + canvas.getWidth() + ", h=" + canvas.getHeight() + ", dirty: " + dirty 5734 + ", xOff=" + xoff + ", yOff=" + yoff); 5735 //canvas.drawARGB(255, 255, 0, 0); 5736 } 5737 5738 // If this bitmap's format includes an alpha channel, we 5739 // need to clear it before drawing so that the child will 5740 // properly re-composite its drawing on a transparent 5741 // background. This automatically respects the clip/dirty region 5742 // or 5743 // If we are applying an offset, we need to clear the area 5744 // where the offset doesn't appear to avoid having garbage 5745 // left in the blank areas. 5746 if (!canvas.isOpaque() || yoff != 0 || xoff != 0) { 5747 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 5748 } 5749 5750 dirty.setEmpty(); 5751 mIsAnimating = false; 5752 mView.mPrivateFlags |= View.PFLAG_DRAWN; 5753 5754 if (DEBUG_DRAW) { 5755 Context cxt = mView.getContext(); 5756 Log.i(mTag, "Drawing: package:" + cxt.getPackageName() + 5757 ", metrics=" + cxt.getResources().getDisplayMetrics() + 5758 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo()); 5759 } 5760 canvas.translate(-xoff, -yoff); 5761 if (mTranslator != null) { 5762 mTranslator.translateCanvas(canvas); 5763 } 5764 canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0); 5765 5766 mView.draw(canvas); 5767 5768 drawAccessibilityFocusedDrawableIfNeeded(canvas); 5769 } finally { 5770 try { 5771 surface.unlockCanvasAndPost(canvas); 5772 } catch (IllegalArgumentException e) { 5773 Log.e(mTag, "Could not unlock surface", e); 5774 mLayoutRequested = true; // ask wm for a new surface next time. 5775 //noinspection ReturnInsideFinallyBlock 5776 return false; 5777 } 5778 5779 if (LOCAL_LOGV) { 5780 Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost"); 5781 } 5782 } 5783 return true; 5784 } 5785 5786 /** 5787 * We want to draw a highlight around the current accessibility focused. 5788 * Since adding a style for all possible view is not a viable option we 5789 * have this specialized drawing method. 5790 * 5791 * Note: We are doing this here to be able to draw the highlight for 5792 * virtual views in addition to real ones. 5793 * 5794 * Note: A round accessibility focus border is drawn on rounded watch 5795 * 5796 * Note: Need to set bounds of accessibility focused drawable before drawing on rounded watch, 5797 * so that when accessibility focus moved, root will be invalidated at 5798 * {@link #draw(boolean, SurfaceSyncGroup, boolean)} and accessibility focus border will be 5799 * updated. 5800 * 5801 * @param canvas The canvas on which to draw. 5802 */ drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas)5803 private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) { 5804 final Rect bounds = mAttachInfo.mTmpInvalRect; 5805 if (getAccessibilityFocusedRect(bounds)) { 5806 boolean isRoundWatch = mContext.getResources().getConfiguration().isScreenRound() 5807 && mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH); 5808 final Drawable drawable = getAccessibilityFocusedDrawable(); 5809 if (drawable != null) { 5810 drawable.setBounds(bounds); 5811 drawable.draw(canvas); 5812 if (mDisplay != null && isRoundWatch) { 5813 // Draw an extra round accessibility focus border on round watch 5814 drawAccessibilityFocusedBorderOnRoundDisplay(canvas, bounds, 5815 getRoundDisplayRadius(), getRoundDisplayAccessibilityHighlightPaint()); 5816 } 5817 } 5818 } else if (mAttachInfo.mAccessibilityFocusDrawable != null) { 5819 mAttachInfo.mAccessibilityFocusDrawable.setBounds(0, 0, 0, 0); 5820 } 5821 } 5822 getRoundDisplayRadius()5823 private int getRoundDisplayRadius() { 5824 Point displaySize = new Point(); 5825 mDisplay.getRealSize(displaySize); 5826 return displaySize.x / 2; 5827 } 5828 getRoundDisplayAccessibilityHighlightPaint()5829 private Paint getRoundDisplayAccessibilityHighlightPaint() { 5830 // Lazily create the round display accessibility highlight paint. 5831 if (mRoundDisplayAccessibilityHighlightPaint == null) { 5832 mRoundDisplayAccessibilityHighlightPaint = new Paint(); 5833 mRoundDisplayAccessibilityHighlightPaint.setStyle(Paint.Style.STROKE); 5834 mRoundDisplayAccessibilityHighlightPaint.setAntiAlias(true); 5835 } 5836 mRoundDisplayAccessibilityHighlightPaint.setStrokeWidth( 5837 mAccessibilityManager.getAccessibilityFocusStrokeWidth()); 5838 mRoundDisplayAccessibilityHighlightPaint.setColor( 5839 mAccessibilityManager.getAccessibilityFocusColor()); 5840 return mRoundDisplayAccessibilityHighlightPaint; 5841 } 5842 drawAccessibilityFocusedBorderOnRoundDisplay(Canvas canvas, Rect bounds, int roundDisplayRadius, Paint accessibilityFocusHighlightPaint)5843 private void drawAccessibilityFocusedBorderOnRoundDisplay(Canvas canvas, Rect bounds, 5844 int roundDisplayRadius, Paint accessibilityFocusHighlightPaint) { 5845 int saveCount = canvas.save(); 5846 canvas.clipRect(bounds); 5847 canvas.drawCircle(/* cx= */ roundDisplayRadius, 5848 /* cy= */ roundDisplayRadius, 5849 /* radius= */ roundDisplayRadius 5850 - mAccessibilityManager.getAccessibilityFocusStrokeWidth() / 2.0f, 5851 accessibilityFocusHighlightPaint); 5852 canvas.restoreToCount(saveCount); 5853 } 5854 getAccessibilityFocusedRect(Rect bounds)5855 private boolean getAccessibilityFocusedRect(Rect bounds) { 5856 if (mView == null) { 5857 Slog.w(TAG, "calling getAccessibilityFocusedRect() while the mView is null"); 5858 return false; 5859 } 5860 if (!mAccessibilityManager.isEnabled() 5861 || !mAccessibilityManager.isTouchExplorationEnabled()) { 5862 return false; 5863 } 5864 5865 final View host = mAccessibilityFocusedHost; 5866 if (host == null || host.mAttachInfo == null) { 5867 return false; 5868 } 5869 5870 final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider(); 5871 if (provider == null) { 5872 host.getBoundsOnScreen(bounds, true); 5873 } else if (mAccessibilityFocusedVirtualView != null) { 5874 mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds); 5875 } else { 5876 return false; 5877 } 5878 5879 // Transform the rect into window-relative coordinates. 5880 final AttachInfo attachInfo = mAttachInfo; 5881 bounds.offset(0, attachInfo.mViewRootImpl.mScrollY); 5882 bounds.offset(-attachInfo.mWindowLeft, -attachInfo.mWindowTop); 5883 if (!bounds.intersect(0, 0, attachInfo.mViewRootImpl.mWidth, 5884 attachInfo.mViewRootImpl.mHeight)) { 5885 // If no intersection, set bounds to empty. 5886 bounds.setEmpty(); 5887 } 5888 return !bounds.isEmpty(); 5889 } 5890 getAccessibilityFocusedDrawable()5891 private Drawable getAccessibilityFocusedDrawable() { 5892 // Lazily load the accessibility focus drawable. 5893 if (mAttachInfo.mAccessibilityFocusDrawable == null) { 5894 final TypedValue value = new TypedValue(); 5895 final boolean resolved = mView.mContext.getTheme().resolveAttribute( 5896 R.attr.accessibilityFocusedDrawable, value, true); 5897 if (resolved) { 5898 mAttachInfo.mAccessibilityFocusDrawable = 5899 mView.mContext.getDrawable(value.resourceId); 5900 } 5901 } 5902 // Sets the focus appearance data into the accessibility focus drawable. 5903 if (mAttachInfo.mAccessibilityFocusDrawable instanceof GradientDrawable) { 5904 final GradientDrawable drawable = 5905 (GradientDrawable) mAttachInfo.mAccessibilityFocusDrawable; 5906 drawable.setStroke(mAccessibilityManager.getAccessibilityFocusStrokeWidth(), 5907 mAccessibilityManager.getAccessibilityFocusColor()); 5908 } 5909 5910 return mAttachInfo.mAccessibilityFocusDrawable; 5911 } 5912 updateSystemGestureExclusionRectsForView(View view)5913 void updateSystemGestureExclusionRectsForView(View view) { 5914 mGestureExclusionTracker.updateRectsForView(view); 5915 mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED); 5916 } 5917 systemGestureExclusionChanged()5918 void systemGestureExclusionChanged() { 5919 final List<Rect> rectsForWindowManager = mGestureExclusionTracker.computeChangedRects(); 5920 if (rectsForWindowManager != null && mView != null) { 5921 try { 5922 mWindowSession.reportSystemGestureExclusionChanged(mWindow, rectsForWindowManager); 5923 } catch (RemoteException e) { 5924 throw e.rethrowFromSystemServer(); 5925 } 5926 mAttachInfo.mTreeObserver 5927 .dispatchOnSystemGestureExclusionRectsChanged(rectsForWindowManager); 5928 } 5929 } 5930 5931 /** 5932 * Called from DecorView when gesture interception state has changed. 5933 * 5934 * @param intercepted If DecorView is intercepting touch events 5935 */ updateDecorViewGestureInterception(boolean intercepted)5936 public void updateDecorViewGestureInterception(boolean intercepted) { 5937 mHandler.sendMessage( 5938 mHandler.obtainMessage( 5939 MSG_DECOR_VIEW_GESTURE_INTERCEPTION, 5940 /* arg1= */ intercepted ? 1 : 0, 5941 /* arg2= */ 0)); 5942 } 5943 decorViewInterceptionChanged(boolean intercepted)5944 void decorViewInterceptionChanged(boolean intercepted) { 5945 if (mView != null) { 5946 try { 5947 mWindowSession.reportDecorViewGestureInterceptionChanged(mWindow, intercepted); 5948 } catch (RemoteException e) { 5949 throw e.rethrowFromSystemServer(); 5950 } 5951 } 5952 } 5953 5954 /** 5955 * Set the root-level system gesture exclusion rects. These are added to those provided by 5956 * the root's view hierarchy. 5957 */ setRootSystemGestureExclusionRects(@onNull List<Rect> rects)5958 public void setRootSystemGestureExclusionRects(@NonNull List<Rect> rects) { 5959 mGestureExclusionTracker.setRootRects(rects); 5960 mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED); 5961 } 5962 5963 /** 5964 * Returns the root-level system gesture exclusion rects. These do not include those provided by 5965 * the root's view hierarchy. 5966 */ 5967 @NonNull getRootSystemGestureExclusionRects()5968 public List<Rect> getRootSystemGestureExclusionRects() { 5969 return mGestureExclusionTracker.getRootRects(); 5970 } 5971 5972 /** 5973 * Called from View when the position listener is triggered 5974 */ updateKeepClearRectsForView(View view)5975 void updateKeepClearRectsForView(View view) { 5976 mKeepClearRectsTracker.updateRectsForView(view); 5977 mUnrestrictedKeepClearRectsTracker.updateRectsForView(view); 5978 mHandler.sendEmptyMessage(MSG_KEEP_CLEAR_RECTS_CHANGED); 5979 } 5980 updateKeepClearForAccessibilityFocusRect()5981 private void updateKeepClearForAccessibilityFocusRect() { 5982 if (mViewConfiguration.isPreferKeepClearForFocusEnabled()) { 5983 if (mKeepClearAccessibilityFocusRect == null) { 5984 mKeepClearAccessibilityFocusRect = new Rect(); 5985 } 5986 boolean hasAccessibilityFocus = 5987 getAccessibilityFocusedRect(mKeepClearAccessibilityFocusRect); 5988 if (!hasAccessibilityFocus) { 5989 mKeepClearAccessibilityFocusRect.setEmpty(); 5990 } 5991 mHandler.obtainMessage(MSG_KEEP_CLEAR_RECTS_CHANGED, 1, 0).sendToTarget(); 5992 } 5993 } 5994 keepClearRectsChanged(boolean accessibilityFocusRectChanged)5995 void keepClearRectsChanged(boolean accessibilityFocusRectChanged) { 5996 boolean restrictedKeepClearRectsChanged = mKeepClearRectsTracker.computeChanges(); 5997 boolean unrestrictedKeepClearRectsChanged = 5998 mUnrestrictedKeepClearRectsTracker.computeChanges(); 5999 6000 if ((restrictedKeepClearRectsChanged || unrestrictedKeepClearRectsChanged 6001 || accessibilityFocusRectChanged) && mView != null) { 6002 mHasPendingKeepClearAreaChange = true; 6003 // Only report keep clear areas immediately if they have not been reported recently 6004 if (!mHandler.hasMessages(MSG_REPORT_KEEP_CLEAR_RECTS)) { 6005 mHandler.sendEmptyMessageDelayed(MSG_REPORT_KEEP_CLEAR_RECTS, 6006 KEEP_CLEAR_AREA_REPORT_RATE_MILLIS); 6007 reportKeepClearAreasChanged(); 6008 } 6009 } 6010 } 6011 reportKeepClearAreasChanged()6012 void reportKeepClearAreasChanged() { 6013 if (!mHasPendingKeepClearAreaChange || mView == null) { 6014 return; 6015 } 6016 mHasPendingKeepClearAreaChange = false; 6017 6018 List<Rect> restrictedKeepClearRects = mKeepClearRectsTracker.getLastComputedRects(); 6019 final List<Rect> unrestrictedKeepClearRects = 6020 mUnrestrictedKeepClearRectsTracker.getLastComputedRects(); 6021 6022 if (mKeepClearAccessibilityFocusRect != null 6023 && !mKeepClearAccessibilityFocusRect.isEmpty()) { 6024 restrictedKeepClearRects = new ArrayList<>(restrictedKeepClearRects); 6025 restrictedKeepClearRects.add(mKeepClearAccessibilityFocusRect); 6026 } 6027 6028 try { 6029 mWindowSession.reportKeepClearAreasChanged(mWindow, restrictedKeepClearRects, 6030 unrestrictedKeepClearRects); 6031 } catch (RemoteException e) { 6032 throw e.rethrowFromSystemServer(); 6033 } 6034 } 6035 6036 /** 6037 * Requests that the root render node is invalidated next time we perform a draw, such that 6038 * {@link WindowCallbacks#onPostDraw} gets called. 6039 */ requestInvalidateRootRenderNode()6040 public void requestInvalidateRootRenderNode() { 6041 mInvalidateRootRequested = true; 6042 } 6043 scrollToRectOrFocus(Rect rectangle, boolean immediate)6044 boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) { 6045 final Rect ci = mAttachInfo.mContentInsets; 6046 final Rect vi = mAttachInfo.mVisibleInsets; 6047 int scrollY = 0; 6048 boolean handled = false; 6049 6050 if (vi.left > ci.left || vi.top > ci.top 6051 || vi.right > ci.right || vi.bottom > ci.bottom) { 6052 // We'll assume that we aren't going to change the scroll 6053 // offset, since we want to avoid that unless it is actually 6054 // going to make the focus visible... otherwise we scroll 6055 // all over the place. 6056 scrollY = mScrollY; 6057 // We can be called for two different situations: during a draw, 6058 // to update the scroll position if the focus has changed (in which 6059 // case 'rectangle' is null), or in response to a 6060 // requestChildRectangleOnScreen() call (in which case 'rectangle' 6061 // is non-null and we just want to scroll to whatever that 6062 // rectangle is). 6063 final View focus = mView.findFocus(); 6064 if (focus == null) { 6065 return false; 6066 } 6067 View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null; 6068 if (focus != lastScrolledFocus) { 6069 // If the focus has changed, then ignore any requests to scroll 6070 // to a rectangle; first we want to make sure the entire focus 6071 // view is visible. 6072 rectangle = null; 6073 } 6074 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Eval scroll: focus=" + focus 6075 + " rectangle=" + rectangle + " ci=" + ci 6076 + " vi=" + vi); 6077 if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) { 6078 // Optimization: if the focus hasn't changed since last 6079 // time, and no layout has happened, then just leave things 6080 // as they are. 6081 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Keeping scroll y=" 6082 + mScrollY + " vi=" + vi.toShortString()); 6083 } else { 6084 // We need to determine if the currently focused view is 6085 // within the visible part of the window and, if not, apply 6086 // a pan so it can be seen. 6087 mLastScrolledFocus = new WeakReference<View>(focus); 6088 mScrollMayChange = false; 6089 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Need to scroll?"); 6090 // Try to find the rectangle from the focus view. 6091 if (focus.getGlobalVisibleRect(mVisRect, null)) { 6092 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Root w=" 6093 + mView.getWidth() + " h=" + mView.getHeight() 6094 + " ci=" + ci.toShortString() 6095 + " vi=" + vi.toShortString()); 6096 if (rectangle == null) { 6097 focus.getFocusedRect(mTempRect); 6098 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Focus " + focus 6099 + ": focusRect=" + mTempRect.toShortString()); 6100 if (mView instanceof ViewGroup) { 6101 ((ViewGroup) mView).offsetDescendantRectToMyCoords( 6102 focus, mTempRect); 6103 } 6104 if (DEBUG_INPUT_RESIZE) Log.v(mTag, 6105 "Focus in window: focusRect=" 6106 + mTempRect.toShortString() 6107 + " visRect=" + mVisRect.toShortString()); 6108 } else { 6109 mTempRect.set(rectangle); 6110 if (DEBUG_INPUT_RESIZE) Log.v(mTag, 6111 "Request scroll to rect: " 6112 + mTempRect.toShortString() 6113 + " visRect=" + mVisRect.toShortString()); 6114 } 6115 if (mTempRect.intersect(mVisRect)) { 6116 if (DEBUG_INPUT_RESIZE) Log.v(mTag, 6117 "Focus window visible rect: " 6118 + mTempRect.toShortString()); 6119 if (mTempRect.height() > 6120 (mView.getHeight()-vi.top-vi.bottom)) { 6121 // If the focus simply is not going to fit, then 6122 // best is probably just to leave things as-is. 6123 if (DEBUG_INPUT_RESIZE) Log.v(mTag, 6124 "Too tall; leaving scrollY=" + scrollY); 6125 } 6126 // Next, check whether top or bottom is covered based on the non-scrolled 6127 // position, and calculate new scrollY (or set it to 0). 6128 // We can't keep using mScrollY here. For example mScrollY is non-zero 6129 // due to IME, then IME goes away. The current value of mScrollY leaves top 6130 // and bottom both visible, but we still need to scroll it back to 0. 6131 else if (mTempRect.top < vi.top) { 6132 scrollY = mTempRect.top - vi.top; 6133 if (DEBUG_INPUT_RESIZE) Log.v(mTag, 6134 "Top covered; scrollY=" + scrollY); 6135 } else if (mTempRect.bottom > (mView.getHeight()-vi.bottom)) { 6136 scrollY = mTempRect.bottom - (mView.getHeight()-vi.bottom); 6137 if (DEBUG_INPUT_RESIZE) Log.v(mTag, 6138 "Bottom covered; scrollY=" + scrollY); 6139 } else { 6140 scrollY = 0; 6141 } 6142 handled = true; 6143 } 6144 } 6145 } 6146 } 6147 6148 if (scrollY != mScrollY) { 6149 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Pan scroll changed: old=" 6150 + mScrollY + " , new=" + scrollY); 6151 if (!immediate) { 6152 if (mScroller == null) { 6153 mScroller = new Scroller(mView.getContext()); 6154 } 6155 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY); 6156 } else if (mScroller != null) { 6157 mScroller.abortAnimation(); 6158 } 6159 mScrollY = scrollY; 6160 } 6161 6162 return handled; 6163 } 6164 6165 @VisibleForTesting(visibility = PACKAGE) setScrollY(int scrollY)6166 public void setScrollY(int scrollY) { 6167 if (mScroller != null) { 6168 mScroller.abortAnimation(); 6169 } 6170 mScrollY = scrollY; 6171 } 6172 6173 @VisibleForTesting getScrollY()6174 public int getScrollY() { 6175 return mScrollY; 6176 } 6177 6178 /** 6179 * @hide 6180 */ 6181 @UnsupportedAppUsage getAccessibilityFocusedHost()6182 public View getAccessibilityFocusedHost() { 6183 return mAccessibilityFocusedHost; 6184 } 6185 6186 /** 6187 * Get accessibility-focused virtual view. The bounds and sourceNodeId of the returned node is 6188 * up-to-date while other fields may be stale. 6189 * 6190 * @hide 6191 */ 6192 @UnsupportedAppUsage getAccessibilityFocusedVirtualView()6193 public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() { 6194 return mAccessibilityFocusedVirtualView; 6195 } 6196 setAccessibilityFocus(View view, AccessibilityNodeInfo node)6197 void setAccessibilityFocus(View view, AccessibilityNodeInfo node) { 6198 // If we have a virtual view with accessibility focus we need 6199 // to clear the focus and invalidate the virtual view bounds. 6200 if (mAccessibilityFocusedVirtualView != null) { 6201 6202 AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView; 6203 View focusHost = mAccessibilityFocusedHost; 6204 6205 // Wipe the state of the current accessibility focus since 6206 // the call into the provider to clear accessibility focus 6207 // will fire an accessibility event which will end up calling 6208 // this method and we want to have clean state when this 6209 // invocation happens. 6210 mAccessibilityFocusedHost = null; 6211 mAccessibilityFocusedVirtualView = null; 6212 6213 // Clear accessibility focus on the host after clearing state since 6214 // this method may be reentrant. 6215 focusHost.clearAccessibilityFocusNoCallbacks( 6216 AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 6217 6218 AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider(); 6219 if (provider != null) { 6220 // Invalidate the area of the cleared accessibility focus. 6221 focusNode.getBoundsInParent(mTempRect); 6222 focusHost.invalidate(mTempRect); 6223 // Clear accessibility focus in the virtual node. 6224 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId( 6225 focusNode.getSourceNodeId()); 6226 provider.performAction(virtualNodeId, 6227 AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null); 6228 } 6229 focusNode.recycle(); 6230 } 6231 if ((mAccessibilityFocusedHost != null) && (mAccessibilityFocusedHost != view)) { 6232 // Clear accessibility focus in the view. 6233 mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks( 6234 AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 6235 } 6236 6237 // Set the new focus host and node. 6238 mAccessibilityFocusedHost = view; 6239 mAccessibilityFocusedVirtualView = node; 6240 updateKeepClearForAccessibilityFocusRect(); 6241 6242 requestInvalidateRootRenderNode(); 6243 if (isAccessibilityFocusDirty()) { 6244 scheduleTraversals(); 6245 } 6246 } 6247 hasPointerCapture()6248 boolean hasPointerCapture() { 6249 return mPointerCapture; 6250 } 6251 requestPointerCapture(boolean enabled)6252 void requestPointerCapture(boolean enabled) { 6253 final IBinder inputToken = getInputToken(); 6254 if (inputToken == null) { 6255 Log.e(mTag, "No input channel to request Pointer Capture."); 6256 return; 6257 } 6258 InputManagerGlobal 6259 .getInstance() 6260 .requestPointerCapture(inputToken, enabled); 6261 } 6262 handlePointerCaptureChanged(boolean hasCapture)6263 private void handlePointerCaptureChanged(boolean hasCapture) { 6264 if (mPointerCapture == hasCapture) { 6265 return; 6266 } 6267 mPointerCapture = hasCapture; 6268 if (mView != null) { 6269 mView.dispatchPointerCaptureChanged(hasCapture); 6270 } 6271 } 6272 updateColorModeIfNeeded(@ctivityInfo.ColorMode int colorMode, float desiredRatio)6273 private void updateColorModeIfNeeded(@ActivityInfo.ColorMode int colorMode, 6274 float desiredRatio) { 6275 if (mAttachInfo.mThreadedRenderer == null) { 6276 return; 6277 } 6278 boolean isHdr = colorMode == ActivityInfo.COLOR_MODE_HDR 6279 || colorMode == ActivityInfo.COLOR_MODE_HDR10; 6280 if (isHdr && !mDisplay.isHdrSdrRatioAvailable()) { 6281 colorMode = ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT; 6282 isHdr = false; 6283 } 6284 // TODO: Centralize this sanitization? Why do we let setting bad modes? 6285 // Alternatively, can we just let HWUI figure it out? Do we need to care here? 6286 if (colorMode != ActivityInfo.COLOR_MODE_A8 6287 && !getConfiguration().isScreenWideColorGamut()) { 6288 colorMode = ActivityInfo.COLOR_MODE_DEFAULT; 6289 } 6290 float automaticRatio = mAttachInfo.mThreadedRenderer.setColorMode(colorMode); 6291 if (desiredRatio == 0 || desiredRatio > automaticRatio) { 6292 desiredRatio = automaticRatio; 6293 } 6294 6295 mHdrRenderState.setDesiredHdrSdrRatio(isHdr, desiredRatio); 6296 } 6297 6298 @Override requestChildFocus(View child, View focused)6299 public void requestChildFocus(View child, View focused) { 6300 if (DEBUG_INPUT_RESIZE) { 6301 Log.v(mTag, "Request child focus: focus now " + focused); 6302 } 6303 checkThread(); 6304 scheduleTraversals(); 6305 } 6306 6307 @Override clearChildFocus(View child)6308 public void clearChildFocus(View child) { 6309 if (DEBUG_INPUT_RESIZE) { 6310 Log.v(mTag, "Clearing child focus"); 6311 } 6312 checkThread(); 6313 scheduleTraversals(); 6314 } 6315 6316 @Override getParentForAccessibility()6317 public ViewParent getParentForAccessibility() { 6318 return null; 6319 } 6320 6321 @Override focusableViewAvailable(View v)6322 public void focusableViewAvailable(View v) { 6323 checkThread(); 6324 if (mView != null) { 6325 if (!mView.hasFocus()) { 6326 if (sAlwaysAssignFocus || !mAttachInfo.mInTouchMode) { 6327 v.requestFocus(); 6328 } 6329 } else { 6330 // the one case where will transfer focus away from the current one 6331 // is if the current view is a view group that prefers to give focus 6332 // to its children first AND the view is a descendant of it. 6333 View focused = mView.findFocus(); 6334 if (focused instanceof ViewGroup) { 6335 ViewGroup group = (ViewGroup) focused; 6336 if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS 6337 && isViewDescendantOf(v, focused)) { 6338 v.requestFocus(); 6339 } 6340 } 6341 } 6342 } 6343 } 6344 6345 @Override recomputeViewAttributes(View child)6346 public void recomputeViewAttributes(View child) { 6347 checkThread(); 6348 if (mView == child) { 6349 mAttachInfo.mRecomputeGlobalAttributes = true; 6350 if (!mWillDrawSoon) { 6351 scheduleTraversals(); 6352 } 6353 } 6354 } 6355 dispatchDetachedFromWindow()6356 void dispatchDetachedFromWindow() { 6357 // Make sure we free-up insets resources if view never received onWindowFocusLost() 6358 // because of a die-signal 6359 mInsetsController.onWindowFocusLost(); 6360 mFirstInputStage.onDetachedFromWindow(); 6361 if (mView != null && mView.mAttachInfo != null) { 6362 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false); 6363 mView.dispatchDetachedFromWindow(); 6364 } 6365 6366 mAccessibilityInteractionConnectionManager.ensureNoConnection(); 6367 mAccessibilityInteractionConnectionManager.ensureNoDirectConnection(); 6368 removeSendWindowContentChangedCallback(); 6369 if (android.view.accessibility.Flags.preventLeakingViewrootimpl() 6370 && mAccessibilityInteractionController != null) { 6371 mAccessibilityInteractionController.destroy(); 6372 mAccessibilityInteractionController = null; 6373 } 6374 6375 destroyHardwareRenderer(); 6376 6377 setAccessibilityFocus(null, null); 6378 6379 mInsetsController.cancelExistingAnimations(); 6380 6381 mView.assignParent(null); 6382 mView = null; 6383 mAttachInfo.mRootView = null; 6384 6385 destroySurface(); 6386 6387 if (mInputQueueCallback != null && mInputQueue != null) { 6388 mInputQueueCallback.onInputQueueDestroyed(mInputQueue); 6389 mInputQueue.dispose(); 6390 mInputQueueCallback = null; 6391 mInputQueue = null; 6392 } 6393 try { 6394 mWindowSession.remove(mWindow.asBinder()); 6395 } catch (RemoteException e) { 6396 } 6397 // Dispose receiver would dispose client InputChannel, too. That could send out a socket 6398 // broken event, so we need to unregister the server InputChannel when removing window to 6399 // prevent server side receive the event and prompt error. 6400 if (mInputEventReceiver != null) { 6401 mInputEventReceiver.dispose(); 6402 mInputEventReceiver = null; 6403 } 6404 6405 unregisterListeners(); 6406 unscheduleTraversals(); 6407 } 6408 6409 /** 6410 * Notifies all callbacks that configuration and/or display has changed and updates internal 6411 * state. 6412 * @param mergedConfiguration New global and override config in {@link MergedConfiguration} 6413 * container. 6414 * @param force Flag indicating if we should force apply the config. 6415 * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} if not 6416 * changed. 6417 * @param activityWindowInfo New activity window info. {@code null} if it is non-app window, or 6418 * this is not a Configuration change to the activity window (global). 6419 */ performConfigurationChange(@onNull MergedConfiguration mergedConfiguration, boolean force, int newDisplayId, @Nullable ActivityWindowInfo activityWindowInfo)6420 private void performConfigurationChange(@NonNull MergedConfiguration mergedConfiguration, 6421 boolean force, int newDisplayId, @Nullable ActivityWindowInfo activityWindowInfo) { 6422 if (mergedConfiguration == null) { 6423 throw new IllegalArgumentException("No merged config provided."); 6424 } 6425 6426 final int lastRotation = mLastReportedMergedConfiguration.getMergedConfiguration() 6427 .windowConfiguration.getRotation(); 6428 final int newRotation = mergedConfiguration.getMergedConfiguration() 6429 .windowConfiguration.getRotation(); 6430 if (lastRotation != newRotation) { 6431 // Trigger ThreadedRenderer#updateSurface() if the surface control doesn't change. 6432 // Because even if the actual surface size is not changed, e.g. flip 180 degrees, 6433 // the buffers may still have content in previous rotation. And the next draw may 6434 // not update all regions, that causes some afterimages to flicker. 6435 mUpdateSurfaceNeeded = true; 6436 if (!mIsInTraversal) { 6437 mForceNextWindowRelayout = true; 6438 } 6439 } 6440 6441 Configuration globalConfig = mergedConfiguration.getGlobalConfiguration(); 6442 final Configuration overrideConfig = mergedConfiguration.getOverrideConfiguration(); 6443 if (DEBUG_CONFIGURATION) Log.v(mTag, 6444 "Applying new config to window " + mWindowAttributes.getTitle() 6445 + ", globalConfig: " + globalConfig 6446 + ", overrideConfig: " + overrideConfig); 6447 6448 final CompatibilityInfo ci = mDisplay.getDisplayAdjustments().getCompatibilityInfo(); 6449 if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) { 6450 globalConfig = new Configuration(globalConfig); 6451 ci.applyToConfiguration(mNoncompatDensity, globalConfig); 6452 } 6453 6454 synchronized (sConfigCallbacks) { 6455 for (int i=sConfigCallbacks.size()-1; i>=0; i--) { 6456 sConfigCallbacks.get(i).onConfigurationChanged(globalConfig); 6457 } 6458 } 6459 6460 mLastReportedMergedConfiguration.setConfiguration(globalConfig, overrideConfig); 6461 if (mLastReportedActivityWindowInfo != null && activityWindowInfo != null) { 6462 mLastReportedActivityWindowInfo.set(activityWindowInfo); 6463 } 6464 6465 mForceNextConfigUpdate = force; 6466 if (mActivityConfigCallback != null) { 6467 // An activity callback is set - notify it about override configuration update. 6468 // This basically initiates a round trip to ActivityThread and back, which will ensure 6469 // that corresponding activity and resources are updated before updating inner state of 6470 // ViewRootImpl. Eventually it will call #updateConfiguration(). 6471 mActivityConfigCallback.onConfigurationChanged(overrideConfig, newDisplayId, 6472 activityWindowInfo); 6473 } else { 6474 // There is no activity callback - update the configuration right away. 6475 updateConfiguration(newDisplayId); 6476 } 6477 mForceNextConfigUpdate = false; 6478 } 6479 6480 /** 6481 * Update display and views if last applied merged configuration changed. 6482 * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} otherwise. 6483 */ updateConfiguration(int newDisplayId)6484 public void updateConfiguration(int newDisplayId) { 6485 if (mView == null) { 6486 return; 6487 } 6488 6489 // At this point the resources have been updated to 6490 // have the most recent config, whatever that is. Use 6491 // the one in them which may be newer. 6492 final Resources localResources = mView.getResources(); 6493 final Configuration config = localResources.getConfiguration(); 6494 6495 // Handle move to display. 6496 if (newDisplayId != INVALID_DISPLAY) { 6497 onMovedToDisplay(newDisplayId, config); 6498 } 6499 6500 // Handle configuration change. 6501 if (mForceNextConfigUpdate || mLastConfigurationFromResources.diff(config) != 0) { 6502 // Update the display with new DisplayAdjustments. 6503 updateInternalDisplay(mDisplay.getDisplayId(), localResources); 6504 6505 updateLastConfigurationFromResources(config); 6506 mView.dispatchConfigurationChanged(config); 6507 6508 // We could have gotten this {@link Configuration} update after we called 6509 // {@link #performTraversals} with an older {@link Configuration}. As a result, our 6510 // window frame may be stale. We must ensure the next pass of {@link #performTraversals} 6511 // catches this. 6512 mForceNextWindowRelayout = true; 6513 requestLayout(); 6514 } 6515 6516 updateForceDarkMode(); 6517 } 6518 updateLastConfigurationFromResources(Configuration resConfig)6519 private void updateLastConfigurationFromResources(Configuration resConfig) { 6520 final int lastLayoutDirection = mLastConfigurationFromResources.getLayoutDirection(); 6521 final int currentLayoutDirection = resConfig.getLayoutDirection(); 6522 mLastConfigurationFromResources.setTo(resConfig); 6523 // Update layout direction in case the language or screen layout is changed. 6524 if (lastLayoutDirection != currentLayoutDirection && mView != null 6525 && mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) { 6526 mView.setLayoutDirection(currentLayoutDirection); 6527 } 6528 } 6529 6530 /** 6531 * Return true if child is an ancestor of parent, (or equal to the parent). 6532 */ isViewDescendantOf(View child, View parent)6533 public static boolean isViewDescendantOf(View child, View parent) { 6534 if (child == parent) { 6535 return true; 6536 } 6537 6538 final ViewParent theParent = child.getParent(); 6539 return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent); 6540 } 6541 forceLayout(View view)6542 private static void forceLayout(View view) { 6543 view.forceLayout(); 6544 if (view instanceof ViewGroup) { 6545 ViewGroup group = (ViewGroup) view; 6546 final int count = group.getChildCount(); 6547 for (int i = 0; i < count; i++) { 6548 forceLayout(group.getChildAt(i)); 6549 } 6550 } 6551 } 6552 6553 private static final int MSG_INVALIDATE = 1; 6554 private static final int MSG_INVALIDATE_RECT = 2; 6555 private static final int MSG_DIE = 3; 6556 private static final int MSG_RESIZED = 4; 6557 private static final int MSG_RESIZED_REPORT = 5; 6558 private static final int MSG_WINDOW_FOCUS_CHANGED = 6; 6559 private static final int MSG_DISPATCH_INPUT_EVENT = 7; 6560 private static final int MSG_DISPATCH_APP_VISIBILITY = 8; 6561 private static final int MSG_DISPATCH_GET_NEW_SURFACE = 9; 6562 private static final int MSG_DISPATCH_KEY_FROM_IME = 11; 6563 private static final int MSG_DISPATCH_KEY_FROM_AUTOFILL = 12; 6564 private static final int MSG_CHECK_FOCUS = 13; 6565 private static final int MSG_CLOSE_SYSTEM_DIALOGS = 14; 6566 private static final int MSG_DISPATCH_DRAG_EVENT = 15; 6567 private static final int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16; 6568 private static final int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17; 6569 private static final int MSG_UPDATE_CONFIGURATION = 18; 6570 private static final int MSG_PROCESS_INPUT_EVENTS = 19; 6571 private static final int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21; 6572 private static final int MSG_INVALIDATE_WORLD = 22; 6573 private static final int MSG_WINDOW_MOVED = 23; 6574 private static final int MSG_SYNTHESIZE_INPUT_EVENT = 24; 6575 private static final int MSG_DISPATCH_WINDOW_SHOWN = 25; 6576 private static final int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26; 6577 private static final int MSG_POINTER_CAPTURE_CHANGED = 28; 6578 private static final int MSG_INSETS_CONTROL_CHANGED = 29; 6579 private static final int MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED = 30; 6580 private static final int MSG_SHOW_INSETS = 31; 6581 private static final int MSG_HIDE_INSETS = 32; 6582 private static final int MSG_REQUEST_SCROLL_CAPTURE = 33; 6583 private static final int MSG_WINDOW_TOUCH_MODE_CHANGED = 34; 6584 private static final int MSG_KEEP_CLEAR_RECTS_CHANGED = 35; 6585 private static final int MSG_REPORT_KEEP_CLEAR_RECTS = 36; 6586 private static final int MSG_PAUSED_FOR_SYNC_TIMEOUT = 37; 6587 private static final int MSG_DECOR_VIEW_GESTURE_INTERCEPTION = 38; 6588 private static final int MSG_TOUCH_BOOST_TIMEOUT = 39; 6589 private static final int MSG_CHECK_INVALIDATION_IDLE = 40; 6590 private static final int MSG_REFRESH_POINTER_ICON = 41; 6591 private static final int MSG_FRAME_RATE_SETTING = 42; 6592 6593 final class ViewRootHandler extends Handler { 6594 @Override getMessageName(Message message)6595 public String getMessageName(Message message) { 6596 switch (message.what) { 6597 case MSG_INVALIDATE: 6598 return "MSG_INVALIDATE"; 6599 case MSG_INVALIDATE_RECT: 6600 return "MSG_INVALIDATE_RECT"; 6601 case MSG_DIE: 6602 return "MSG_DIE"; 6603 case MSG_RESIZED: 6604 return "MSG_RESIZED"; 6605 case MSG_RESIZED_REPORT: 6606 return "MSG_RESIZED_REPORT"; 6607 case MSG_WINDOW_FOCUS_CHANGED: 6608 return "MSG_WINDOW_FOCUS_CHANGED"; 6609 case MSG_DISPATCH_INPUT_EVENT: 6610 return "MSG_DISPATCH_INPUT_EVENT"; 6611 case MSG_DISPATCH_APP_VISIBILITY: 6612 return "MSG_DISPATCH_APP_VISIBILITY"; 6613 case MSG_DISPATCH_GET_NEW_SURFACE: 6614 return "MSG_DISPATCH_GET_NEW_SURFACE"; 6615 case MSG_DISPATCH_KEY_FROM_IME: 6616 return "MSG_DISPATCH_KEY_FROM_IME"; 6617 case MSG_DISPATCH_KEY_FROM_AUTOFILL: 6618 return "MSG_DISPATCH_KEY_FROM_AUTOFILL"; 6619 case MSG_CHECK_FOCUS: 6620 return "MSG_CHECK_FOCUS"; 6621 case MSG_CLOSE_SYSTEM_DIALOGS: 6622 return "MSG_CLOSE_SYSTEM_DIALOGS"; 6623 case MSG_DISPATCH_DRAG_EVENT: 6624 return "MSG_DISPATCH_DRAG_EVENT"; 6625 case MSG_DISPATCH_DRAG_LOCATION_EVENT: 6626 return "MSG_DISPATCH_DRAG_LOCATION_EVENT"; 6627 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: 6628 return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY"; 6629 case MSG_UPDATE_CONFIGURATION: 6630 return "MSG_UPDATE_CONFIGURATION"; 6631 case MSG_PROCESS_INPUT_EVENTS: 6632 return "MSG_PROCESS_INPUT_EVENTS"; 6633 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: 6634 return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST"; 6635 case MSG_WINDOW_MOVED: 6636 return "MSG_WINDOW_MOVED"; 6637 case MSG_SYNTHESIZE_INPUT_EVENT: 6638 return "MSG_SYNTHESIZE_INPUT_EVENT"; 6639 case MSG_DISPATCH_WINDOW_SHOWN: 6640 return "MSG_DISPATCH_WINDOW_SHOWN"; 6641 case MSG_POINTER_CAPTURE_CHANGED: 6642 return "MSG_POINTER_CAPTURE_CHANGED"; 6643 case MSG_INSETS_CONTROL_CHANGED: 6644 return "MSG_INSETS_CONTROL_CHANGED"; 6645 case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED: 6646 return "MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED"; 6647 case MSG_SHOW_INSETS: 6648 return "MSG_SHOW_INSETS"; 6649 case MSG_HIDE_INSETS: 6650 return "MSG_HIDE_INSETS"; 6651 case MSG_WINDOW_TOUCH_MODE_CHANGED: 6652 return "MSG_WINDOW_TOUCH_MODE_CHANGED"; 6653 case MSG_KEEP_CLEAR_RECTS_CHANGED: 6654 return "MSG_KEEP_CLEAR_RECTS_CHANGED"; 6655 case MSG_CHECK_INVALIDATION_IDLE: 6656 return "MSG_CHECK_INVALIDATION_IDLE"; 6657 case MSG_REFRESH_POINTER_ICON: 6658 return "MSG_REFRESH_POINTER_ICON"; 6659 case MSG_TOUCH_BOOST_TIMEOUT: 6660 return "MSG_TOUCH_BOOST_TIMEOUT"; 6661 case MSG_FRAME_RATE_SETTING: 6662 return "MSG_FRAME_RATE_SETTING"; 6663 } 6664 return super.getMessageName(message); 6665 } 6666 6667 @Override sendMessageAtTime(Message msg, long uptimeMillis)6668 public boolean sendMessageAtTime(Message msg, long uptimeMillis) { 6669 if (msg.what == MSG_REQUEST_KEYBOARD_SHORTCUTS && msg.obj == null) { 6670 // Debugging for b/27963013 6671 throw new NullPointerException( 6672 "Attempted to call MSG_REQUEST_KEYBOARD_SHORTCUTS with null receiver:"); 6673 } 6674 return super.sendMessageAtTime(msg, uptimeMillis); 6675 } 6676 6677 @Override handleMessage(Message msg)6678 public void handleMessage(Message msg) { 6679 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 6680 Trace.traceBegin(Trace.TRACE_TAG_VIEW, getMessageName(msg)); 6681 } 6682 try { 6683 handleMessageImpl(msg); 6684 } finally { 6685 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 6686 } 6687 } 6688 handleMessageImpl(Message msg)6689 private void handleMessageImpl(Message msg) { 6690 switch (msg.what) { 6691 case MSG_INVALIDATE: 6692 ((View) msg.obj).invalidate(); 6693 break; 6694 case MSG_INVALIDATE_RECT: 6695 final View.AttachInfo.InvalidateInfo info = 6696 (View.AttachInfo.InvalidateInfo) msg.obj; 6697 info.target.invalidate(info.left, info.top, info.right, info.bottom); 6698 info.recycle(); 6699 break; 6700 case MSG_PROCESS_INPUT_EVENTS: 6701 mProcessInputEventsScheduled = false; 6702 doProcessInputEvents(); 6703 break; 6704 case MSG_DISPATCH_APP_VISIBILITY: 6705 handleAppVisibility(msg.arg1 != 0); 6706 break; 6707 case MSG_DISPATCH_GET_NEW_SURFACE: 6708 handleGetNewSurface(); 6709 break; 6710 case MSG_RESIZED: 6711 case MSG_RESIZED_REPORT: { 6712 final SomeArgs args = (SomeArgs) msg.obj; 6713 final ClientWindowFrames frames = (ClientWindowFrames) args.arg1; 6714 final boolean reportDraw = msg.what == MSG_RESIZED_REPORT; 6715 final MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg2; 6716 final InsetsState insetsState = (InsetsState) args.arg3; 6717 final ActivityWindowInfo activityWindowInfo = (ActivityWindowInfo) args.arg4; 6718 final boolean forceLayout = args.argi1 != 0; 6719 final boolean alwaysConsumeSystemBars = args.argi2 != 0; 6720 final int displayId = args.argi3; 6721 final int syncSeqId = args.argi4; 6722 final boolean dragResizing = args.argi5 != 0; 6723 handleResized(frames, reportDraw, mergedConfiguration, insetsState, forceLayout, 6724 alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing, 6725 activityWindowInfo); 6726 args.recycle(); 6727 break; 6728 } 6729 case MSG_INSETS_CONTROL_CHANGED: { 6730 final SomeArgs args = (SomeArgs) msg.obj; 6731 final InsetsState insetsState = (InsetsState) args.arg1; 6732 final InsetsSourceControl.Array activeControls = 6733 (InsetsSourceControl.Array) args.arg2; 6734 handleInsetsControlChanged(insetsState, activeControls); 6735 args.recycle(); 6736 break; 6737 } 6738 case MSG_SHOW_INSETS: { 6739 final ImeTracker.Token statsToken = (ImeTracker.Token) msg.obj; 6740 ImeTracker.forLogging().onProgress(statsToken, 6741 ImeTracker.PHASE_CLIENT_HANDLE_SHOW_INSETS); 6742 if (mView == null) { 6743 Log.e(TAG, 6744 String.format("Calling showInsets(%d,%b) on window that no longer" 6745 + " has views.", msg.arg1, msg.arg2 == 1)); 6746 } 6747 clearLowProfileModeIfNeeded(msg.arg1, msg.arg2 == 1); 6748 mInsetsController.show(msg.arg1, msg.arg2 == 1, statsToken); 6749 break; 6750 } 6751 case MSG_HIDE_INSETS: { 6752 final ImeTracker.Token statsToken = (ImeTracker.Token) msg.obj; 6753 ImeTracker.forLogging().onProgress(statsToken, 6754 ImeTracker.PHASE_CLIENT_HANDLE_HIDE_INSETS); 6755 mInsetsController.hide(msg.arg1, msg.arg2 == 1, statsToken); 6756 break; 6757 } 6758 case MSG_WINDOW_MOVED: 6759 if (mAdded) { 6760 final int w = mWinFrame.width(); 6761 final int h = mWinFrame.height(); 6762 final int l = msg.arg1; 6763 final int t = msg.arg2; 6764 mTmpFrames.frame.left = l; 6765 mTmpFrames.frame.right = l + w; 6766 mTmpFrames.frame.top = t; 6767 mTmpFrames.frame.bottom = t + h; 6768 setFrame(mTmpFrames.frame, false /* withinRelayout */); 6769 maybeHandleWindowMove(mWinFrame); 6770 } 6771 break; 6772 case MSG_WINDOW_FOCUS_CHANGED: { 6773 handleWindowFocusChanged(); 6774 } break; 6775 case MSG_WINDOW_TOUCH_MODE_CHANGED: { 6776 handleWindowTouchModeChanged(); 6777 } break; 6778 case MSG_DIE: { 6779 doDie(); 6780 } break; 6781 case MSG_DISPATCH_INPUT_EVENT: { 6782 SomeArgs args = (SomeArgs) msg.obj; 6783 InputEvent event = (InputEvent) args.arg1; 6784 InputEventReceiver receiver = (InputEventReceiver) args.arg2; 6785 enqueueInputEvent(event, receiver, 0, true); 6786 args.recycle(); 6787 } break; 6788 case MSG_SYNTHESIZE_INPUT_EVENT: { 6789 InputEvent event = (InputEvent) msg.obj; 6790 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_UNHANDLED, true); 6791 } break; 6792 case MSG_DISPATCH_KEY_FROM_IME: { 6793 if (LOCAL_LOGV) { 6794 Log.v(TAG, "Dispatching key " + msg.obj + " from IME to " + mView); 6795 } 6796 KeyEvent event = (KeyEvent) msg.obj; 6797 if ((event.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) != 0) { 6798 // The IME is trying to say this event is from the 6799 // system! Bad bad bad! 6800 //noinspection UnusedAssignment 6801 event = KeyEvent.changeFlags(event, 6802 event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM); 6803 } 6804 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true); 6805 } break; 6806 case MSG_DISPATCH_KEY_FROM_AUTOFILL: { 6807 if (LOCAL_LOGV) { 6808 Log.v(TAG, "Dispatching key " + msg.obj + " from Autofill to " + mView); 6809 } 6810 KeyEvent event = (KeyEvent) msg.obj; 6811 enqueueInputEvent(event, null, 0, true); 6812 } break; 6813 case MSG_CHECK_FOCUS: { 6814 getImeFocusController().onScheduledCheckFocus(); 6815 } break; 6816 case MSG_CLOSE_SYSTEM_DIALOGS: { 6817 if (mView != null) { 6818 mView.onCloseSystemDialogs((String) msg.obj); 6819 } 6820 } break; 6821 case MSG_DISPATCH_DRAG_EVENT: { 6822 } // fall through 6823 case MSG_DISPATCH_DRAG_LOCATION_EVENT: { 6824 DragEvent event = (DragEvent) msg.obj; 6825 // only present when this app called startDrag() 6826 event.mLocalState = mLocalDragState; 6827 final boolean traceDragEvent = event.mAction != ACTION_DRAG_LOCATION; 6828 try { 6829 if (traceDragEvent) { 6830 Trace.traceBegin(TRACE_TAG_VIEW, 6831 "c#" + DragEvent.actionToString(event.mAction)); 6832 } 6833 handleDragEvent(event); 6834 } finally { 6835 if (traceDragEvent) { 6836 Trace.traceEnd(TRACE_TAG_VIEW); 6837 } 6838 } 6839 } break; 6840 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: { 6841 handleDispatchSystemUiVisibilityChanged(); 6842 } break; 6843 case MSG_UPDATE_CONFIGURATION: { 6844 Configuration config = (Configuration) msg.obj; 6845 if (config.isOtherSeqNewer( 6846 mLastReportedMergedConfiguration.getMergedConfiguration())) { 6847 // If we already have a newer merged config applied - use its global part. 6848 config = mLastReportedMergedConfiguration.getGlobalConfiguration(); 6849 } 6850 6851 // Use the newer global config and last reported override config. 6852 mPendingMergedConfiguration.setConfiguration(config, 6853 mLastReportedMergedConfiguration.getOverrideConfiguration()); 6854 if (mPendingActivityWindowInfo != null) { 6855 mPendingActivityWindowInfo.set(mLastReportedActivityWindowInfo); 6856 } 6857 6858 performConfigurationChange(new MergedConfiguration(mPendingMergedConfiguration), 6859 false /* force */, INVALID_DISPLAY /* same display */, 6860 mPendingActivityWindowInfo != null 6861 ? new ActivityWindowInfo(mPendingActivityWindowInfo) 6862 : null); 6863 } break; 6864 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: { 6865 setAccessibilityFocus(null, null); 6866 } break; 6867 case MSG_INVALIDATE_WORLD: { 6868 if (mView != null) { 6869 invalidateWorld(mView); 6870 } 6871 } break; 6872 case MSG_DISPATCH_WINDOW_SHOWN: { 6873 handleDispatchWindowShown(); 6874 } break; 6875 case MSG_REQUEST_KEYBOARD_SHORTCUTS: { 6876 final IResultReceiver receiver = (IResultReceiver) msg.obj; 6877 final int deviceId = msg.arg1; 6878 handleRequestKeyboardShortcuts(receiver, deviceId); 6879 } break; 6880 case MSG_POINTER_CAPTURE_CHANGED: { 6881 final boolean hasCapture = msg.arg1 != 0; 6882 handlePointerCaptureChanged(hasCapture); 6883 } break; 6884 case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED: { 6885 systemGestureExclusionChanged(); 6886 } break; 6887 case MSG_DECOR_VIEW_GESTURE_INTERCEPTION: { 6888 decorViewInterceptionChanged(/* intercepted= */ msg.arg1 == 1); 6889 } break; 6890 case MSG_KEEP_CLEAR_RECTS_CHANGED: { 6891 keepClearRectsChanged(/* accessibilityFocusRectChanged= */ msg.arg1 == 1); 6892 } break; 6893 case MSG_REPORT_KEEP_CLEAR_RECTS: { 6894 reportKeepClearAreasChanged(); 6895 } break; 6896 case MSG_REQUEST_SCROLL_CAPTURE: 6897 handleScrollCaptureRequest((IScrollCaptureResponseListener) msg.obj); 6898 break; 6899 case MSG_PAUSED_FOR_SYNC_TIMEOUT: 6900 Log.e(mTag, "Timedout waiting to unpause for sync"); 6901 mNumPausedForSync = 0; 6902 scheduleTraversals(); 6903 break; 6904 case MSG_CHECK_INVALIDATION_IDLE: { 6905 long delta; 6906 if (mIsTouchBoosting || mIsFrameRateBoosting || mInsetsAnimationRunning) { 6907 delta = 0; 6908 } else { 6909 delta = System.nanoTime() / NANOS_PER_MILLI - mLastUpdateTimeMillis; 6910 } 6911 if (delta >= IDLE_TIME_MILLIS) { 6912 mFrameRateCategoryHighCount = 0; 6913 mFrameRateCategoryHighHintCount = 0; 6914 mFrameRateCategoryNormalCount = 0; 6915 mFrameRateCategoryLowCount = 0; 6916 mPreferredFrameRate = 0; 6917 mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE; 6918 updateFrameRateFromThreadedRendererViews(); 6919 setPreferredFrameRate(mPreferredFrameRate); 6920 setPreferredFrameRateCategory(mPreferredFrameRateCategory); 6921 mInvalidationIdleMessagePosted = false; 6922 } else { 6923 mInvalidationIdleMessagePosted = true; 6924 mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE, 6925 IDLE_TIME_MILLIS - delta); 6926 } 6927 break; 6928 } 6929 case MSG_TOUCH_BOOST_TIMEOUT: 6930 /** 6931 * Lower the frame rate after the boosting period (FRAME_RATE_TOUCH_BOOST_TIME). 6932 */ 6933 mIsFrameRateBoosting = false; 6934 mIsTouchBoosting = false; 6935 break; 6936 case MSG_REFRESH_POINTER_ICON: 6937 if (mPointerIconEvent == null) { 6938 break; 6939 } 6940 updatePointerIcon(mPointerIconEvent); 6941 break; 6942 case MSG_FRAME_RATE_SETTING: 6943 mPreferredFrameRate = 0; 6944 mFrameRateCompatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; 6945 break; 6946 } 6947 } 6948 } 6949 6950 final ViewRootHandler mHandler = new ViewRootHandler(); 6951 final Executor mExecutor = (Runnable r) -> { 6952 mHandler.post(r); 6953 }; 6954 6955 /** 6956 * Something in the current window tells us we need to change the touch mode. For 6957 * example, we are not in touch mode, and the user touches the screen. 6958 * 6959 * If the touch mode has changed, tell the window manager, and handle it locally. 6960 * 6961 * @param inTouchMode Whether we want to be in touch mode. 6962 * @return True if the touch mode changed and focus changed was changed as a result 6963 */ 6964 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) ensureTouchMode(boolean inTouchMode)6965 boolean ensureTouchMode(boolean inTouchMode) { 6966 if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current " 6967 + "touch mode is " + mAttachInfo.mInTouchMode); 6968 if (mAttachInfo.mInTouchMode == inTouchMode) return false; 6969 6970 // tell the window manager 6971 try { 6972 IWindowManager windowManager = WindowManagerGlobal.getWindowManagerService(); 6973 windowManager.setInTouchMode(inTouchMode, getDisplayId()); 6974 } catch (RemoteException e) { 6975 throw new RuntimeException(e); 6976 } 6977 6978 // handle the change 6979 return ensureTouchModeLocally(inTouchMode); 6980 } 6981 6982 /** 6983 * Ensure that the touch mode for this window is set, and if it is changing, 6984 * take the appropriate action. 6985 * @param inTouchMode Whether we want to be in touch mode. 6986 * @return True if the touch mode changed and focus changed was changed as a result 6987 */ ensureTouchModeLocally(boolean inTouchMode)6988 private boolean ensureTouchModeLocally(boolean inTouchMode) { 6989 if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current " 6990 + "touch mode is " + mAttachInfo.mInTouchMode); 6991 6992 if (mAttachInfo.mInTouchMode == inTouchMode) return false; 6993 6994 mAttachInfo.mInTouchMode = inTouchMode; 6995 mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode); 6996 6997 return (inTouchMode) ? enterTouchMode() : leaveTouchMode(); 6998 } 6999 enterTouchMode()7000 private boolean enterTouchMode() { 7001 if (mView != null && mView.hasFocus()) { 7002 // note: not relying on mFocusedView here because this could 7003 // be when the window is first being added, and mFocused isn't 7004 // set yet. 7005 final View focused = mView.findFocus(); 7006 if (focused != null && !focused.isFocusableInTouchMode()) { 7007 final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused); 7008 if (ancestorToTakeFocus != null) { 7009 // there is an ancestor that wants focus after its 7010 // descendants that is focusable in touch mode.. give it 7011 // focus 7012 return ancestorToTakeFocus.requestFocus(); 7013 } else { 7014 // There's nothing to focus. Clear and propagate through the 7015 // hierarchy, but don't attempt to place new focus. 7016 focused.clearFocusInternal(null, true, false); 7017 return true; 7018 } 7019 } 7020 } 7021 return false; 7022 } 7023 7024 /** 7025 * Find an ancestor of focused that wants focus after its descendants and is 7026 * focusable in touch mode. 7027 * @param focused The currently focused view. 7028 * @return An appropriate view, or null if no such view exists. 7029 */ findAncestorToTakeFocusInTouchMode(View focused)7030 private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) { 7031 ViewParent parent = focused.getParent(); 7032 while (parent instanceof ViewGroup) { 7033 final ViewGroup vgParent = (ViewGroup) parent; 7034 if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS 7035 && vgParent.isFocusableInTouchMode()) { 7036 return vgParent; 7037 } 7038 if (vgParent.isRootNamespace()) { 7039 return null; 7040 } else { 7041 parent = vgParent.getParent(); 7042 } 7043 } 7044 return null; 7045 } 7046 leaveTouchMode()7047 private boolean leaveTouchMode() { 7048 if (mView != null) { 7049 if (mView.hasFocus()) { 7050 View focusedView = mView.findFocus(); 7051 if (!(focusedView instanceof ViewGroup)) { 7052 // some view has focus, let it keep it 7053 return false; 7054 } else if (((ViewGroup) focusedView).getDescendantFocusability() != 7055 ViewGroup.FOCUS_AFTER_DESCENDANTS) { 7056 // some view group has focus, and doesn't prefer its children 7057 // over itself for focus, so let them keep it. 7058 return false; 7059 } 7060 } 7061 7062 // find the best view to give focus to in this brave new non-touch-mode 7063 // world 7064 return mView.restoreDefaultFocus(); 7065 } 7066 return false; 7067 } 7068 7069 /** 7070 * Base class for implementing a stage in the chain of responsibility 7071 * for processing input events. 7072 * <p> 7073 * Events are delivered to the stage by the {@link #deliver} method. The stage 7074 * then has the choice of finishing the event or forwarding it to the next stage. 7075 * </p> 7076 */ 7077 abstract class InputStage { 7078 private final InputStage mNext; 7079 7080 protected static final int FORWARD = 0; 7081 protected static final int FINISH_HANDLED = 1; 7082 protected static final int FINISH_NOT_HANDLED = 2; 7083 7084 private String mTracePrefix; 7085 7086 /** 7087 * Creates an input stage. 7088 * @param next The next stage to which events should be forwarded. 7089 */ InputStage(InputStage next)7090 public InputStage(InputStage next) { 7091 mNext = next; 7092 } 7093 7094 /** 7095 * Delivers an event to be processed. 7096 */ deliver(QueuedInputEvent q)7097 public final void deliver(QueuedInputEvent q) { 7098 if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) { 7099 forward(q); 7100 } else if (shouldDropInputEvent(q)) { 7101 finish(q, false); 7102 } else { 7103 traceEvent(q, Trace.TRACE_TAG_VIEW); 7104 final int result; 7105 try { 7106 result = onProcess(q); 7107 } finally { 7108 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 7109 } 7110 apply(q, result); 7111 } 7112 } 7113 7114 /** 7115 * Marks the input event as finished then forwards it to the next stage. 7116 */ finish(QueuedInputEvent q, boolean handled)7117 protected void finish(QueuedInputEvent q, boolean handled) { 7118 q.mFlags |= QueuedInputEvent.FLAG_FINISHED; 7119 if (handled) { 7120 q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED; 7121 } 7122 forward(q); 7123 } 7124 7125 /** 7126 * Forwards the event to the next stage. 7127 */ forward(QueuedInputEvent q)7128 protected void forward(QueuedInputEvent q) { 7129 onDeliverToNext(q); 7130 } 7131 7132 /** 7133 * Applies a result code from {@link #onProcess} to the specified event. 7134 */ apply(QueuedInputEvent q, int result)7135 protected void apply(QueuedInputEvent q, int result) { 7136 if (result == FORWARD) { 7137 forward(q); 7138 } else if (result == FINISH_HANDLED) { 7139 finish(q, true); 7140 } else if (result == FINISH_NOT_HANDLED) { 7141 finish(q, false); 7142 } else { 7143 throw new IllegalArgumentException("Invalid result: " + result); 7144 } 7145 } 7146 7147 /** 7148 * Called when an event is ready to be processed. 7149 * @return A result code indicating how the event was handled. 7150 */ onProcess(QueuedInputEvent q)7151 protected int onProcess(QueuedInputEvent q) { 7152 return FORWARD; 7153 } 7154 7155 /** 7156 * Called when an event is being delivered to the next stage. 7157 */ onDeliverToNext(QueuedInputEvent q)7158 protected void onDeliverToNext(QueuedInputEvent q) { 7159 if (DEBUG_INPUT_STAGES) { 7160 Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q); 7161 } 7162 if (mNext != null) { 7163 mNext.deliver(q); 7164 } else { 7165 finishInputEvent(q); 7166 } 7167 } 7168 onWindowFocusChanged(boolean hasWindowFocus)7169 protected void onWindowFocusChanged(boolean hasWindowFocus) { 7170 if (mNext != null) { 7171 mNext.onWindowFocusChanged(hasWindowFocus); 7172 } 7173 } 7174 onDetachedFromWindow()7175 protected void onDetachedFromWindow() { 7176 if (mNext != null) { 7177 mNext.onDetachedFromWindow(); 7178 } 7179 } 7180 shouldDropInputEvent(QueuedInputEvent q)7181 protected boolean shouldDropInputEvent(QueuedInputEvent q) { 7182 if (mView == null || !mAdded) { 7183 Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent); 7184 return true; 7185 } 7186 7187 // Find a reason for dropping or canceling the event. 7188 final String reason; 7189 // The embedded window is focused, allow this VRI to handle back key. 7190 if (!mAttachInfo.mHasWindowFocus && !(mProcessingBackKey && isBack(q.mEvent)) 7191 && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER) 7192 && !isAutofillUiShowing()) { 7193 // This is a non-pointer event and the window doesn't currently have input focus 7194 // This could be an event that came back from the previous stage 7195 // but the window has lost focus or stopped in the meantime. 7196 reason = "no window focus"; 7197 } else if (mStopped) { 7198 reason = "window is stopped"; 7199 } else if (mIsAmbientMode 7200 && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON)) { 7201 reason = "non-button event in ambient mode"; 7202 } else if (mPausedForTransition && !isBack(q.mEvent)) { 7203 reason = "paused for transition"; 7204 } else { 7205 // Most common path: no reason to drop or cancel the event 7206 return false; 7207 } 7208 7209 if (isTerminalInputEvent(q.mEvent)) { 7210 // Don't drop terminal input events, however mark them as canceled. 7211 q.mEvent.cancel(); 7212 Slog.w(mTag, "Cancelling event (" + reason + "):" + q.mEvent); 7213 return false; 7214 } 7215 7216 // Drop non-terminal input events. 7217 Slog.w(mTag, "Dropping event (" + reason + "):" + q.mEvent); 7218 return true; 7219 } 7220 dump(String prefix, PrintWriter writer)7221 void dump(String prefix, PrintWriter writer) { 7222 if (mNext != null) { 7223 mNext.dump(prefix, writer); 7224 } 7225 } 7226 isBack(InputEvent event)7227 boolean isBack(InputEvent event) { 7228 if (event instanceof KeyEvent) { 7229 return ((KeyEvent) event).getKeyCode() == KeyEvent.KEYCODE_BACK; 7230 } else { 7231 return false; 7232 } 7233 } 7234 traceEvent(QueuedInputEvent q, long traceTag)7235 private void traceEvent(QueuedInputEvent q, long traceTag) { 7236 if (!Trace.isTagEnabled(traceTag)) { 7237 return; 7238 } 7239 7240 if (mTracePrefix == null) { 7241 mTracePrefix = getClass().getSimpleName(); 7242 } 7243 Trace.traceBegin(traceTag, mTracePrefix + " id=0x" 7244 + Integer.toHexString(q.mEvent.getId())); 7245 } 7246 } 7247 7248 /** 7249 * Base class for implementing an input pipeline stage that supports 7250 * asynchronous and out-of-order processing of input events. 7251 * <p> 7252 * In addition to what a normal input stage can do, an asynchronous 7253 * input stage may also defer an input event that has been delivered to it 7254 * and finish or forward it later. 7255 * </p> 7256 */ 7257 abstract class AsyncInputStage extends InputStage { 7258 private final String mTraceCounter; 7259 7260 private QueuedInputEvent mQueueHead; 7261 private QueuedInputEvent mQueueTail; 7262 private int mQueueLength; 7263 7264 protected static final int DEFER = 3; 7265 7266 /** 7267 * Creates an asynchronous input stage. 7268 * @param next The next stage to which events should be forwarded. 7269 * @param traceCounter The name of a counter to record the size of 7270 * the queue of pending events. 7271 */ AsyncInputStage(InputStage next, String traceCounter)7272 public AsyncInputStage(InputStage next, String traceCounter) { 7273 super(next); 7274 mTraceCounter = traceCounter; 7275 } 7276 7277 /** 7278 * Marks the event as deferred, which is to say that it will be handled 7279 * asynchronously. The caller is responsible for calling {@link #forward} 7280 * or {@link #finish} later when it is done handling the event. 7281 */ defer(QueuedInputEvent q)7282 protected void defer(QueuedInputEvent q) { 7283 q.mFlags |= QueuedInputEvent.FLAG_DEFERRED; 7284 enqueue(q); 7285 } 7286 7287 @Override forward(QueuedInputEvent q)7288 protected void forward(QueuedInputEvent q) { 7289 // Clear the deferred flag. 7290 q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED; 7291 7292 // Fast path if the queue is empty. 7293 QueuedInputEvent curr = mQueueHead; 7294 if (curr == null) { 7295 super.forward(q); 7296 return; 7297 } 7298 7299 // Determine whether the event must be serialized behind any others 7300 // before it can be delivered to the next stage. This is done because 7301 // deferred events might be handled out of order by the stage. 7302 final int deviceId = q.mEvent.getDeviceId(); 7303 QueuedInputEvent prev = null; 7304 boolean blocked = false; 7305 while (curr != null && curr != q) { 7306 if (!blocked && deviceId == curr.mEvent.getDeviceId()) { 7307 blocked = true; 7308 } 7309 prev = curr; 7310 curr = curr.mNext; 7311 } 7312 7313 // If the event is blocked, then leave it in the queue to be delivered later. 7314 // Note that the event might not yet be in the queue if it was not previously 7315 // deferred so we will enqueue it if needed. 7316 if (blocked) { 7317 if (curr == null) { 7318 enqueue(q); 7319 } 7320 return; 7321 } 7322 7323 // The event is not blocked. Deliver it immediately. 7324 if (curr != null) { 7325 curr = curr.mNext; 7326 dequeue(q, prev); 7327 } 7328 super.forward(q); 7329 7330 // Dequeuing this event may have unblocked successors. Deliver them. 7331 while (curr != null) { 7332 if (deviceId == curr.mEvent.getDeviceId()) { 7333 if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) { 7334 break; 7335 } 7336 QueuedInputEvent next = curr.mNext; 7337 dequeue(curr, prev); 7338 super.forward(curr); 7339 curr = next; 7340 } else { 7341 prev = curr; 7342 curr = curr.mNext; 7343 } 7344 } 7345 } 7346 7347 @Override apply(QueuedInputEvent q, int result)7348 protected void apply(QueuedInputEvent q, int result) { 7349 if (result == DEFER) { 7350 defer(q); 7351 } else { 7352 super.apply(q, result); 7353 } 7354 } 7355 enqueue(QueuedInputEvent q)7356 private void enqueue(QueuedInputEvent q) { 7357 if (mQueueTail == null) { 7358 mQueueHead = q; 7359 mQueueTail = q; 7360 } else { 7361 mQueueTail.mNext = q; 7362 mQueueTail = q; 7363 } 7364 7365 mQueueLength += 1; 7366 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength); 7367 } 7368 dequeue(QueuedInputEvent q, QueuedInputEvent prev)7369 private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) { 7370 if (prev == null) { 7371 mQueueHead = q.mNext; 7372 } else { 7373 prev.mNext = q.mNext; 7374 } 7375 if (mQueueTail == q) { 7376 mQueueTail = prev; 7377 } 7378 q.mNext = null; 7379 7380 mQueueLength -= 1; 7381 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength); 7382 } 7383 7384 @Override dump(String prefix, PrintWriter writer)7385 void dump(String prefix, PrintWriter writer) { 7386 writer.print(prefix); 7387 writer.print(getClass().getName()); 7388 writer.print(": mQueueLength="); 7389 writer.println(mQueueLength); 7390 7391 super.dump(prefix, writer); 7392 } 7393 } 7394 7395 /** 7396 * Delivers pre-ime input events to a native activity. 7397 * Does not support pointer events. 7398 */ 7399 final class NativePreImeInputStage extends AsyncInputStage 7400 implements InputQueue.FinishedInputEventCallback { 7401 NativePreImeInputStage(InputStage next, String traceCounter)7402 public NativePreImeInputStage(InputStage next, String traceCounter) { 7403 super(next, traceCounter); 7404 } 7405 7406 @Override onProcess(QueuedInputEvent q)7407 protected int onProcess(QueuedInputEvent q) { 7408 if (q.mEvent instanceof KeyEvent) { 7409 final KeyEvent keyEvent = (KeyEvent) q.mEvent; 7410 7411 // If the new back dispatch is enabled, intercept KEYCODE_BACK before it reaches the 7412 // view tree or IME, and invoke the appropriate {@link OnBackInvokedCallback}. 7413 if (isBack(keyEvent)) { 7414 if (mWindowlessBackKeyCallback != null) { 7415 if (mWindowlessBackKeyCallback.test(keyEvent)) { 7416 return keyEvent.getAction() == KeyEvent.ACTION_UP 7417 && !keyEvent.isCanceled() 7418 ? FINISH_HANDLED : FINISH_NOT_HANDLED; 7419 } else { 7420 // Unable to forward the back key to host, forward to next stage. 7421 return FORWARD; 7422 } 7423 } else if (mContext != null 7424 && mOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled()) { 7425 return doOnBackKeyEvent(keyEvent); 7426 } 7427 } 7428 7429 if (mInputQueue != null) { 7430 mInputQueue.sendInputEvent(q.mEvent, q, true, this); 7431 return DEFER; 7432 } 7433 } 7434 return FORWARD; 7435 } 7436 doOnBackKeyEvent(KeyEvent keyEvent)7437 private int doOnBackKeyEvent(KeyEvent keyEvent) { 7438 WindowOnBackInvokedDispatcher dispatcher = getOnBackInvokedDispatcher(); 7439 OnBackInvokedCallback topCallback = dispatcher.getTopCallback(); 7440 if (dispatcher.isBackGestureInProgress()) { 7441 return FINISH_NOT_HANDLED; 7442 } 7443 if (topCallback instanceof OnBackAnimationCallback 7444 && !(topCallback instanceof ImeBackAnimationController)) { 7445 final OnBackAnimationCallback animationCallback = 7446 (OnBackAnimationCallback) topCallback; 7447 switch (keyEvent.getAction()) { 7448 case KeyEvent.ACTION_DOWN: 7449 // ACTION_DOWN is emitted twice: once when the user presses the button, 7450 // and again a few milliseconds later. 7451 // Based on the result of `keyEvent.getRepeatCount()` we have: 7452 // - 0 means the button was pressed. 7453 // - 1 means the button continues to be pressed (long press). 7454 if (keyEvent.getRepeatCount() == 0) { 7455 animationCallback.onBackStarted( 7456 new BackEvent(0, 0, 0f, BackEvent.EDGE_LEFT)); 7457 } 7458 break; 7459 case KeyEvent.ACTION_UP: 7460 if (keyEvent.isCanceled()) { 7461 animationCallback.onBackCancelled(); 7462 } else { 7463 topCallback.onBackInvoked(); 7464 return FINISH_HANDLED; 7465 } 7466 break; 7467 } 7468 } else if (topCallback != null) { 7469 if (keyEvent.getAction() == KeyEvent.ACTION_UP) { 7470 if (!keyEvent.isCanceled()) { 7471 topCallback.onBackInvoked(); 7472 return FINISH_HANDLED; 7473 } else { 7474 Log.d(mTag, "Skip onBackInvoked(), reason: keyEvent.isCanceled=true"); 7475 } 7476 } 7477 } 7478 7479 return FINISH_NOT_HANDLED; 7480 } 7481 7482 @Override onFinishedInputEvent(Object token, boolean handled)7483 public void onFinishedInputEvent(Object token, boolean handled) { 7484 QueuedInputEvent q = (QueuedInputEvent)token; 7485 if (handled) { 7486 finish(q, true); 7487 return; 7488 } 7489 forward(q); 7490 } 7491 } 7492 7493 /** 7494 * Delivers pre-ime input events to the view hierarchy. 7495 * Does not support pointer events. 7496 */ 7497 final class ViewPreImeInputStage extends InputStage { ViewPreImeInputStage(InputStage next)7498 public ViewPreImeInputStage(InputStage next) { 7499 super(next); 7500 } 7501 7502 @Override onProcess(QueuedInputEvent q)7503 protected int onProcess(QueuedInputEvent q) { 7504 if (q.mEvent instanceof KeyEvent) { 7505 return processKeyEvent(q); 7506 } 7507 return FORWARD; 7508 } 7509 processKeyEvent(QueuedInputEvent q)7510 private int processKeyEvent(QueuedInputEvent q) { 7511 final KeyEvent event = (KeyEvent)q.mEvent; 7512 if (mView.dispatchKeyEventPreIme(event)) { 7513 return FINISH_HANDLED; 7514 } 7515 return FORWARD; 7516 } 7517 } 7518 7519 /** 7520 * Delivers input events to the ime. 7521 * Does not support pointer events. 7522 */ 7523 final class ImeInputStage extends AsyncInputStage 7524 implements InputMethodManager.FinishedInputEventCallback { ImeInputStage(InputStage next, String traceCounter)7525 public ImeInputStage(InputStage next, String traceCounter) { 7526 super(next, traceCounter); 7527 } 7528 7529 @Override onProcess(QueuedInputEvent q)7530 protected int onProcess(QueuedInputEvent q) { 7531 final int result = mImeFocusController.onProcessImeInputStage( 7532 q, q.mEvent, mWindowAttributes, this); 7533 switch (result) { 7534 case InputMethodManager.DISPATCH_IN_PROGRESS: 7535 // callback will be invoked later 7536 return DEFER; 7537 case InputMethodManager.DISPATCH_NOT_HANDLED: 7538 // The IME could not handle it, so skip along to the next InputStage 7539 return FORWARD; 7540 case InputMethodManager.DISPATCH_HANDLED: 7541 return FINISH_HANDLED; 7542 default: 7543 throw new IllegalStateException("Unexpected result=" + result); 7544 } 7545 } 7546 7547 @Override onFinishedInputEvent(Object token, boolean handled)7548 public void onFinishedInputEvent(Object token, boolean handled) { 7549 QueuedInputEvent q = (QueuedInputEvent)token; 7550 if (handled) { 7551 finish(q, true); 7552 return; 7553 } 7554 forward(q); 7555 } 7556 } 7557 7558 /** 7559 * Performs early processing of post-ime input events. 7560 */ 7561 final class EarlyPostImeInputStage extends InputStage { EarlyPostImeInputStage(InputStage next)7562 public EarlyPostImeInputStage(InputStage next) { 7563 super(next); 7564 } 7565 7566 @Override onProcess(QueuedInputEvent q)7567 protected int onProcess(QueuedInputEvent q) { 7568 if (q.mEvent instanceof KeyEvent) { 7569 return processKeyEvent(q); 7570 } else if (q.mEvent instanceof MotionEvent) { 7571 return processMotionEvent(q); 7572 } 7573 return FORWARD; 7574 } 7575 processKeyEvent(QueuedInputEvent q)7576 private int processKeyEvent(QueuedInputEvent q) { 7577 final KeyEvent event = (KeyEvent)q.mEvent; 7578 7579 if (mAttachInfo.mTooltipHost != null) { 7580 mAttachInfo.mTooltipHost.handleTooltipKey(event); 7581 } 7582 7583 // If the key's purpose is to exit touch mode then we consume it 7584 // and consider it handled. 7585 if (checkForLeavingTouchModeAndConsume(event)) { 7586 return FINISH_HANDLED; 7587 } 7588 7589 // Make sure the fallback event policy sees all keys that will be 7590 // delivered to the view hierarchy. 7591 mFallbackEventHandler.preDispatchKeyEvent(event); 7592 7593 // Reset last tracked MotionEvent click toolType. 7594 if (event.getAction() == KeyEvent.ACTION_DOWN) { 7595 mLastClickToolType = MotionEvent.TOOL_TYPE_UNKNOWN; 7596 } 7597 7598 return FORWARD; 7599 } 7600 processMotionEvent(QueuedInputEvent q)7601 private int processMotionEvent(QueuedInputEvent q) { 7602 final MotionEvent event = (MotionEvent) q.mEvent; 7603 7604 if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 7605 return processPointerEvent(q); 7606 } 7607 7608 // If the motion event is from an absolute position device, exit touch mode 7609 final int action = event.getActionMasked(); 7610 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) { 7611 if (event.isFromSource(InputDevice.SOURCE_CLASS_POSITION)) { 7612 ensureTouchMode(false); 7613 } 7614 } 7615 return FORWARD; 7616 } 7617 processPointerEvent(QueuedInputEvent q)7618 private int processPointerEvent(QueuedInputEvent q) { 7619 final MotionEvent event = (MotionEvent)q.mEvent; 7620 7621 // Translate the pointer event for compatibility, if needed. 7622 if (mTranslator != null) { 7623 mTranslator.translateEventInScreenToAppWindow(event); 7624 } 7625 7626 // Enter touch mode on down or scroll from any type of a device. 7627 final int action = event.getAction(); 7628 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) { 7629 ensureTouchMode(true); 7630 } 7631 7632 if (action == MotionEvent.ACTION_DOWN) { 7633 // Upon motion event within app window, close autofill ui. 7634 AutofillManager afm = getAutofillManager(); 7635 if (afm != null) { 7636 afm.requestHideFillUi(); 7637 } 7638 } 7639 7640 if (action == MotionEvent.ACTION_DOWN && mAttachInfo.mTooltipHost != null) { 7641 mAttachInfo.mTooltipHost.hideTooltip(); 7642 } 7643 7644 // Offset the scroll position. 7645 if (mCurScrollY != 0) { 7646 event.offsetLocation(0, mCurScrollY); 7647 } 7648 7649 if (event.isTouchEvent()) { 7650 // Remember the touch position for possible drag-initiation. 7651 mLastTouchPoint.x = event.getRawX(); 7652 mLastTouchPoint.y = event.getRawY(); 7653 mLastTouchSource = event.getSource(); 7654 mLastTouchDeviceId = event.getDeviceId(); 7655 mLastTouchPointerId = event.getPointerId(0); 7656 7657 // Register last ACTION_UP. This will be propagated to IME. 7658 if (event.getActionMasked() == MotionEvent.ACTION_UP) { 7659 mLastClickToolType = event.getToolType(event.getActionIndex()); 7660 } 7661 } 7662 return FORWARD; 7663 } 7664 } 7665 7666 /** 7667 * Delivers post-ime input events to a native activity. 7668 */ 7669 final class NativePostImeInputStage extends AsyncInputStage 7670 implements InputQueue.FinishedInputEventCallback { NativePostImeInputStage(InputStage next, String traceCounter)7671 public NativePostImeInputStage(InputStage next, String traceCounter) { 7672 super(next, traceCounter); 7673 } 7674 7675 @Override onProcess(QueuedInputEvent q)7676 protected int onProcess(QueuedInputEvent q) { 7677 if (mInputQueue != null) { 7678 mInputQueue.sendInputEvent(q.mEvent, q, false, this); 7679 return DEFER; 7680 } 7681 return FORWARD; 7682 } 7683 7684 @Override onFinishedInputEvent(Object token, boolean handled)7685 public void onFinishedInputEvent(Object token, boolean handled) { 7686 QueuedInputEvent q = (QueuedInputEvent)token; 7687 if (handled) { 7688 finish(q, true); 7689 return; 7690 } 7691 forward(q); 7692 } 7693 } 7694 7695 /** 7696 * Delivers post-ime input events to the view hierarchy. 7697 */ 7698 final class ViewPostImeInputStage extends InputStage { ViewPostImeInputStage(InputStage next)7699 public ViewPostImeInputStage(InputStage next) { 7700 super(next); 7701 } 7702 7703 @Override onProcess(QueuedInputEvent q)7704 protected int onProcess(QueuedInputEvent q) { 7705 if (q.mEvent instanceof KeyEvent) { 7706 return processKeyEvent(q); 7707 } else { 7708 final int source = q.mEvent.getSource(); 7709 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 7710 return processPointerEvent(q); 7711 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { 7712 return processTrackballEvent(q); 7713 } else { 7714 return processGenericMotionEvent(q); 7715 } 7716 } 7717 } 7718 7719 @Override onDeliverToNext(QueuedInputEvent q)7720 protected void onDeliverToNext(QueuedInputEvent q) { 7721 if (mUnbufferedInputDispatch 7722 && q.mEvent instanceof MotionEvent 7723 && ((MotionEvent)q.mEvent).isTouchEvent() 7724 && isTerminalInputEvent(q.mEvent)) { 7725 mUnbufferedInputDispatch = false; 7726 scheduleConsumeBatchedInput(); 7727 } 7728 super.onDeliverToNext(q); 7729 } 7730 performFocusNavigation(KeyEvent event)7731 private boolean performFocusNavigation(KeyEvent event) { 7732 @FocusDirection int direction = 0; 7733 switch (event.getKeyCode()) { 7734 case KeyEvent.KEYCODE_DPAD_LEFT: 7735 if (event.hasNoModifiers()) { 7736 direction = View.FOCUS_LEFT; 7737 } 7738 break; 7739 case KeyEvent.KEYCODE_DPAD_RIGHT: 7740 if (event.hasNoModifiers()) { 7741 direction = View.FOCUS_RIGHT; 7742 } 7743 break; 7744 case KeyEvent.KEYCODE_DPAD_UP: 7745 if (event.hasNoModifiers()) { 7746 direction = View.FOCUS_UP; 7747 } 7748 break; 7749 case KeyEvent.KEYCODE_DPAD_DOWN: 7750 if (event.hasNoModifiers()) { 7751 direction = View.FOCUS_DOWN; 7752 } 7753 break; 7754 case KeyEvent.KEYCODE_TAB: 7755 if (event.hasNoModifiers()) { 7756 direction = View.FOCUS_FORWARD; 7757 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) { 7758 direction = View.FOCUS_BACKWARD; 7759 } 7760 break; 7761 } 7762 if (direction != 0) { 7763 View focused = mView.findFocus(); 7764 if (focused != null) { 7765 mAttachInfo.mNextFocusLooped = false; 7766 View v = focused.focusSearch(direction); 7767 if (v != null && v != focused) { 7768 if (mAttachInfo.mNextFocusLooped) { 7769 // The next focus is looped. Let's try to move the focus to the adjacent 7770 // window. Note: we still need to move the focus in this window 7771 // regardless of what moveFocusToAdjacentWindow returns, so the focus 7772 // can be looped back from the focus in the adjacent window to next 7773 // focus of this window. 7774 moveFocusToAdjacentWindow(direction); 7775 } 7776 7777 // do the math the get the interesting rect 7778 // of previous focused into the coord system of 7779 // newly focused view 7780 focused.getFocusedRect(mTempRect); 7781 if (mView instanceof ViewGroup) { 7782 ((ViewGroup) mView).offsetDescendantRectToMyCoords( 7783 focused, mTempRect); 7784 ((ViewGroup) mView).offsetRectIntoDescendantCoords( 7785 v, mTempRect); 7786 } 7787 if (v.requestFocus(direction, mTempRect)) { 7788 boolean isFastScrolling = event.getRepeatCount() > 0; 7789 playSoundEffect( 7790 SoundEffectConstants.getConstantForFocusDirection(direction, 7791 isFastScrolling)); 7792 return true; 7793 } 7794 } else if (moveFocusToAdjacentWindow(direction)) { 7795 return true; 7796 } 7797 7798 // Give the focused view a last chance to handle the dpad key. 7799 if (mView.dispatchUnhandledMove(focused, direction)) { 7800 return true; 7801 } 7802 } else { 7803 if (mView.restoreDefaultFocus()) { 7804 return true; 7805 } else if (moveFocusToAdjacentWindow(direction)) { 7806 return true; 7807 } 7808 } 7809 } 7810 return false; 7811 } 7812 moveFocusToAdjacentWindow(@ocusDirection int direction)7813 private boolean moveFocusToAdjacentWindow(@FocusDirection int direction) { 7814 if (getConfiguration().windowConfiguration.getWindowingMode() 7815 != WINDOWING_MODE_MULTI_WINDOW) { 7816 return false; 7817 } 7818 try { 7819 return mWindowSession.moveFocusToAdjacentWindow(mWindow, direction); 7820 } catch (RemoteException e) { 7821 return false; 7822 } 7823 } 7824 performKeyboardGroupNavigation(int direction)7825 private boolean performKeyboardGroupNavigation(int direction) { 7826 final View focused = mView.findFocus(); 7827 if (focused == null && mView.restoreDefaultFocus()) { 7828 return true; 7829 } 7830 View cluster = focused == null ? keyboardNavigationClusterSearch(null, direction) 7831 : focused.keyboardNavigationClusterSearch(null, direction); 7832 7833 // Since requestFocus only takes "real" focus directions (and therefore also 7834 // restoreFocusInCluster), convert forward/backward focus into FOCUS_DOWN. 7835 int realDirection = direction; 7836 if (direction == View.FOCUS_FORWARD || direction == View.FOCUS_BACKWARD) { 7837 realDirection = View.FOCUS_DOWN; 7838 } 7839 7840 if (cluster != null && cluster.isRootNamespace()) { 7841 // the default cluster. Try to find a non-clustered view to focus. 7842 if (cluster.restoreFocusNotInCluster()) { 7843 playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction)); 7844 return true; 7845 } 7846 // otherwise skip to next actual cluster 7847 cluster = keyboardNavigationClusterSearch(null, direction); 7848 } 7849 7850 if (cluster != null && cluster.restoreFocusInCluster(realDirection)) { 7851 playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction)); 7852 return true; 7853 } 7854 7855 return false; 7856 } 7857 processKeyEvent(QueuedInputEvent q)7858 private int processKeyEvent(QueuedInputEvent q) { 7859 final KeyEvent event = (KeyEvent)q.mEvent; 7860 7861 if (mUnhandledKeyManager.preViewDispatch(event)) { 7862 return FINISH_HANDLED; 7863 } 7864 7865 // Deliver the key to the view hierarchy. 7866 if (mView.dispatchKeyEvent(event)) { 7867 return FINISH_HANDLED; 7868 } 7869 7870 if (shouldDropInputEvent(q)) { 7871 return FINISH_NOT_HANDLED; 7872 } 7873 7874 // This dispatch is for windows that don't have a Window.Callback. Otherwise, 7875 // the Window.Callback usually will have already called this (see 7876 // DecorView.superDispatchKeyEvent) leaving this call a no-op. 7877 if (mUnhandledKeyManager.dispatch(mView, event)) { 7878 return FINISH_HANDLED; 7879 } 7880 7881 int groupNavigationDirection = 0; 7882 7883 if (event.getAction() == KeyEvent.ACTION_DOWN 7884 && event.getKeyCode() == KeyEvent.KEYCODE_TAB) { 7885 if (KeyEvent.metaStateHasModifiers(event.getMetaState(), KeyEvent.META_CTRL_ON)) { 7886 groupNavigationDirection = View.FOCUS_FORWARD; 7887 } else if (KeyEvent.metaStateHasModifiers(event.getMetaState(), 7888 KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)) { 7889 groupNavigationDirection = View.FOCUS_BACKWARD; 7890 } 7891 } 7892 7893 // If a modifier is held, try to interpret the key as a shortcut. 7894 if (event.getAction() == KeyEvent.ACTION_DOWN 7895 && !KeyEvent.metaStateHasNoModifiers(event.getMetaState()) 7896 && event.getRepeatCount() == 0 7897 && !KeyEvent.isModifierKey(event.getKeyCode()) 7898 && groupNavigationDirection == 0) { 7899 if (mView.dispatchKeyShortcutEvent(event)) { 7900 return FINISH_HANDLED; 7901 } 7902 if (shouldDropInputEvent(q)) { 7903 return FINISH_NOT_HANDLED; 7904 } 7905 } 7906 7907 // Apply the fallback event policy. 7908 if (mFallbackEventHandler.dispatchKeyEvent(event)) { 7909 return FINISH_HANDLED; 7910 } 7911 if (shouldDropInputEvent(q)) { 7912 return FINISH_NOT_HANDLED; 7913 } 7914 7915 // Handle automatic focus changes. 7916 if (event.getAction() == KeyEvent.ACTION_DOWN) { 7917 if (groupNavigationDirection != 0) { 7918 if (performKeyboardGroupNavigation(groupNavigationDirection)) { 7919 return FINISH_HANDLED; 7920 } 7921 } else { 7922 if (performFocusNavigation(event)) { 7923 return FINISH_HANDLED; 7924 } 7925 } 7926 } 7927 return FORWARD; 7928 } 7929 processPointerEvent(QueuedInputEvent q)7930 private int processPointerEvent(QueuedInputEvent q) { 7931 final MotionEvent event = (MotionEvent)q.mEvent; 7932 final int action = event.getAction(); 7933 boolean handled = false; 7934 if (!disableHandwritingInitiatorForIme() 7935 || mWindowAttributes.type != TYPE_INPUT_METHOD) { 7936 handled = mHandwritingInitiator.onTouchEvent(event); 7937 } 7938 if (handled) { 7939 // If handwriting is started, toolkit doesn't receive ACTION_UP. 7940 mLastClickToolType = event.getToolType(event.getActionIndex()); 7941 } 7942 7943 mAttachInfo.mUnbufferedDispatchRequested = false; 7944 mAttachInfo.mHandlingPointerEvent = true; 7945 // If the event was fully handled by the handwriting initiator, then don't dispatch it 7946 // to the view tree. 7947 handled = handled || mView.dispatchPointerEvent(event); 7948 maybeUpdatePointerIcon(event); 7949 maybeUpdateTooltip(event); 7950 mAttachInfo.mHandlingPointerEvent = false; 7951 if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) { 7952 mUnbufferedInputDispatch = true; 7953 if (mConsumeBatchedInputScheduled) { 7954 scheduleConsumeBatchedInputImmediately(); 7955 } 7956 } 7957 7958 // For the variable refresh rate project 7959 if (handled && shouldTouchBoost(action & MotionEvent.ACTION_MASK, 7960 mWindowAttributes.type)) { 7961 // set the frame rate to the maximum value. 7962 mIsTouchBoosting = true; 7963 setPreferredFrameRateCategory(mLastPreferredFrameRateCategory); 7964 } 7965 /** 7966 * We want to lower the refresh rate when MotionEvent.ACTION_UP, 7967 * MotionEvent.ACTION_CANCEL is detected. 7968 * Not using ACTION_MOVE to avoid checking and sending messages too frequently. 7969 */ 7970 if (mIsTouchBoosting && (action == MotionEvent.ACTION_UP 7971 || action == MotionEvent.ACTION_CANCEL)) { 7972 mHandler.removeMessages(MSG_TOUCH_BOOST_TIMEOUT); 7973 mHandler.sendEmptyMessageDelayed(MSG_TOUCH_BOOST_TIMEOUT, 7974 FRAME_RATE_TOUCH_BOOST_TIME); 7975 } 7976 return handled ? FINISH_HANDLED : FORWARD; 7977 } 7978 maybeUpdatePointerIcon(MotionEvent event)7979 private void maybeUpdatePointerIcon(MotionEvent event) { 7980 if (event.getPointerCount() != 1) { 7981 return; 7982 } 7983 final int action = event.getActionMasked(); 7984 final boolean needsStylusPointerIcon = event.isStylusPointer() 7985 && event.isHoverEvent() 7986 && mIsStylusPointerIconEnabled; 7987 if (!needsStylusPointerIcon && !event.isFromSource(InputDevice.SOURCE_MOUSE)) { 7988 return; 7989 } 7990 7991 if (action == MotionEvent.ACTION_HOVER_ENTER 7992 || action == MotionEvent.ACTION_HOVER_EXIT) { 7993 // Other apps or the window manager may change the icon type outside of 7994 // this app, therefore the icon type has to be reset on enter/exit event. 7995 mResolvedPointerIcon = null; 7996 } 7997 7998 if (action != MotionEvent.ACTION_HOVER_EXIT) { 7999 // Resolve the pointer icon 8000 if (!updatePointerIcon(event) && action == MotionEvent.ACTION_HOVER_MOVE) { 8001 mResolvedPointerIcon = null; 8002 } 8003 } 8004 8005 // Keep track of the newest event used to resolve the pointer icon. 8006 switch (action) { 8007 case MotionEvent.ACTION_HOVER_EXIT: 8008 case MotionEvent.ACTION_UP: 8009 case MotionEvent.ACTION_POINTER_UP: 8010 case MotionEvent.ACTION_CANCEL: 8011 if (mPointerIconEvent != null) { 8012 mPointerIconEvent.recycle(); 8013 } 8014 mPointerIconEvent = null; 8015 break; 8016 default: 8017 mPointerIconEvent = MotionEvent.obtain(event); 8018 break; 8019 } 8020 } 8021 processTrackballEvent(QueuedInputEvent q)8022 private int processTrackballEvent(QueuedInputEvent q) { 8023 final MotionEvent event = (MotionEvent)q.mEvent; 8024 8025 if (event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) { 8026 if (!hasPointerCapture() || mView.dispatchCapturedPointerEvent(event)) { 8027 return FINISH_HANDLED; 8028 } 8029 } 8030 8031 if (mView.dispatchTrackballEvent(event)) { 8032 return FINISH_HANDLED; 8033 } 8034 return FORWARD; 8035 } 8036 processGenericMotionEvent(QueuedInputEvent q)8037 private int processGenericMotionEvent(QueuedInputEvent q) { 8038 final MotionEvent event = (MotionEvent)q.mEvent; 8039 8040 if (event.isFromSource(InputDevice.SOURCE_TOUCHPAD)) { 8041 if (hasPointerCapture() && mView.dispatchCapturedPointerEvent(event)) { 8042 return FINISH_HANDLED; 8043 } 8044 } 8045 8046 // Deliver the event to the view. 8047 if (mView.dispatchGenericMotionEvent(event)) { 8048 return FINISH_HANDLED; 8049 } 8050 return FORWARD; 8051 } 8052 } 8053 8054 /** 8055 * Returns whether this view is currently handling a pointer event. 8056 * 8057 * @hide 8058 */ isHandlingPointerEvent()8059 public boolean isHandlingPointerEvent() { 8060 return mAttachInfo.mHandlingPointerEvent; 8061 } 8062 8063 8064 /** 8065 * If there is pointer that is showing a PointerIcon in this window, refresh the icon for that 8066 * pointer. This will resolve the PointerIcon through the view hierarchy. 8067 */ refreshPointerIcon()8068 public void refreshPointerIcon() { 8069 mHandler.removeMessages(MSG_REFRESH_POINTER_ICON); 8070 mHandler.sendEmptyMessage(MSG_REFRESH_POINTER_ICON); 8071 } 8072 updatePointerIcon(MotionEvent event)8073 private boolean updatePointerIcon(MotionEvent event) { 8074 final int pointerIndex = 0; 8075 final float x = event.getX(pointerIndex); 8076 final float y = event.getY(pointerIndex); 8077 if (mView == null) { 8078 // E.g. click outside a popup to dismiss it 8079 Slog.d(mTag, "updatePointerIcon called after view was removed"); 8080 return false; 8081 } 8082 if (x < 0 || x >= mView.getWidth() || y < 0 || y >= mView.getHeight()) { 8083 // E.g. when moving window divider with mouse 8084 Slog.d(mTag, "updatePointerIcon called with position out of bounds"); 8085 return false; 8086 } 8087 8088 PointerIcon pointerIcon = null; 8089 if (event.isStylusPointer() && mIsStylusPointerIconEnabled 8090 && (!disableHandwritingInitiatorForIme() 8091 || mWindowAttributes.type != TYPE_INPUT_METHOD)) { 8092 pointerIcon = mHandwritingInitiator.onResolvePointerIcon(mContext, event); 8093 } 8094 if (pointerIcon == null) { 8095 pointerIcon = mView.onResolvePointerIcon(event, pointerIndex); 8096 } 8097 if (pointerIcon == null) { 8098 pointerIcon = PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_NOT_SPECIFIED); 8099 } 8100 if (Objects.equals(mResolvedPointerIcon, pointerIcon)) { 8101 return true; 8102 } 8103 mResolvedPointerIcon = pointerIcon; 8104 8105 InputManagerGlobal.getInstance() 8106 .setPointerIcon(pointerIcon, event.getDisplayId(), 8107 event.getDeviceId(), event.getPointerId(0), getInputToken()); 8108 return true; 8109 } 8110 maybeUpdateTooltip(MotionEvent event)8111 private void maybeUpdateTooltip(MotionEvent event) { 8112 if (event.getPointerCount() != 1) { 8113 return; 8114 } 8115 final int action = event.getActionMasked(); 8116 if (action != MotionEvent.ACTION_HOVER_ENTER 8117 && action != MotionEvent.ACTION_HOVER_MOVE 8118 && action != MotionEvent.ACTION_HOVER_EXIT) { 8119 return; 8120 } 8121 if (mAccessibilityManager.isEnabled() 8122 && mAccessibilityManager.isTouchExplorationEnabled()) { 8123 return; 8124 } 8125 if (mView == null) { 8126 Slog.d(mTag, "maybeUpdateTooltip called after view was removed"); 8127 return; 8128 } 8129 mView.dispatchTooltipHoverEvent(event); 8130 } 8131 8132 @Nullable getFocusedViewOrNull()8133 private View getFocusedViewOrNull() { 8134 return mView != null ? mView.findFocus() : null; 8135 } 8136 8137 /** 8138 * Performs synthesis of new input events from unhandled input events. 8139 */ 8140 final class SyntheticInputStage extends InputStage { 8141 private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler(); 8142 private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler(); 8143 private final SyntheticTouchNavigationHandler mTouchNavigation = 8144 new SyntheticTouchNavigationHandler(); 8145 private final SyntheticKeyboardHandler mKeyboard = new SyntheticKeyboardHandler(); 8146 SyntheticInputStage()8147 public SyntheticInputStage() { 8148 super(null); 8149 } 8150 8151 @Override onProcess(QueuedInputEvent q)8152 protected int onProcess(QueuedInputEvent q) { 8153 q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED; 8154 if (q.mEvent instanceof MotionEvent) { 8155 final MotionEvent event = (MotionEvent)q.mEvent; 8156 final int source = event.getSource(); 8157 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { 8158 // Do not synthesize events for relative mouse movement. If apps opt into 8159 // relative mouse movement they must be prepared to handle the events. 8160 if (!event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) { 8161 mTrackball.process(event); 8162 } 8163 return FINISH_HANDLED; 8164 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { 8165 mJoystick.process(event); 8166 return FINISH_HANDLED; 8167 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION) 8168 == InputDevice.SOURCE_TOUCH_NAVIGATION) { 8169 mTouchNavigation.process(event); 8170 return FINISH_HANDLED; 8171 } 8172 } else if ((q.mFlags & QueuedInputEvent.FLAG_UNHANDLED) != 0) { 8173 mKeyboard.process((KeyEvent)q.mEvent); 8174 return FINISH_HANDLED; 8175 } 8176 8177 return FORWARD; 8178 } 8179 8180 @Override onDeliverToNext(QueuedInputEvent q)8181 protected void onDeliverToNext(QueuedInputEvent q) { 8182 if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) { 8183 // Cancel related synthetic events if any prior stage has handled the event. 8184 if (q.mEvent instanceof MotionEvent) { 8185 final MotionEvent event = (MotionEvent)q.mEvent; 8186 final int source = event.getSource(); 8187 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { 8188 mTrackball.cancel(); 8189 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { 8190 mJoystick.cancel(); 8191 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION) 8192 == InputDevice.SOURCE_TOUCH_NAVIGATION) { 8193 // Touch navigation events cannot be cancelled since they are dispatched 8194 // immediately. 8195 } 8196 } 8197 } 8198 super.onDeliverToNext(q); 8199 } 8200 8201 @Override onWindowFocusChanged(boolean hasWindowFocus)8202 protected void onWindowFocusChanged(boolean hasWindowFocus) { 8203 if (!hasWindowFocus) { 8204 mJoystick.cancel(); 8205 } 8206 } 8207 8208 @Override onDetachedFromWindow()8209 protected void onDetachedFromWindow() { 8210 mJoystick.cancel(); 8211 } 8212 } 8213 8214 /** 8215 * Creates dpad events from unhandled trackball movements. 8216 */ 8217 final class SyntheticTrackballHandler { 8218 private final TrackballAxis mX = new TrackballAxis(); 8219 private final TrackballAxis mY = new TrackballAxis(); 8220 private long mLastTime; 8221 process(MotionEvent event)8222 public void process(MotionEvent event) { 8223 // Translate the trackball event into DPAD keys and try to deliver those. 8224 long curTime = SystemClock.uptimeMillis(); 8225 if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) { 8226 // It has been too long since the last movement, 8227 // so restart at the beginning. 8228 mX.reset(0); 8229 mY.reset(0); 8230 mLastTime = curTime; 8231 } 8232 8233 final int action = event.getAction(); 8234 final int metaState = event.getMetaState(); 8235 switch (action) { 8236 case MotionEvent.ACTION_DOWN: 8237 mX.reset(2); 8238 mY.reset(2); 8239 enqueueInputEvent(new KeyEvent(curTime, curTime, 8240 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState, 8241 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, 8242 InputDevice.SOURCE_KEYBOARD)); 8243 break; 8244 case MotionEvent.ACTION_UP: 8245 mX.reset(2); 8246 mY.reset(2); 8247 enqueueInputEvent(new KeyEvent(curTime, curTime, 8248 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState, 8249 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, 8250 InputDevice.SOURCE_KEYBOARD)); 8251 break; 8252 } 8253 8254 if (DEBUG_TRACKBALL) Log.v(mTag, "TB X=" + mX.position + " step=" 8255 + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration 8256 + " move=" + event.getX() 8257 + " / Y=" + mY.position + " step=" 8258 + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration 8259 + " move=" + event.getY()); 8260 final float xOff = mX.collect(event.getX(), event.getEventTime(), "X"); 8261 final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y"); 8262 8263 // Generate DPAD events based on the trackball movement. 8264 // We pick the axis that has moved the most as the direction of 8265 // the DPAD. When we generate DPAD events for one axis, then the 8266 // other axis is reset -- we don't want to perform DPAD jumps due 8267 // to slight movements in the trackball when making major movements 8268 // along the other axis. 8269 int keycode = 0; 8270 int movement = 0; 8271 float accel = 1; 8272 if (xOff > yOff) { 8273 movement = mX.generate(); 8274 if (movement != 0) { 8275 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT 8276 : KeyEvent.KEYCODE_DPAD_LEFT; 8277 accel = mX.acceleration; 8278 mY.reset(2); 8279 } 8280 } else if (yOff > 0) { 8281 movement = mY.generate(); 8282 if (movement != 0) { 8283 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN 8284 : KeyEvent.KEYCODE_DPAD_UP; 8285 accel = mY.acceleration; 8286 mX.reset(2); 8287 } 8288 } 8289 8290 if (keycode != 0) { 8291 if (movement < 0) movement = -movement; 8292 int accelMovement = (int)(movement * accel); 8293 if (DEBUG_TRACKBALL) Log.v(mTag, "Move: movement=" + movement 8294 + " accelMovement=" + accelMovement 8295 + " accel=" + accel); 8296 if (accelMovement > movement) { 8297 if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: " 8298 + keycode); 8299 movement--; 8300 int repeatCount = accelMovement - movement; 8301 enqueueInputEvent(new KeyEvent(curTime, curTime, 8302 KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState, 8303 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, 8304 InputDevice.SOURCE_KEYBOARD)); 8305 } 8306 while (movement > 0) { 8307 if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: " 8308 + keycode); 8309 movement--; 8310 curTime = SystemClock.uptimeMillis(); 8311 enqueueInputEvent(new KeyEvent(curTime, curTime, 8312 KeyEvent.ACTION_DOWN, keycode, 0, metaState, 8313 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, 8314 InputDevice.SOURCE_KEYBOARD)); 8315 enqueueInputEvent(new KeyEvent(curTime, curTime, 8316 KeyEvent.ACTION_UP, keycode, 0, metaState, 8317 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK, 8318 InputDevice.SOURCE_KEYBOARD)); 8319 } 8320 mLastTime = curTime; 8321 } 8322 } 8323 cancel()8324 public void cancel() { 8325 mLastTime = Integer.MIN_VALUE; 8326 8327 // If we reach this, we consumed a trackball event. 8328 // Because we will not translate the trackball event into a key event, 8329 // touch mode will not exit, so we exit touch mode here. 8330 if (mView != null && mAdded) { 8331 ensureTouchMode(false); 8332 } 8333 } 8334 } 8335 8336 /** 8337 * Maintains state information for a single trackball axis, generating 8338 * discrete (DPAD) movements based on raw trackball motion. 8339 */ 8340 static final class TrackballAxis { 8341 /** 8342 * The maximum amount of acceleration we will apply. 8343 */ 8344 static final float MAX_ACCELERATION = 20; 8345 8346 /** 8347 * The maximum amount of time (in milliseconds) between events in order 8348 * for us to consider the user to be doing fast trackball movements, 8349 * and thus apply an acceleration. 8350 */ 8351 static final long FAST_MOVE_TIME = 150; 8352 8353 /** 8354 * Scaling factor to the time (in milliseconds) between events to how 8355 * much to multiple/divide the current acceleration. When movement 8356 * is < FAST_MOVE_TIME this multiplies the acceleration; when > 8357 * FAST_MOVE_TIME it divides it. 8358 */ 8359 static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40); 8360 8361 static final float FIRST_MOVEMENT_THRESHOLD = 0.5f; 8362 static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f; 8363 static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f; 8364 8365 float position; 8366 float acceleration = 1; 8367 long lastMoveTime = 0; 8368 int step; 8369 int dir; 8370 int nonAccelMovement; 8371 reset(int _step)8372 void reset(int _step) { 8373 position = 0; 8374 acceleration = 1; 8375 lastMoveTime = 0; 8376 step = _step; 8377 dir = 0; 8378 } 8379 8380 /** 8381 * Add trackball movement into the state. If the direction of movement 8382 * has been reversed, the state is reset before adding the 8383 * movement (so that you don't have to compensate for any previously 8384 * collected movement before see the result of the movement in the 8385 * new direction). 8386 * 8387 * @return Returns the absolute value of the amount of movement 8388 * collected so far. 8389 */ collect(float off, long time, String axis)8390 float collect(float off, long time, String axis) { 8391 long normTime; 8392 if (off > 0) { 8393 normTime = (long)(off * FAST_MOVE_TIME); 8394 if (dir < 0) { 8395 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!"); 8396 position = 0; 8397 step = 0; 8398 acceleration = 1; 8399 lastMoveTime = 0; 8400 } 8401 dir = 1; 8402 } else if (off < 0) { 8403 normTime = (long)((-off) * FAST_MOVE_TIME); 8404 if (dir > 0) { 8405 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!"); 8406 position = 0; 8407 step = 0; 8408 acceleration = 1; 8409 lastMoveTime = 0; 8410 } 8411 dir = -1; 8412 } else { 8413 normTime = 0; 8414 } 8415 8416 // The number of milliseconds between each movement that is 8417 // considered "normal" and will not result in any acceleration 8418 // or deceleration, scaled by the offset we have here. 8419 if (normTime > 0) { 8420 long delta = time - lastMoveTime; 8421 lastMoveTime = time; 8422 float acc = acceleration; 8423 if (delta < normTime) { 8424 // The user is scrolling rapidly, so increase acceleration. 8425 float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR; 8426 if (scale > 1) acc *= scale; 8427 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off=" 8428 + off + " normTime=" + normTime + " delta=" + delta 8429 + " scale=" + scale + " acc=" + acc); 8430 acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION; 8431 } else { 8432 // The user is scrolling slowly, so decrease acceleration. 8433 float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR; 8434 if (scale > 1) acc /= scale; 8435 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off=" 8436 + off + " normTime=" + normTime + " delta=" + delta 8437 + " scale=" + scale + " acc=" + acc); 8438 acceleration = acc > 1 ? acc : 1; 8439 } 8440 } 8441 position += off; 8442 return Math.abs(position); 8443 } 8444 8445 /** 8446 * Generate the number of discrete movement events appropriate for 8447 * the currently collected trackball movement. 8448 * 8449 * @return Returns the number of discrete movements, either positive 8450 * or negative, or 0 if there is not enough trackball movement yet 8451 * for a discrete movement. 8452 */ generate()8453 int generate() { 8454 int movement = 0; 8455 nonAccelMovement = 0; 8456 do { 8457 final int dir = position >= 0 ? 1 : -1; 8458 switch (step) { 8459 // If we are going to execute the first step, then we want 8460 // to do this as soon as possible instead of waiting for 8461 // a full movement, in order to make things look responsive. 8462 case 0: 8463 if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) { 8464 return movement; 8465 } 8466 movement += dir; 8467 nonAccelMovement += dir; 8468 step = 1; 8469 break; 8470 // If we have generated the first movement, then we need 8471 // to wait for the second complete trackball motion before 8472 // generating the second discrete movement. 8473 case 1: 8474 if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) { 8475 return movement; 8476 } 8477 movement += dir; 8478 nonAccelMovement += dir; 8479 position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir; 8480 step = 2; 8481 break; 8482 // After the first two, we generate discrete movements 8483 // consistently with the trackball, applying an acceleration 8484 // if the trackball is moving quickly. This is a simple 8485 // acceleration on top of what we already compute based 8486 // on how quickly the wheel is being turned, to apply 8487 // a longer increasing acceleration to continuous movement 8488 // in one direction. 8489 default: 8490 if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) { 8491 return movement; 8492 } 8493 movement += dir; 8494 position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD; 8495 float acc = acceleration; 8496 acc *= 1.1f; 8497 acceleration = acc < MAX_ACCELERATION ? acc : acceleration; 8498 break; 8499 } 8500 } while (true); 8501 } 8502 } 8503 8504 /** 8505 * Creates dpad events from unhandled joystick movements. 8506 */ 8507 final class SyntheticJoystickHandler extends Handler { 8508 private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1; 8509 private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2; 8510 8511 private final JoystickAxesState mJoystickAxesState = new JoystickAxesState(); 8512 private final SparseArray<KeyEvent> mDeviceKeyEvents = new SparseArray<>(); 8513 8514 public SyntheticJoystickHandler() { 8515 super(true); 8516 } 8517 8518 @Override 8519 public void handleMessage(Message msg) { 8520 switch (msg.what) { 8521 case MSG_ENQUEUE_X_AXIS_KEY_REPEAT: 8522 case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: { 8523 if (mAttachInfo.mHasWindowFocus) { 8524 KeyEvent oldEvent = (KeyEvent) msg.obj; 8525 KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent, 8526 SystemClock.uptimeMillis(), oldEvent.getRepeatCount() + 1); 8527 enqueueInputEvent(e); 8528 Message m = obtainMessage(msg.what, e); 8529 m.setAsynchronous(true); 8530 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay()); 8531 } 8532 } break; 8533 } 8534 } 8535 8536 public void process(MotionEvent event) { 8537 switch(event.getActionMasked()) { 8538 case MotionEvent.ACTION_CANCEL: 8539 cancel(); 8540 break; 8541 case MotionEvent.ACTION_MOVE: 8542 update(event); 8543 break; 8544 default: 8545 Log.w(mTag, "Unexpected action: " + event.getActionMasked()); 8546 } 8547 } 8548 8549 private void cancel() { 8550 removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT); 8551 removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT); 8552 for (int i = 0; i < mDeviceKeyEvents.size(); i++) { 8553 final KeyEvent keyEvent = mDeviceKeyEvents.valueAt(i); 8554 if (keyEvent != null) { 8555 enqueueInputEvent(KeyEvent.changeTimeRepeat(keyEvent, 8556 SystemClock.uptimeMillis(), 0)); 8557 } 8558 } 8559 mDeviceKeyEvents.clear(); 8560 mJoystickAxesState.resetState(); 8561 } 8562 8563 private void update(MotionEvent event) { 8564 final int historySize = event.getHistorySize(); 8565 for (int h = 0; h < historySize; h++) { 8566 final long time = event.getHistoricalEventTime(h); 8567 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X, 8568 event.getHistoricalAxisValue(MotionEvent.AXIS_X, 0, h)); 8569 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y, 8570 event.getHistoricalAxisValue(MotionEvent.AXIS_Y, 0, h)); 8571 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X, 8572 event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_X, 0, h)); 8573 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y, 8574 event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_Y, 0, h)); 8575 } 8576 final long time = event.getEventTime(); 8577 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X, 8578 event.getAxisValue(MotionEvent.AXIS_X)); 8579 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y, 8580 event.getAxisValue(MotionEvent.AXIS_Y)); 8581 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X, 8582 event.getAxisValue(MotionEvent.AXIS_HAT_X)); 8583 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y, 8584 event.getAxisValue(MotionEvent.AXIS_HAT_Y)); 8585 } 8586 8587 final class JoystickAxesState { 8588 // State machine: from neutral state (no button press) can go into 8589 // button STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state, emitting an ACTION_DOWN event. 8590 // From STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state can go into neutral state, 8591 // emitting an ACTION_UP event. 8592 private static final int STATE_UP_OR_LEFT = -1; 8593 private static final int STATE_NEUTRAL = 0; 8594 private static final int STATE_DOWN_OR_RIGHT = 1; 8595 8596 final int[] mAxisStatesHat = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_HAT_X, AXIS_HAT_Y} 8597 final int[] mAxisStatesStick = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_X, AXIS_Y} 8598 8599 void resetState() { 8600 mAxisStatesHat[0] = STATE_NEUTRAL; 8601 mAxisStatesHat[1] = STATE_NEUTRAL; 8602 mAxisStatesStick[0] = STATE_NEUTRAL; 8603 mAxisStatesStick[1] = STATE_NEUTRAL; 8604 } 8605 8606 void updateStateForAxis(MotionEvent event, long time, int axis, float value) { 8607 // Emit KeyEvent if necessary 8608 // axis can be AXIS_X, AXIS_Y, AXIS_HAT_X, AXIS_HAT_Y 8609 final int axisStateIndex; 8610 final int repeatMessage; 8611 if (isXAxis(axis)) { 8612 axisStateIndex = 0; 8613 repeatMessage = MSG_ENQUEUE_X_AXIS_KEY_REPEAT; 8614 } else if (isYAxis(axis)) { 8615 axisStateIndex = 1; 8616 repeatMessage = MSG_ENQUEUE_Y_AXIS_KEY_REPEAT; 8617 } else { 8618 Log.e(mTag, "Unexpected axis " + axis + " in updateStateForAxis!"); 8619 return; 8620 } 8621 final int newState = joystickAxisValueToState(value); 8622 8623 final int currentState; 8624 if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) { 8625 currentState = mAxisStatesStick[axisStateIndex]; 8626 } else { 8627 currentState = mAxisStatesHat[axisStateIndex]; 8628 } 8629 8630 if (currentState == newState) { 8631 return; 8632 } 8633 8634 final int metaState = event.getMetaState(); 8635 final int deviceId = event.getDeviceId(); 8636 final int source = event.getSource(); 8637 8638 if (currentState == STATE_DOWN_OR_RIGHT || currentState == STATE_UP_OR_LEFT) { 8639 // send a button release event 8640 final int keyCode = joystickAxisAndStateToKeycode(axis, currentState); 8641 if (keyCode != KeyEvent.KEYCODE_UNKNOWN) { 8642 enqueueInputEvent(new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode, 8643 0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source)); 8644 // remove the corresponding pending UP event if focus lost/view detached 8645 mDeviceKeyEvents.put(deviceId, null); 8646 } 8647 removeMessages(repeatMessage); 8648 } 8649 8650 if (newState == STATE_DOWN_OR_RIGHT || newState == STATE_UP_OR_LEFT) { 8651 // send a button down event 8652 final int keyCode = joystickAxisAndStateToKeycode(axis, newState); 8653 if (keyCode != KeyEvent.KEYCODE_UNKNOWN) { 8654 KeyEvent keyEvent = new KeyEvent(time, time, KeyEvent.ACTION_DOWN, keyCode, 8655 0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source); 8656 enqueueInputEvent(keyEvent); 8657 Message m = obtainMessage(repeatMessage, keyEvent); 8658 m.setAsynchronous(true); 8659 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout()); 8660 // store the corresponding ACTION_UP event so that it can be sent 8661 // if focus is lost or root view is removed 8662 mDeviceKeyEvents.put(deviceId, 8663 new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode, 8664 0, metaState, deviceId, 0, 8665 KeyEvent.FLAG_FALLBACK | KeyEvent.FLAG_CANCELED, 8666 source)); 8667 } 8668 } 8669 if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) { 8670 mAxisStatesStick[axisStateIndex] = newState; 8671 } else { 8672 mAxisStatesHat[axisStateIndex] = newState; 8673 } 8674 } 8675 8676 private boolean isXAxis(int axis) { 8677 return axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_HAT_X; 8678 } 8679 private boolean isYAxis(int axis) { 8680 return axis == MotionEvent.AXIS_Y || axis == MotionEvent.AXIS_HAT_Y; 8681 } 8682 8683 private int joystickAxisAndStateToKeycode(int axis, int state) { 8684 if (isXAxis(axis) && state == STATE_UP_OR_LEFT) { 8685 return KeyEvent.KEYCODE_DPAD_LEFT; 8686 } 8687 if (isXAxis(axis) && state == STATE_DOWN_OR_RIGHT) { 8688 return KeyEvent.KEYCODE_DPAD_RIGHT; 8689 } 8690 if (isYAxis(axis) && state == STATE_UP_OR_LEFT) { 8691 return KeyEvent.KEYCODE_DPAD_UP; 8692 } 8693 if (isYAxis(axis) && state == STATE_DOWN_OR_RIGHT) { 8694 return KeyEvent.KEYCODE_DPAD_DOWN; 8695 } 8696 Log.e(mTag, "Unknown axis " + axis + " or direction " + state); 8697 return KeyEvent.KEYCODE_UNKNOWN; // should never happen 8698 } 8699 8700 private int joystickAxisValueToState(float value) { 8701 if (value >= 0.5f) { 8702 return STATE_DOWN_OR_RIGHT; 8703 } else if (value <= -0.5f) { 8704 return STATE_UP_OR_LEFT; 8705 } else { 8706 return STATE_NEUTRAL; 8707 } 8708 } 8709 } 8710 } 8711 8712 /** 8713 * Creates DPAD events from unhandled touch navigation movements. 8714 */ 8715 final class SyntheticTouchNavigationHandler extends Handler { 8716 private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler"; 8717 8718 // The id of the input device that is being tracked. 8719 private int mCurrentDeviceId = -1; 8720 private int mCurrentSource; 8721 8722 private int mPendingKeyMetaState; 8723 8724 private final GestureDetector mGestureDetector; 8725 8726 SyntheticTouchNavigationHandler() { 8727 super(true); 8728 int gestureDetectorVelocityStrategy = 8729 android.companion.virtual.flags.Flags 8730 .impulseVelocityStrategyForTouchNavigation() 8731 ? VelocityTracker.VELOCITY_TRACKER_STRATEGY_IMPULSE 8732 : VelocityTracker.VELOCITY_TRACKER_STRATEGY_DEFAULT; 8733 mGestureDetector = new GestureDetector(mContext, 8734 new GestureDetector.OnGestureListener() { 8735 @Override 8736 public boolean onDown(@NonNull MotionEvent e) { 8737 // This can be ignored since it's not clear what KeyEvent this will 8738 // belong to. 8739 return true; 8740 } 8741 8742 @Override 8743 public void onShowPress(@NonNull MotionEvent e) { 8744 } 8745 8746 @Override 8747 public boolean onSingleTapUp(@NonNull MotionEvent e) { 8748 dispatchTap(e.getEventTime()); 8749 return true; 8750 } 8751 8752 @Override 8753 public boolean onScroll(@Nullable MotionEvent e1, @NonNull MotionEvent e2, 8754 float distanceX, float distanceY) { 8755 // Scroll doesn't translate to DPAD events so should be ignored. 8756 return true; 8757 } 8758 8759 @Override 8760 public void onLongPress(@NonNull MotionEvent e) { 8761 // Long presses don't translate to DPAD events so should be ignored. 8762 } 8763 8764 @Override 8765 public boolean onFling(@Nullable MotionEvent e1, @NonNull MotionEvent e2, 8766 float velocityX, float velocityY) { 8767 dispatchFling(velocityX, velocityY, e2.getEventTime()); 8768 return true; 8769 } 8770 }, 8771 /* handler= */ null, 8772 gestureDetectorVelocityStrategy); 8773 } 8774 8775 public void process(MotionEvent event) { 8776 if (event.getDevice() == null) { 8777 // The current device is not supported. 8778 if (DEBUG_TOUCH_NAVIGATION) { 8779 Log.d(LOCAL_TAG, 8780 "Current device not supported so motion event is not processed"); 8781 } 8782 return; 8783 } 8784 mPendingKeyMetaState = event.getMetaState(); 8785 // Update the current device information. 8786 final int deviceId = event.getDeviceId(); 8787 final int source = event.getSource(); 8788 if (mCurrentDeviceId != deviceId || mCurrentSource != source) { 8789 mCurrentDeviceId = deviceId; 8790 mCurrentSource = source; 8791 } 8792 8793 // Interpret the event. 8794 mGestureDetector.onTouchEvent(event); 8795 } 8796 8797 private void dispatchTap(long time) { 8798 dispatchEvent(time, KeyEvent.KEYCODE_DPAD_CENTER); 8799 } 8800 8801 private void dispatchFling(float x, float y, long time) { 8802 if (Math.abs(x) > Math.abs(y)) { 8803 dispatchEvent(time, 8804 x > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT); 8805 } else { 8806 dispatchEvent(time, y > 0 ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP); 8807 } 8808 } 8809 dispatchEvent(long time, int keyCode)8810 private void dispatchEvent(long time, int keyCode) { 8811 if (DEBUG_TOUCH_NAVIGATION) { 8812 Log.d(LOCAL_TAG, "Dispatching DPAD events DOWN and UP with keycode " + keyCode); 8813 } 8814 enqueueInputEvent(new KeyEvent(time, time, 8815 KeyEvent.ACTION_DOWN, keyCode, /* repeat= */ 0, mPendingKeyMetaState, 8816 mCurrentDeviceId, /* scancode= */ 0, KeyEvent.FLAG_FALLBACK, 8817 mCurrentSource)); 8818 enqueueInputEvent(new KeyEvent(time, time, 8819 KeyEvent.ACTION_UP, keyCode, /* repeat= */ 0, mPendingKeyMetaState, 8820 mCurrentDeviceId, /* scancode= */ 0, KeyEvent.FLAG_FALLBACK, 8821 mCurrentSource)); 8822 } 8823 } 8824 8825 final class SyntheticKeyboardHandler { process(KeyEvent event)8826 public void process(KeyEvent event) { 8827 if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) { 8828 return; 8829 } 8830 8831 final KeyCharacterMap kcm = event.getKeyCharacterMap(); 8832 final int keyCode = event.getKeyCode(); 8833 final int metaState = event.getMetaState(); 8834 8835 // Check for fallback actions specified by the key character map. 8836 KeyCharacterMap.FallbackAction fallbackAction = 8837 kcm.getFallbackAction(keyCode, metaState); 8838 if (fallbackAction != null) { 8839 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK; 8840 KeyEvent fallbackEvent = KeyEvent.obtain( 8841 event.getDownTime(), event.getEventTime(), 8842 event.getAction(), fallbackAction.keyCode, 8843 event.getRepeatCount(), fallbackAction.metaState, 8844 event.getDeviceId(), event.getScanCode(), 8845 flags, event.getSource(), null); 8846 fallbackAction.recycle(); 8847 enqueueInputEvent(fallbackEvent); 8848 } 8849 } 8850 } 8851 8852 /** 8853 * Returns true if the key is used for keyboard navigation. 8854 * @param keyEvent The key event. 8855 * @return True if the key is used for keyboard navigation. 8856 */ isNavigationKey(KeyEvent keyEvent)8857 private static boolean isNavigationKey(KeyEvent keyEvent) { 8858 switch (keyEvent.getKeyCode()) { 8859 case KeyEvent.KEYCODE_DPAD_LEFT: 8860 case KeyEvent.KEYCODE_DPAD_RIGHT: 8861 case KeyEvent.KEYCODE_DPAD_UP: 8862 case KeyEvent.KEYCODE_DPAD_DOWN: 8863 case KeyEvent.KEYCODE_DPAD_CENTER: 8864 case KeyEvent.KEYCODE_PAGE_UP: 8865 case KeyEvent.KEYCODE_PAGE_DOWN: 8866 case KeyEvent.KEYCODE_MOVE_HOME: 8867 case KeyEvent.KEYCODE_MOVE_END: 8868 case KeyEvent.KEYCODE_TAB: 8869 case KeyEvent.KEYCODE_SPACE: 8870 case KeyEvent.KEYCODE_ENTER: 8871 return true; 8872 } 8873 return false; 8874 } 8875 8876 /** 8877 * Returns true if the key is used for typing. 8878 * @param keyEvent The key event. 8879 * @return True if the key is used for typing. 8880 */ isTypingKey(KeyEvent keyEvent)8881 private static boolean isTypingKey(KeyEvent keyEvent) { 8882 return keyEvent.getUnicodeChar() > 0; 8883 } 8884 8885 /** 8886 * See if the key event means we should leave touch mode (and leave touch mode if so). 8887 * @param event The key event. 8888 * @return Whether this key event should be consumed (meaning the act of 8889 * leaving touch mode alone is considered the event). 8890 */ checkForLeavingTouchModeAndConsume(KeyEvent event)8891 private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) { 8892 // Only relevant in touch mode. 8893 if (!mAttachInfo.mInTouchMode) { 8894 return false; 8895 } 8896 8897 // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP. 8898 final int action = event.getAction(); 8899 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) { 8900 return false; 8901 } 8902 8903 // Don't leave touch mode if the IME told us not to. 8904 if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) { 8905 return false; 8906 } 8907 8908 // If the key can be used for keyboard navigation then leave touch mode 8909 // and select a focused view if needed (in ensureTouchMode). 8910 // When a new focused view is selected, we consume the navigation key because 8911 // navigation doesn't make much sense unless a view already has focus so 8912 // the key's purpose is to set focus. 8913 if (event.hasNoModifiers() && isNavigationKey(event)) { 8914 return ensureTouchMode(false); 8915 } 8916 8917 // If the key can be used for typing then leave touch mode 8918 // and select a focused view if needed (in ensureTouchMode). 8919 // Always allow the view to process the typing key. 8920 if (isTypingKey(event)) { 8921 ensureTouchMode(false); 8922 return false; 8923 } 8924 8925 return false; 8926 } 8927 8928 /* drag/drop */ 8929 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setLocalDragState(Object obj)8930 void setLocalDragState(Object obj) { 8931 mLocalDragState = obj; 8932 } 8933 handleDragEvent(DragEvent event)8934 private void handleDragEvent(DragEvent event) { 8935 // From the root, only drag start/end/location are dispatched. entered/exited 8936 // are determined and dispatched by the viewgroup hierarchy, who then report 8937 // that back here for ultimate reporting back to the framework. 8938 if (mView != null && mAdded) { 8939 final int what = event.mAction; 8940 8941 // Cache the drag description when the operation starts, then fill it in 8942 // on subsequent calls as a convenience 8943 if (what == DragEvent.ACTION_DRAG_STARTED) { 8944 mCurrentDragView = null; // Start the current-recipient tracking 8945 mDragDescription = event.mClipDescription; 8946 if (mStartedDragViewForA11y != null) { 8947 // Send a drag started a11y event 8948 mStartedDragViewForA11y.sendWindowContentChangedAccessibilityEvent( 8949 AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_STARTED); 8950 } 8951 } else { 8952 if (what == DragEvent.ACTION_DRAG_ENDED) { 8953 mDragDescription = null; 8954 } 8955 event.mClipDescription = mDragDescription; 8956 } 8957 8958 if (what == DragEvent.ACTION_DRAG_EXITED) { 8959 // A direct EXITED event means that the window manager knows we've just crossed 8960 // a window boundary, so the current drag target within this one must have 8961 // just been exited. Send the EXITED notification to the current drag view, if any. 8962 if (View.sCascadedDragDrop) { 8963 mView.dispatchDragEnterExitInPreN(event); 8964 } 8965 setDragFocus(null, event); 8966 } else { 8967 // For events with a [screen] location, translate into window coordinates 8968 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) { 8969 mDragPoint.set(event.mX, event.mY); 8970 if (mTranslator != null) { 8971 mTranslator.translatePointInScreenToAppWindow(mDragPoint); 8972 } 8973 8974 if (mCurScrollY != 0) { 8975 mDragPoint.offset(0, mCurScrollY); 8976 } 8977 8978 event.mX = mDragPoint.x; 8979 event.mY = mDragPoint.y; 8980 } 8981 8982 // Remember who the current drag target is pre-dispatch 8983 final View prevDragView = mCurrentDragView; 8984 8985 if (what == DragEvent.ACTION_DROP && event.mClipData != null) { 8986 event.mClipData.prepareToEnterProcess( 8987 mView.getContext().getAttributionSource()); 8988 } 8989 8990 // Now dispatch the drag/drop event 8991 boolean result = mView.dispatchDragEvent(event); 8992 8993 if (what == DragEvent.ACTION_DRAG_LOCATION && !event.mEventHandlerWasCalled) { 8994 // If the LOCATION event wasn't delivered to any handler, no view now has a drag 8995 // focus. 8996 setDragFocus(null, event); 8997 } 8998 8999 // If we changed apparent drag target, tell the OS about it 9000 if (prevDragView != mCurrentDragView) { 9001 try { 9002 if (prevDragView != null) { 9003 mWindowSession.dragRecipientExited(mWindow); 9004 } 9005 if (mCurrentDragView != null) { 9006 mWindowSession.dragRecipientEntered(mWindow); 9007 } 9008 } catch (RemoteException e) { 9009 Slog.e(mTag, "Unable to note drag target change"); 9010 } 9011 } 9012 9013 // Report the drop result when we're done 9014 if (what == DragEvent.ACTION_DROP) { 9015 try { 9016 Log.i(mTag, "Reporting drop result: " + result); 9017 mWindowSession.reportDropResult(mWindow, result); 9018 } catch (RemoteException e) { 9019 Log.e(mTag, "Unable to report drop result"); 9020 } 9021 } 9022 9023 // When the drag operation ends, reset drag-related state 9024 if (what == DragEvent.ACTION_DRAG_ENDED) { 9025 if (mStartedDragViewForA11y != null) { 9026 // If the drag failed, send a cancelled event from the source. Otherwise, 9027 // the View that accepted the drop sends CONTENT_CHANGE_TYPE_DRAG_DROPPED 9028 if (!event.getResult()) { 9029 mStartedDragViewForA11y.sendWindowContentChangedAccessibilityEvent( 9030 AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_CANCELLED); 9031 } 9032 mStartedDragViewForA11y.setAccessibilityDragStarted(false); 9033 } 9034 mStartedDragViewForA11y = null; 9035 mCurrentDragView = null; 9036 setLocalDragState(null); 9037 mAttachInfo.mDragToken = null; 9038 if (mAttachInfo.mDragSurface != null) { 9039 mAttachInfo.mDragSurface.release(); 9040 mAttachInfo.mDragSurface = null; 9041 } 9042 if (mAttachInfo.mDragData != null) { 9043 View.cleanUpPendingIntents(mAttachInfo.mDragData); 9044 mAttachInfo.mDragData = null; 9045 } 9046 } 9047 } 9048 } 9049 event.recycle(); 9050 } 9051 9052 /** 9053 * Notify that the window title changed 9054 */ onWindowTitleChanged()9055 public void onWindowTitleChanged() { 9056 mAttachInfo.mForceReportNewAttributes = true; 9057 } 9058 handleDispatchWindowShown()9059 public void handleDispatchWindowShown() { 9060 mAttachInfo.mTreeObserver.dispatchOnWindowShown(); 9061 } 9062 handleRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId)9063 public void handleRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) { 9064 Bundle data = new Bundle(); 9065 ArrayList<KeyboardShortcutGroup> list = new ArrayList<>(); 9066 if (mView != null) { 9067 mView.requestKeyboardShortcuts(list, deviceId); 9068 } 9069 int numGroups = list.size(); 9070 for (int i = 0; i < numGroups; ++i) { 9071 final KeyboardShortcutGroup group = list.get(i); 9072 group.setPackageName(mBasePackageName); 9073 9074 } 9075 data.putParcelableArrayList(WindowManager.PARCEL_KEY_SHORTCUTS_ARRAY, list); 9076 try { 9077 receiver.send(0, data); 9078 } catch (RemoteException e) { 9079 } 9080 } 9081 9082 @UnsupportedAppUsage getLastTouchPoint(Point outLocation)9083 public void getLastTouchPoint(Point outLocation) { 9084 outLocation.x = (int) mLastTouchPoint.x; 9085 outLocation.y = (int) mLastTouchPoint.y; 9086 } 9087 getLastTouchSource()9088 public int getLastTouchSource() { 9089 return mLastTouchSource; 9090 } 9091 getLastTouchDeviceId()9092 public int getLastTouchDeviceId() { 9093 return mLastTouchDeviceId; 9094 } 9095 getLastTouchPointerId()9096 public int getLastTouchPointerId() { 9097 return mLastTouchPointerId; 9098 } 9099 9100 /** 9101 * Used by InputMethodManager. 9102 * @hide 9103 */ getLastClickToolType()9104 public int getLastClickToolType() { 9105 return mLastClickToolType; 9106 } 9107 setDragFocus(View newDragTarget, DragEvent event)9108 public void setDragFocus(View newDragTarget, DragEvent event) { 9109 if (mCurrentDragView != newDragTarget && !View.sCascadedDragDrop) { 9110 // Send EXITED and ENTERED notifications to the old and new drag focus views. 9111 9112 final float tx = event.mX; 9113 final float ty = event.mY; 9114 final int action = event.mAction; 9115 final ClipData td = event.mClipData; 9116 // Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED. 9117 event.mX = 0; 9118 event.mY = 0; 9119 event.mClipData = null; 9120 9121 if (mCurrentDragView != null) { 9122 event.mAction = DragEvent.ACTION_DRAG_EXITED; 9123 mCurrentDragView.callDragEventHandler(event); 9124 } 9125 9126 if (newDragTarget != null) { 9127 event.mAction = DragEvent.ACTION_DRAG_ENTERED; 9128 newDragTarget.callDragEventHandler(event); 9129 } 9130 9131 event.mAction = action; 9132 event.mX = tx; 9133 event.mY = ty; 9134 event.mClipData = td; 9135 } 9136 9137 mCurrentDragView = newDragTarget; 9138 } 9139 9140 /** Sets the view that started drag and drop for the purpose of sending AccessibilityEvents */ setDragStartedViewForAccessibility(View view)9141 void setDragStartedViewForAccessibility(View view) { 9142 if (mStartedDragViewForA11y == null) { 9143 mStartedDragViewForA11y = view; 9144 } 9145 } 9146 getAudioManager()9147 private AudioManager getAudioManager() { 9148 if (mView == null) { 9149 throw new IllegalStateException("getAudioManager called when there is no mView"); 9150 } 9151 if (mAudioManager == null) { 9152 mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE); 9153 mFastScrollSoundEffectsEnabled = mAudioManager.areNavigationRepeatSoundEffectsEnabled(); 9154 } 9155 return mAudioManager; 9156 } 9157 getAutofillManager()9158 private @Nullable AutofillManager getAutofillManager() { 9159 if (mView instanceof ViewGroup) { 9160 ViewGroup decorView = (ViewGroup) mView; 9161 if (decorView.getChildCount() > 0) { 9162 // We cannot use decorView's Context for querying AutofillManager: DecorView's 9163 // context is based on Application Context, it would allocate a different 9164 // AutofillManager instance. 9165 return decorView.getChildAt(0).getContext() 9166 .getSystemService(AutofillManager.class); 9167 } 9168 } 9169 return null; 9170 } 9171 isAutofillUiShowing()9172 private boolean isAutofillUiShowing() { 9173 AutofillManager afm = getAutofillManager(); 9174 if (afm == null) { 9175 return false; 9176 } 9177 return afm.isAutofillUiShowing(); 9178 } 9179 getAccessibilityInteractionController()9180 public AccessibilityInteractionController getAccessibilityInteractionController() { 9181 if (mView == null) { 9182 throw new IllegalStateException("getAccessibilityInteractionController" 9183 + " called when there is no mView"); 9184 } 9185 if (mAccessibilityInteractionController == null) { 9186 mAccessibilityInteractionController = new AccessibilityInteractionController(this); 9187 } 9188 return mAccessibilityInteractionController; 9189 } 9190 relayoutWindow(WindowManager.LayoutParams params, int viewVisibility, boolean insetsPending)9191 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility, 9192 boolean insetsPending) throws RemoteException { 9193 final WindowConfiguration winConfigFromAm = getConfiguration().windowConfiguration; 9194 final WindowConfiguration winConfigFromWm = 9195 mLastReportedMergedConfiguration.getGlobalConfiguration().windowConfiguration; 9196 final WindowConfiguration winConfig = getCompatWindowConfiguration(); 9197 final int measuredWidth = mMeasuredWidth; 9198 final int measuredHeight = mMeasuredHeight; 9199 final boolean relayoutAsync; 9200 if ((mViewFrameInfo.flags & FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED) == 0 9201 && mWindowAttributes.type != TYPE_APPLICATION_STARTING 9202 && mSyncSeqId <= mLastSyncSeqId 9203 && winConfigFromAm.diff(winConfigFromWm, false /* compareUndefined */) == 0) { 9204 final InsetsState state = mInsetsController.getState(); 9205 final Rect displayCutoutSafe = mTempRect; 9206 state.getDisplayCutoutSafe(displayCutoutSafe); 9207 mWindowLayout.computeFrames(mWindowAttributes.forRotation(winConfig.getRotation()), 9208 state, displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(), 9209 measuredWidth, measuredHeight, mInsetsController.getRequestedVisibleTypes(), 9210 1f /* compatScale */, mTmpFrames); 9211 mWinFrameInScreen.set(mTmpFrames.frame); 9212 if (mTranslator != null) { 9213 mTranslator.translateRectInAppWindowToScreen(mWinFrameInScreen); 9214 } 9215 9216 // If the position and the size of the frame are both changed, it will trigger a BLAST 9217 // sync, and we still need to call relayout to obtain the syncSeqId. Otherwise, we just 9218 // need to send attributes via relayoutAsync. 9219 final Rect oldFrame = mLastLayoutFrame; 9220 final Rect newFrame = mTmpFrames.frame; 9221 final boolean positionChanged = 9222 newFrame.top != oldFrame.top || newFrame.left != oldFrame.left; 9223 final boolean sizeChanged = 9224 newFrame.width() != oldFrame.width() || newFrame.height() != oldFrame.height(); 9225 relayoutAsync = !positionChanged || !sizeChanged; 9226 } else { 9227 relayoutAsync = false; 9228 } 9229 9230 float appScale = mAttachInfo.mApplicationScale; 9231 boolean restore = false; 9232 if (params != null && mTranslator != null) { 9233 restore = true; 9234 params.backup(); 9235 mTranslator.translateWindowLayout(params); 9236 } 9237 9238 if (params != null) { 9239 if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params); 9240 9241 if (mOrigWindowType != params.type) { 9242 // For compatibility with old apps, don't crash here. 9243 if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 9244 Slog.w(mTag, "Window type can not be changed after " 9245 + "the window is added; ignoring change of " + mView); 9246 params.type = mOrigWindowType; 9247 } 9248 } 9249 } 9250 9251 final int requestedWidth = (int) (measuredWidth * appScale + 0.5f); 9252 final int requestedHeight = (int) (measuredHeight * appScale + 0.5f); 9253 int relayoutResult = 0; 9254 mRelayoutSeq++; 9255 if (relayoutAsync) { 9256 mWindowSession.relayoutAsync(mWindow, params, 9257 requestedWidth, requestedHeight, viewVisibility, 9258 insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mRelayoutSeq, 9259 mLastSyncSeqId); 9260 } else { 9261 if (windowSessionRelayoutInfo()) { 9262 relayoutResult = mWindowSession.relayout(mWindow, params, 9263 requestedWidth, requestedHeight, viewVisibility, 9264 insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, 9265 mRelayoutSeq, mLastSyncSeqId, mRelayoutResult); 9266 } else { 9267 relayoutResult = mWindowSession.relayoutLegacy(mWindow, params, 9268 requestedWidth, requestedHeight, viewVisibility, 9269 insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, 9270 mRelayoutSeq, mLastSyncSeqId, mTmpFrames, mPendingMergedConfiguration, 9271 mSurfaceControl, mTempInsets, mTempControls, mRelayoutBundle); 9272 } 9273 mRelayoutRequested = true; 9274 9275 if (activityWindowInfoFlag() && mPendingActivityWindowInfo != null) { 9276 ActivityWindowInfo outInfo = null; 9277 if (windowSessionRelayoutInfo()) { 9278 outInfo = mRelayoutResult != null ? mRelayoutResult.activityWindowInfo : null; 9279 } else { 9280 try { 9281 outInfo = mRelayoutBundle.getParcelable( 9282 IWindowSession.KEY_RELAYOUT_BUNDLE_ACTIVITY_WINDOW_INFO, 9283 ActivityWindowInfo.class); 9284 mRelayoutBundle.remove( 9285 IWindowSession.KEY_RELAYOUT_BUNDLE_ACTIVITY_WINDOW_INFO); 9286 } catch (IllegalStateException e) { 9287 Log.e(TAG, "Failed to get ActivityWindowInfo from relayout Bundle", e); 9288 } 9289 } 9290 if (outInfo != null) { 9291 mPendingActivityWindowInfo.set(outInfo); 9292 } 9293 } 9294 final int maybeSyncSeqId = windowSessionRelayoutInfo() 9295 ? mRelayoutResult.syncSeqId 9296 : mRelayoutBundle.getInt(IWindowSession.KEY_RELAYOUT_BUNDLE_SEQID); 9297 if (maybeSyncSeqId > 0) { 9298 mSyncSeqId = maybeSyncSeqId; 9299 } 9300 9301 mWinFrameInScreen.set(mTmpFrames.frame); 9302 if (mTranslator != null) { 9303 mTranslator.translateRectInScreenToAppWindow(mTmpFrames.frame); 9304 mTranslator.translateRectInScreenToAppWindow(mTmpFrames.displayFrame); 9305 mTranslator.translateRectInScreenToAppWindow(mTmpFrames.attachedFrame); 9306 mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets); 9307 mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls.get()); 9308 } 9309 mInvCompatScale = 1f / mTmpFrames.compatScale; 9310 CompatibilityInfo.applyOverrideScaleIfNeeded(mPendingMergedConfiguration); 9311 mInsetsController.onStateChanged(mTempInsets); 9312 mInsetsController.onControlsChanged(mTempControls.get()); 9313 9314 mPendingAlwaysConsumeSystemBars = 9315 (relayoutResult & RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS) != 0; 9316 } 9317 9318 final int transformHint = SurfaceControl.rotationToBufferTransform( 9319 (mDisplay.getInstallOrientation() + mDisplay.getRotation()) % 4); 9320 final boolean transformHintChanged = transformHint != mPreviousTransformHint; 9321 mPreviousTransformHint = transformHint; 9322 mSurfaceControl.setTransformHint(transformHint); 9323 9324 WindowLayout.computeSurfaceSize(mWindowAttributes, winConfig.getMaxBounds(), requestedWidth, 9325 requestedHeight, mWinFrameInScreen, mPendingDragResizing, mSurfaceSize); 9326 9327 final boolean sizeChanged = !mLastSurfaceSize.equals(mSurfaceSize); 9328 final boolean surfaceControlChanged = 9329 (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED) == RELAYOUT_RES_SURFACE_CHANGED; 9330 if (mAttachInfo.mThreadedRenderer != null && 9331 (transformHintChanged || sizeChanged || surfaceControlChanged)) { 9332 if (mAttachInfo.mThreadedRenderer.pause()) { 9333 // Animations were running so we need to push a frame 9334 // to resume them 9335 mDirty.set(0, 0, mWidth, mHeight); 9336 } 9337 } 9338 9339 if (mSurfaceControl.isValid()) { 9340 if (mPendingDragResizing && !mSurfaceSize.equals( 9341 mWinFrameInScreen.width(), mWinFrameInScreen.height())) { 9342 // During drag-resize, a single fullscreen-sized surface is reused for optimization. 9343 // Crop to the content size instead of the surface size to avoid exposing garbage 9344 // content that is still on the surface from previous re-layouts (e.g. when 9345 // resizing to a larger size). 9346 mTransaction.setWindowCrop(mSurfaceControl, 9347 mWinFrameInScreen.width(), mWinFrameInScreen.height()); 9348 } else if (!HardwareRenderer.isDrawingEnabled()) { 9349 // When drawing is disabled the window layer won't have a valid buffer. 9350 // Set a window crop so input can get delivered to the window. 9351 mTransaction.setWindowCrop(mSurfaceControl, mSurfaceSize.x, mSurfaceSize.y).apply(); 9352 } 9353 } 9354 9355 if (mAttachInfo.mContentCaptureManager != null) { 9356 ContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager 9357 .getMainContentCaptureSession(); 9358 mainSession.notifyWindowBoundsChanged(mainSession.getId(), 9359 getConfiguration().windowConfiguration.getBounds()); 9360 } 9361 9362 if (mSurfaceControl.isValid()) { 9363 updateBlastSurfaceIfNeeded(); 9364 if (mAttachInfo.mThreadedRenderer != null) { 9365 mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue); 9366 } 9367 mHdrRenderState.forceUpdateHdrSdrRatio(); 9368 if (transformHintChanged) { 9369 dispatchTransformHintChanged(transformHint); 9370 } 9371 } else { 9372 if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.pause()) { 9373 mDirty.set(0, 0, mWidth, mHeight); 9374 } 9375 destroySurface(); 9376 } 9377 9378 if (restore) { 9379 params.restore(); 9380 } 9381 9382 setFrame(mTmpFrames.frame, true /* withinRelayout */); 9383 return relayoutResult; 9384 } 9385 updateOpacity(WindowManager.LayoutParams params, boolean dragResizing, boolean forceUpdate)9386 private void updateOpacity(WindowManager.LayoutParams params, boolean dragResizing, 9387 boolean forceUpdate) { 9388 boolean opaque = false; 9389 9390 if (!PixelFormat.formatHasAlpha(params.format) 9391 // Don't make surface with surfaceInsets opaque as they display a 9392 // translucent shadow. 9393 && params.surfaceInsets.left == 0 9394 && params.surfaceInsets.top == 0 9395 && params.surfaceInsets.right == 0 9396 && params.surfaceInsets.bottom == 0 9397 // Don't make surface opaque when resizing to reduce the amount of 9398 // artifacts shown in areas the app isn't drawing content to. 9399 && !dragResizing) { 9400 opaque = true; 9401 } 9402 9403 if (!forceUpdate && mIsSurfaceOpaque == opaque) { 9404 return; 9405 } 9406 9407 final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer; 9408 if (renderer != null && renderer.rendererOwnsSurfaceControlOpacity()) { 9409 opaque = renderer.setSurfaceControlOpaque(opaque); 9410 } else { 9411 mTransaction.setOpaque(mSurfaceControl, opaque).apply(); 9412 } 9413 9414 mIsSurfaceOpaque = opaque; 9415 } 9416 9417 /** 9418 * Set the mWinFrame of this window. 9419 * @param frame the new frame of this window. 9420 * @param withinRelayout {@code true} if this setting is within the relayout, or is the initial 9421 * setting. That will make sure in the relayout process, we always compare 9422 * the window frame with the last processed window frame. 9423 */ setFrame(Rect frame, boolean withinRelayout)9424 private void setFrame(Rect frame, boolean withinRelayout) { 9425 mWinFrame.set(frame); 9426 if (withinRelayout) { 9427 mLastLayoutFrame.set(frame); 9428 } 9429 9430 final WindowConfiguration winConfig = getCompatWindowConfiguration(); 9431 mPendingBackDropFrame.set(mPendingDragResizing && !winConfig.useWindowFrameForBackdrop() 9432 ? winConfig.getMaxBounds() 9433 : frame); 9434 // Surface position is now inherited from parent, and BackdropFrameRenderer uses backdrop 9435 // frame to position content. Thus, we just keep the size of backdrop frame, and remove the 9436 // offset to avoid double offset from display origin. 9437 mPendingBackDropFrame.offsetTo(0, 0); 9438 9439 mInsetsController.onFrameChanged(mOverrideInsetsFrame != null ? 9440 mOverrideInsetsFrame : frame); 9441 } 9442 9443 /** 9444 * In the normal course of operations we compute insets relative to 9445 * the frame returned from relayout window. In the case of 9446 * SurfaceControlViewHost, this frame is in local coordinates 9447 * instead of global coordinates. We support this override 9448 * frame so we can allow SurfaceControlViewHost to set a frame 9449 * to be used to calculate insets, without disturbing the main 9450 * mFrame. 9451 */ setOverrideInsetsFrame(Rect frame)9452 void setOverrideInsetsFrame(Rect frame) { 9453 mOverrideInsetsFrame = new Rect(frame); 9454 mInsetsController.onFrameChanged(mOverrideInsetsFrame); 9455 } 9456 9457 /** 9458 * Gets the current display size in which the window is being laid out, accounting for screen 9459 * decorations around it. 9460 */ getDisplayFrame(Rect outFrame)9461 void getDisplayFrame(Rect outFrame) { 9462 outFrame.set(mTmpFrames.displayFrame); 9463 // Apply sandboxing here (in getter) due to possible layout updates on the client after 9464 // mTmpFrames.displayFrame is received from the server. 9465 applyViewBoundsSandboxingIfNeeded(outFrame); 9466 } 9467 9468 /** 9469 * Gets the current display size in which the window is being laid out, accounting for screen 9470 * decorations around it. 9471 */ getWindowVisibleDisplayFrame(Rect outFrame)9472 void getWindowVisibleDisplayFrame(Rect outFrame) { 9473 outFrame.set(mTmpFrames.displayFrame); 9474 // XXX This is really broken, and probably all needs to be done 9475 // in the window manager, and we need to know more about whether 9476 // we want the area behind or in front of the IME. 9477 final Rect insets = mAttachInfo.mVisibleInsets; 9478 outFrame.left += insets.left; 9479 outFrame.top += insets.top; 9480 outFrame.right -= insets.right; 9481 outFrame.bottom -= insets.bottom; 9482 // Apply sandboxing here (in getter) due to possible layout updates on the client after 9483 // mTmpFrames.displayFrame is received from the server. 9484 applyViewBoundsSandboxingIfNeeded(outFrame); 9485 } 9486 9487 /** 9488 * Offset outRect to make it sandboxed within Window's bounds. 9489 * 9490 * <p>This is used by {@link android.view.View#getBoundsOnScreen}, 9491 * {@link android.view.ViewRootImpl#getDisplayFrame} and 9492 * {@link android.view.ViewRootImpl#getWindowVisibleDisplayFrame}, which are invoked by 9493 * {@link android.view.View#getWindowDisplayFrame} and 9494 * {@link android.view.View#getWindowVisibleDisplayFrame}, as well as 9495 * {@link android.view.ViewDebug#captureLayers} for debugging. 9496 */ applyViewBoundsSandboxingIfNeeded(final Rect inOutRect)9497 void applyViewBoundsSandboxingIfNeeded(final Rect inOutRect) { 9498 if (mViewBoundsSandboxingEnabled) { 9499 final Rect bounds = getConfiguration().windowConfiguration.getBounds(); 9500 inOutRect.offset(-bounds.left, -bounds.top); 9501 } 9502 } 9503 9504 /** 9505 * Offset outLocation to make it sandboxed within Window's bounds. 9506 * 9507 * <p>This is used by {@link android.view.View#getLocationOnScreen(int[])} 9508 */ applyViewLocationSandboxingIfNeeded(@ize2) int[] outLocation)9509 public void applyViewLocationSandboxingIfNeeded(@Size(2) int[] outLocation) { 9510 if (mViewBoundsSandboxingEnabled) { 9511 final Rect bounds = getConfiguration().windowConfiguration.getBounds(); 9512 outLocation[0] -= bounds.left; 9513 outLocation[1] -= bounds.top; 9514 } 9515 } 9516 getViewBoundsSandboxingEnabled()9517 private boolean getViewBoundsSandboxingEnabled() { 9518 // System dialogs (e.g. ANR) can be created within System process, so handleBindApplication 9519 // may be never called. This results into all app compat changes being enabled 9520 // (see b/268007823) because AppCompatCallbacks.install() is never called with non-empty 9521 // array. 9522 // With ActivityThread.isSystem we verify that it is not the system process, 9523 // then this CompatChange can take effect. 9524 if (ActivityThread.isSystem() 9525 || !CompatChanges.isChangeEnabled(OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS)) { 9526 // It is a system process or OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS change-id is disabled. 9527 return false; 9528 } 9529 9530 // OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS is enabled by the device manufacturer. 9531 try { 9532 final List<PackageManager.Property> properties = mContext.getPackageManager() 9533 .queryApplicationProperty(PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS); 9534 9535 final boolean isOptedOut = !properties.isEmpty() && !properties.get(0).getBoolean(); 9536 if (isOptedOut) { 9537 // PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS is disabled by the app devs. 9538 return false; 9539 } 9540 } catch (RuntimeException e) { 9541 // remote exception. 9542 } 9543 9544 return true; 9545 } 9546 9547 /** 9548 * {@inheritDoc} 9549 */ 9550 @Override playSoundEffect(@oundEffectConstants.SoundEffect int effectId)9551 public void playSoundEffect(@SoundEffectConstants.SoundEffect int effectId) { 9552 if ((mDisplay.getFlags() & Display.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) { 9553 return; 9554 } 9555 9556 checkThread(); 9557 9558 try { 9559 final AudioManager audioManager = getAudioManager(); 9560 9561 if (mFastScrollSoundEffectsEnabled 9562 && SoundEffectConstants.isNavigationRepeat(effectId)) { 9563 audioManager.playSoundEffect( 9564 SoundEffectConstants.nextNavigationRepeatSoundEffectId()); 9565 return; 9566 } 9567 9568 switch (effectId) { 9569 case SoundEffectConstants.CLICK: 9570 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK); 9571 return; 9572 case SoundEffectConstants.NAVIGATION_DOWN: 9573 case SoundEffectConstants.NAVIGATION_REPEAT_DOWN: 9574 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN); 9575 return; 9576 case SoundEffectConstants.NAVIGATION_LEFT: 9577 case SoundEffectConstants.NAVIGATION_REPEAT_LEFT: 9578 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT); 9579 return; 9580 case SoundEffectConstants.NAVIGATION_RIGHT: 9581 case SoundEffectConstants.NAVIGATION_REPEAT_RIGHT: 9582 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT); 9583 return; 9584 case SoundEffectConstants.NAVIGATION_UP: 9585 case SoundEffectConstants.NAVIGATION_REPEAT_UP: 9586 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP); 9587 return; 9588 default: 9589 throw new IllegalArgumentException("unknown effect id " + effectId + 9590 " not defined in " + SoundEffectConstants.class.getCanonicalName()); 9591 } 9592 } catch (IllegalStateException e) { 9593 // Exception thrown by getAudioManager() when mView is null 9594 Log.e(mTag, "FATAL EXCEPTION when attempting to play sound effect: " + e); 9595 e.printStackTrace(); 9596 } 9597 } 9598 9599 /** 9600 * {@inheritDoc} 9601 */ 9602 @Override performHapticFeedback(int effectId, boolean always, boolean fromIme)9603 public boolean performHapticFeedback(int effectId, boolean always, boolean fromIme) { 9604 if ((mDisplay.getFlags() & Display.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) { 9605 return false; 9606 } 9607 9608 try { 9609 if (USE_ASYNC_PERFORM_HAPTIC_FEEDBACK) { 9610 mWindowSession.performHapticFeedbackAsync(effectId, always, fromIme); 9611 return true; 9612 } else { 9613 // Original blocking binder call path. 9614 return mWindowSession.performHapticFeedback(effectId, always, fromIme); 9615 } 9616 } catch (RemoteException e) { 9617 return false; 9618 } 9619 } 9620 9621 /** 9622 * {@inheritDoc} 9623 */ 9624 @Override focusSearch(View focused, int direction)9625 public View focusSearch(View focused, int direction) { 9626 checkThread(); 9627 if (!(mView instanceof ViewGroup)) { 9628 return null; 9629 } 9630 return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction); 9631 } 9632 9633 /** 9634 * {@inheritDoc} 9635 */ 9636 @Override keyboardNavigationClusterSearch(View currentCluster, @FocusDirection int direction)9637 public View keyboardNavigationClusterSearch(View currentCluster, 9638 @FocusDirection int direction) { 9639 checkThread(); 9640 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( 9641 mView, currentCluster, direction); 9642 } 9643 debug()9644 public void debug() { 9645 mView.debug(); 9646 } 9647 9648 /** 9649 * Export the state of {@link ViewRootImpl} and other relevant classes into a protocol buffer 9650 * output stream. 9651 * 9652 * @param proto Stream to write the state to 9653 * @param fieldId FieldId of ViewRootImpl as defined in the parent message 9654 */ 9655 @GuardedBy("this") dumpDebug(ProtoOutputStream proto, long fieldId)9656 public void dumpDebug(ProtoOutputStream proto, long fieldId) { 9657 final long token = proto.start(fieldId); 9658 proto.write(VIEW, Objects.toString(mView)); 9659 proto.write(DISPLAY_ID, mDisplay.getDisplayId()); 9660 proto.write(APP_VISIBLE, mAppVisible); 9661 proto.write(HEIGHT, mHeight); 9662 proto.write(WIDTH, mWidth); 9663 proto.write(IS_ANIMATING, mIsAnimating); 9664 mVisRect.dumpDebug(proto, VISIBLE_RECT); 9665 proto.write(IS_DRAWING, mIsDrawing); 9666 proto.write(ADDED, mAdded); 9667 mWinFrame.dumpDebug(proto, WIN_FRAME); 9668 proto.write(LAST_WINDOW_INSETS, Objects.toString(mLastWindowInsets)); 9669 proto.write(SOFT_INPUT_MODE, InputMethodDebug.softInputModeToString(mSoftInputMode)); 9670 proto.write(SCROLL_Y, mScrollY); 9671 proto.write(CUR_SCROLL_Y, mCurScrollY); 9672 proto.write(REMOVED, mRemoved); 9673 mWindowAttributes.dumpDebug(proto, WINDOW_ATTRIBUTES); 9674 proto.end(token); 9675 mInsetsController.dumpDebug(proto, INSETS_CONTROLLER); 9676 mImeFocusController.dumpDebug(proto, IME_FOCUS_CONTROLLER); 9677 } 9678 9679 /** 9680 * Dump information about this ViewRootImpl 9681 * @param prefix the prefix that will be prepended to each line of the produced output 9682 * @param writer the writer that will receive the resulting text 9683 */ dump(String prefix, PrintWriter writer)9684 public void dump(String prefix, PrintWriter writer) { 9685 String innerPrefix = prefix + " "; 9686 writer.println(prefix + "ViewRoot:"); 9687 writer.println(innerPrefix + "mAdded=" + mAdded); 9688 writer.println(innerPrefix + "mRemoved=" + mRemoved); 9689 writer.println(innerPrefix + "mStopped=" + mStopped); 9690 writer.println(innerPrefix + "mPausedForTransition=" + mPausedForTransition); 9691 writer.println(innerPrefix + "mConsumeBatchedInputScheduled=" 9692 + mConsumeBatchedInputScheduled); 9693 writer.println(innerPrefix + "mConsumeBatchedInputImmediatelyScheduled=" 9694 + mConsumeBatchedInputImmediatelyScheduled); 9695 writer.println(innerPrefix + "mPendingInputEventCount=" + mPendingInputEventCount); 9696 writer.println(innerPrefix + "mProcessInputEventsScheduled=" 9697 + mProcessInputEventsScheduled); 9698 writer.println(innerPrefix + "mTraversalScheduled=" + mTraversalScheduled); 9699 if (mTraversalScheduled) { 9700 writer.println(innerPrefix + " (barrier=" + mTraversalBarrier + ")"); 9701 } 9702 writer.println(innerPrefix + "mReportNextDraw=" + mReportNextDraw); 9703 if (mReportNextDraw) { 9704 writer.println(innerPrefix + " (reason=" + mLastReportNextDrawReason + ")"); 9705 } 9706 if (mLastPerformTraversalsSkipDrawReason != null) { 9707 writer.println(innerPrefix + "mLastPerformTraversalsFailedReason=" 9708 + mLastPerformTraversalsSkipDrawReason); 9709 } 9710 if (mLastPerformDrawSkippedReason != null) { 9711 writer.println(innerPrefix + "mLastPerformDrawFailedReason=" 9712 + mLastPerformDrawSkippedReason); 9713 } 9714 if (mWmsRequestSyncGroupState != WMS_SYNC_NONE) { 9715 writer.println(innerPrefix + "mWmsRequestSyncGroupState=" + mWmsRequestSyncGroupState); 9716 } 9717 writer.println(innerPrefix + "mLastReportedMergedConfiguration=" 9718 + mLastReportedMergedConfiguration); 9719 writer.println(innerPrefix + "mLastConfigurationFromResources=" 9720 + mLastConfigurationFromResources); 9721 if (mLastReportedActivityWindowInfo != null) { 9722 writer.println(innerPrefix + "mLastReportedActivityWindowInfo=" 9723 + mLastReportedActivityWindowInfo); 9724 } 9725 writer.println(innerPrefix + "mIsAmbientMode=" + mIsAmbientMode); 9726 writer.println(innerPrefix + "mUnbufferedInputSource=" 9727 + Integer.toHexString(mUnbufferedInputSource)); 9728 if (mAttachInfo != null) { 9729 writer.print(innerPrefix + "mAttachInfo= "); 9730 mAttachInfo.dump(innerPrefix, writer); 9731 } else { 9732 writer.println(innerPrefix + "mAttachInfo=<null>"); 9733 } 9734 9735 mFirstInputStage.dump(innerPrefix, writer); 9736 9737 if (mInputEventReceiver != null) { 9738 mInputEventReceiver.dump(innerPrefix, writer); 9739 } 9740 9741 mChoreographer.dump(prefix, writer); 9742 9743 mInsetsController.dump(prefix, writer); 9744 9745 mOnBackInvokedDispatcher.dump(prefix, writer); 9746 9747 mImeBackAnimationController.dump(prefix, writer); 9748 9749 writer.println(prefix + "View Hierarchy:"); 9750 dumpViewHierarchy(innerPrefix, writer, mView); 9751 } 9752 dumpViewHierarchy(String prefix, PrintWriter writer, View view)9753 private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) { 9754 writer.print(prefix); 9755 if (view == null) { 9756 writer.println("null"); 9757 return; 9758 } 9759 writer.println(view.toString()); 9760 if (!(view instanceof ViewGroup)) { 9761 return; 9762 } 9763 ViewGroup grp = (ViewGroup)view; 9764 final int N = grp.getChildCount(); 9765 if (N <= 0) { 9766 return; 9767 } 9768 prefix = prefix + " "; 9769 for (int i=0; i<N; i++) { 9770 dumpViewHierarchy(prefix, writer, grp.getChildAt(i)); 9771 } 9772 } 9773 9774 static final class GfxInfo { 9775 public int viewCount; 9776 public long renderNodeMemoryUsage; 9777 public long renderNodeMemoryAllocated; 9778 add(GfxInfo other)9779 void add(GfxInfo other) { 9780 viewCount += other.viewCount; 9781 renderNodeMemoryUsage += other.renderNodeMemoryUsage; 9782 renderNodeMemoryAllocated += other.renderNodeMemoryAllocated; 9783 } 9784 } 9785 getGfxInfo()9786 GfxInfo getGfxInfo() { 9787 GfxInfo info = new GfxInfo(); 9788 if (mView != null) { 9789 appendGfxInfo(mView, info); 9790 } 9791 return info; 9792 } 9793 computeRenderNodeUsage(RenderNode node, GfxInfo info)9794 private static void computeRenderNodeUsage(RenderNode node, GfxInfo info) { 9795 if (node == null) return; 9796 info.renderNodeMemoryUsage += node.computeApproximateMemoryUsage(); 9797 info.renderNodeMemoryAllocated += node.computeApproximateMemoryAllocated(); 9798 } 9799 appendGfxInfo(View view, GfxInfo info)9800 private static void appendGfxInfo(View view, GfxInfo info) { 9801 info.viewCount++; 9802 computeRenderNodeUsage(view.mRenderNode, info); 9803 computeRenderNodeUsage(view.mBackgroundRenderNode, info); 9804 if (view instanceof ViewGroup) { 9805 ViewGroup group = (ViewGroup) view; 9806 9807 int count = group.getChildCount(); 9808 for (int i = 0; i < count; i++) { 9809 appendGfxInfo(group.getChildAt(i), info); 9810 } 9811 } 9812 } 9813 9814 /** 9815 * @param immediate True, do now if not in traversal. False, put on queue and do later. 9816 * @return True, request has been queued. False, request has been completed. 9817 */ die(boolean immediate)9818 boolean die(boolean immediate) { 9819 // Make sure we do execute immediately if we are in the middle of a traversal or the damage 9820 // done by dispatchDetachedFromWindow will cause havoc on return. 9821 if (immediate && !mIsInTraversal) { 9822 doDie(); 9823 return false; 9824 } 9825 9826 if (!mIsDrawing) { 9827 destroyHardwareRenderer(); 9828 } else { 9829 Log.e(mTag, "Attempting to destroy the window while drawing!\n" + 9830 " window=" + this + ", title=" + mWindowAttributes.getTitle()); 9831 } 9832 mHandler.sendEmptyMessage(MSG_DIE); 9833 return true; 9834 } 9835 doDie()9836 void doDie() { 9837 checkThread(); 9838 if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface); 9839 synchronized (this) { 9840 if (mRemoved) { 9841 return; 9842 } 9843 mRemoved = true; 9844 mOnBackInvokedDispatcher.detachFromWindow(); 9845 removeVrrMessages(); 9846 9847 if (mAdded) { 9848 dispatchDetachedFromWindow(); 9849 } 9850 9851 if (mAdded && !mFirst) { 9852 destroyHardwareRenderer(); 9853 9854 if (mView != null) { 9855 int viewVisibility = mView.getVisibility(); 9856 boolean viewVisibilityChanged = mViewVisibility != viewVisibility; 9857 if (mWindowAttributesChanged || viewVisibilityChanged) { 9858 // If layout params have been changed, first give them 9859 // to the window manager to make sure it has the correct 9860 // animation info. 9861 try { 9862 if ((relayoutWindow(mWindowAttributes, viewVisibility, false) 9863 & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { 9864 mWindowSession.finishDrawing( 9865 mWindow, null /* postDrawTransaction */, Integer.MAX_VALUE); 9866 } 9867 } catch (RemoteException e) { 9868 } 9869 } 9870 9871 destroySurface(); 9872 } 9873 } 9874 9875 // If our window is removed, we might not get notified about losing control. 9876 // Invoking this can release the leashes as soon as possible instead of relying on GC. 9877 mInsetsController.onControlsChanged(null); 9878 9879 mAdded = false; 9880 AnimationHandler.removeRequestor(this); 9881 } 9882 handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions, 9883 mPendingTransaction, "shutting down VRI"); 9884 WindowManagerGlobal.getInstance().doRemoveView(this); 9885 } 9886 requestUpdateConfiguration(Configuration config)9887 public void requestUpdateConfiguration(Configuration config) { 9888 Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config); 9889 mHandler.sendMessage(msg); 9890 } 9891 loadSystemProperties()9892 public void loadSystemProperties() { 9893 mHandler.post(new Runnable() { 9894 @Override 9895 public void run() { 9896 // Profiling 9897 mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false); 9898 profileRendering(mAttachInfo.mHasWindowFocus); 9899 9900 // Hardware rendering 9901 if (mAttachInfo.mThreadedRenderer != null) { 9902 if (mAttachInfo.mThreadedRenderer.loadSystemProperties()) { 9903 invalidate(); 9904 } 9905 } 9906 9907 // Layout debugging 9908 boolean layout = DisplayProperties.debug_layout().orElse(false); 9909 if (layout != mAttachInfo.mDebugLayout) { 9910 mAttachInfo.mDebugLayout = layout; 9911 if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) { 9912 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200); 9913 } 9914 } 9915 } 9916 }); 9917 } 9918 destroyHardwareRenderer()9919 private void destroyHardwareRenderer() { 9920 ThreadedRenderer hardwareRenderer = mAttachInfo.mThreadedRenderer; 9921 9922 mHdrRenderState.stopListening(); 9923 9924 if (hardwareRenderer != null) { 9925 if (mHardwareRendererObserver != null) { 9926 hardwareRenderer.removeObserver(mHardwareRendererObserver); 9927 } 9928 if (mView != null) { 9929 hardwareRenderer.destroyHardwareResources(mView); 9930 } 9931 hardwareRenderer.destroy(); 9932 hardwareRenderer.setRequested(false); 9933 9934 mAttachInfo.mThreadedRenderer = null; 9935 mAttachInfo.mHardwareAccelerated = false; 9936 } 9937 } 9938 9939 @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)9940 private void dispatchResized(ClientWindowFrames frames, boolean reportDraw, 9941 MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout, 9942 boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing, 9943 @Nullable ActivityWindowInfo activityWindowInfo) { 9944 Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED); 9945 SomeArgs args = SomeArgs.obtain(); 9946 args.arg1 = frames; 9947 args.arg2 = mergedConfiguration; 9948 args.arg3 = insetsState; 9949 args.arg4 = activityWindowInfo; 9950 args.argi1 = forceLayout ? 1 : 0; 9951 args.argi2 = alwaysConsumeSystemBars ? 1 : 0; 9952 args.argi3 = displayId; 9953 args.argi4 = syncSeqId; 9954 args.argi5 = dragResizing ? 1 : 0; 9955 9956 msg.obj = args; 9957 mHandler.sendMessage(msg); 9958 } 9959 dispatchInsetsControlChanged(@onNull InsetsState insetsState, @NonNull InsetsSourceControl.Array activeControls)9960 private void dispatchInsetsControlChanged(@NonNull InsetsState insetsState, 9961 @NonNull InsetsSourceControl.Array activeControls) { 9962 final SomeArgs args = SomeArgs.obtain(); 9963 args.arg1 = insetsState; 9964 args.arg2 = activeControls; 9965 mHandler.obtainMessage(MSG_INSETS_CONTROL_CHANGED, args).sendToTarget(); 9966 } 9967 showInsets(@nsetsType int types, boolean fromIme, @Nullable ImeTracker.Token statsToken)9968 private void showInsets(@InsetsType int types, boolean fromIme, 9969 @Nullable ImeTracker.Token statsToken) { 9970 mHandler.obtainMessage(MSG_SHOW_INSETS, types, fromIme ? 1 : 0, statsToken).sendToTarget(); 9971 } 9972 hideInsets(@nsetsType int types, boolean fromIme, @Nullable ImeTracker.Token statsToken)9973 private void hideInsets(@InsetsType int types, boolean fromIme, 9974 @Nullable ImeTracker.Token statsToken) { 9975 mHandler.obtainMessage(MSG_HIDE_INSETS, types, fromIme ? 1 : 0, statsToken).sendToTarget(); 9976 } 9977 dispatchMoved(int newX, int newY)9978 public void dispatchMoved(int newX, int newY) { 9979 if (DEBUG_LAYOUT) Log.v(mTag, "Window moved " + this + ": newX=" + newX + " newY=" + newY); 9980 if (mTranslator != null) { 9981 PointF point = new PointF(newX, newY); 9982 mTranslator.translatePointInScreenToAppWindow(point); 9983 newX = (int) (point.x + 0.5); 9984 newY = (int) (point.y + 0.5); 9985 } 9986 Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY); 9987 mHandler.sendMessage(msg); 9988 } 9989 9990 /** 9991 * Represents a pending input event that is waiting in a queue. 9992 * 9993 * Input events are processed in serial order by the timestamp specified by 9994 * {@link InputEvent#getEventTimeNanos()}. In general, the input dispatcher delivers 9995 * one input event to the application at a time and waits for the application 9996 * to finish handling it before delivering the next one. 9997 * 9998 * However, because the application or IME can synthesize and inject multiple 9999 * key events at a time without going through the input dispatcher, we end up 10000 * needing a queue on the application's side. 10001 */ 10002 private static final class QueuedInputEvent { 10003 public static final int FLAG_DELIVER_POST_IME = 1 << 0; 10004 public static final int FLAG_DEFERRED = 1 << 1; 10005 public static final int FLAG_FINISHED = 1 << 2; 10006 public static final int FLAG_FINISHED_HANDLED = 1 << 3; 10007 public static final int FLAG_RESYNTHESIZED = 1 << 4; 10008 public static final int FLAG_UNHANDLED = 1 << 5; 10009 public static final int FLAG_MODIFIED_FOR_COMPATIBILITY = 1 << 6; 10010 10011 public QueuedInputEvent mNext; 10012 10013 public InputEvent mEvent; 10014 public InputEventReceiver mReceiver; 10015 public int mFlags; 10016 shouldSkipIme()10017 public boolean shouldSkipIme() { 10018 if ((mFlags & FLAG_DELIVER_POST_IME) != 0) { 10019 return true; 10020 } 10021 return mEvent instanceof MotionEvent 10022 && (mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)); 10023 } 10024 shouldSendToSynthesizer()10025 public boolean shouldSendToSynthesizer() { 10026 if ((mFlags & FLAG_UNHANDLED) != 0) { 10027 return true; 10028 } 10029 10030 return false; 10031 } 10032 10033 @Override toString()10034 public String toString() { 10035 StringBuilder sb = new StringBuilder("QueuedInputEvent{flags="); 10036 boolean hasPrevious = false; 10037 hasPrevious = flagToString("DELIVER_POST_IME", FLAG_DELIVER_POST_IME, hasPrevious, sb); 10038 hasPrevious = flagToString("DEFERRED", FLAG_DEFERRED, hasPrevious, sb); 10039 hasPrevious = flagToString("FINISHED", FLAG_FINISHED, hasPrevious, sb); 10040 hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb); 10041 hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb); 10042 hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb); 10043 if (!hasPrevious) { 10044 sb.append("0"); 10045 } 10046 sb.append(", hasNextQueuedEvent=" + (mEvent != null ? "true" : "false")); 10047 sb.append(", hasInputEventReceiver=" + (mReceiver != null ? "true" : "false")); 10048 sb.append(", mEvent=" + mEvent + "}"); 10049 return sb.toString(); 10050 } 10051 flagToString(String name, int flag, boolean hasPrevious, StringBuilder sb)10052 private boolean flagToString(String name, int flag, 10053 boolean hasPrevious, StringBuilder sb) { 10054 if ((mFlags & flag) != 0) { 10055 if (hasPrevious) { 10056 sb.append("|"); 10057 } 10058 sb.append(name); 10059 return true; 10060 } 10061 return hasPrevious; 10062 } 10063 } 10064 obtainQueuedInputEvent(InputEvent event, InputEventReceiver receiver, int flags)10065 private QueuedInputEvent obtainQueuedInputEvent(InputEvent event, 10066 InputEventReceiver receiver, int flags) { 10067 QueuedInputEvent q = mQueuedInputEventPool; 10068 if (q != null) { 10069 mQueuedInputEventPoolSize -= 1; 10070 mQueuedInputEventPool = q.mNext; 10071 q.mNext = null; 10072 } else { 10073 q = new QueuedInputEvent(); 10074 } 10075 10076 q.mEvent = event; 10077 q.mReceiver = receiver; 10078 q.mFlags = flags; 10079 return q; 10080 } 10081 recycleQueuedInputEvent(QueuedInputEvent q)10082 private void recycleQueuedInputEvent(QueuedInputEvent q) { 10083 q.mEvent = null; 10084 q.mReceiver = null; 10085 10086 if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) { 10087 mQueuedInputEventPoolSize += 1; 10088 q.mNext = mQueuedInputEventPool; 10089 mQueuedInputEventPool = q; 10090 } 10091 } 10092 10093 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) enqueueInputEvent(InputEvent event)10094 public void enqueueInputEvent(InputEvent event) { 10095 enqueueInputEvent(event, null, 0, false); 10096 } 10097 10098 @UnsupportedAppUsage enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately)10099 void enqueueInputEvent(InputEvent event, 10100 InputEventReceiver receiver, int flags, boolean processImmediately) { 10101 QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags); 10102 10103 if (event instanceof MotionEvent) { 10104 MotionEvent me = (MotionEvent) event; 10105 if (me.getAction() == MotionEvent.ACTION_CANCEL) { 10106 EventLog.writeEvent(EventLogTags.VIEW_ENQUEUE_INPUT_EVENT, "Motion - Cancel", 10107 getTitle().toString()); 10108 } 10109 } else if (event instanceof KeyEvent) { 10110 KeyEvent ke = (KeyEvent) event; 10111 if (ke.isCanceled()) { 10112 EventLog.writeEvent(EventLogTags.VIEW_ENQUEUE_INPUT_EVENT, "Key - Cancel", 10113 getTitle().toString()); 10114 } 10115 } 10116 // Always enqueue the input event in order, regardless of its time stamp. 10117 // We do this because the application or the IME may inject key events 10118 // in response to touch events and we want to ensure that the injected keys 10119 // are processed in the order they were received and we cannot trust that 10120 // the time stamp of injected events are monotonic. 10121 QueuedInputEvent last = mPendingInputEventTail; 10122 if (last == null) { 10123 mPendingInputEventHead = q; 10124 mPendingInputEventTail = q; 10125 } else { 10126 last.mNext = q; 10127 mPendingInputEventTail = q; 10128 } 10129 mPendingInputEventCount += 1; 10130 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName, 10131 mPendingInputEventCount); 10132 10133 if (processImmediately) { 10134 doProcessInputEvents(); 10135 } else { 10136 scheduleProcessInputEvents(); 10137 } 10138 } 10139 scheduleProcessInputEvents()10140 private void scheduleProcessInputEvents() { 10141 if (!mProcessInputEventsScheduled) { 10142 mProcessInputEventsScheduled = true; 10143 Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS); 10144 msg.setAsynchronous(true); 10145 mHandler.sendMessage(msg); 10146 } 10147 } 10148 doProcessInputEvents()10149 void doProcessInputEvents() { 10150 // Deliver all pending input events in the queue. 10151 while (mPendingInputEventHead != null) { 10152 QueuedInputEvent q = mPendingInputEventHead; 10153 mPendingInputEventHead = q.mNext; 10154 if (mPendingInputEventHead == null) { 10155 mPendingInputEventTail = null; 10156 } 10157 q.mNext = null; 10158 10159 mPendingInputEventCount -= 1; 10160 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName, 10161 mPendingInputEventCount); 10162 10163 mViewFrameInfo.setInputEvent(mInputEventAssigner.processEvent(q.mEvent)); 10164 10165 deliverInputEvent(q); 10166 } 10167 10168 // We are done processing all input events that we can process right now 10169 // so we can clear the pending flag immediately. 10170 if (mProcessInputEventsScheduled) { 10171 mProcessInputEventsScheduled = false; 10172 mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS); 10173 } 10174 } 10175 deliverInputEvent(QueuedInputEvent q)10176 private void deliverInputEvent(QueuedInputEvent q) { 10177 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent", 10178 q.mEvent.getId()); 10179 10180 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 10181 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent src=0x" 10182 + Integer.toHexString(q.mEvent.getSource()) + " eventTimeNano=" 10183 + q.mEvent.getEventTimeNanos() + " id=0x" 10184 + Integer.toHexString(q.mEvent.getId())); 10185 } 10186 try { 10187 if (mInputEventConsistencyVerifier != null) { 10188 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "verifyEventConsistency"); 10189 try { 10190 mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0); 10191 } finally { 10192 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 10193 } 10194 } 10195 10196 InputStage stage; 10197 if (q.shouldSendToSynthesizer()) { 10198 stage = mSyntheticInputStage; 10199 } else { 10200 stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage; 10201 } 10202 10203 if (q.mEvent instanceof KeyEvent) { 10204 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "preDispatchToUnhandledKeyManager"); 10205 try { 10206 mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent); 10207 } finally { 10208 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 10209 } 10210 } 10211 10212 if (stage != null) { 10213 handleWindowFocusChanged(); 10214 stage.deliver(q); 10215 } else { 10216 finishInputEvent(q); 10217 } 10218 } finally { 10219 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 10220 } 10221 } 10222 finishInputEvent(QueuedInputEvent q)10223 private void finishInputEvent(QueuedInputEvent q) { 10224 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent", 10225 q.mEvent.getId()); 10226 10227 if (q.mReceiver != null) { 10228 boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0; 10229 boolean modified = (q.mFlags & QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY) != 0; 10230 if (modified) { 10231 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventBeforeFinish"); 10232 InputEvent processedEvent; 10233 try { 10234 processedEvent = 10235 mInputCompatProcessor.processInputEventBeforeFinish(q.mEvent); 10236 } finally { 10237 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 10238 } 10239 if (processedEvent != null) { 10240 q.mReceiver.finishInputEvent(processedEvent, handled); 10241 } 10242 } else { 10243 q.mReceiver.finishInputEvent(q.mEvent, handled); 10244 } 10245 if (q.mEvent instanceof KeyEvent) { 10246 logHandledSystemKey((KeyEvent) q.mEvent, handled); 10247 } 10248 } else { 10249 q.mEvent.recycleIfNeededAfterDispatch(); 10250 } 10251 10252 recycleQueuedInputEvent(q); 10253 } 10254 logHandledSystemKey(KeyEvent event, boolean handled)10255 private void logHandledSystemKey(KeyEvent event, boolean handled) { 10256 final int keyCode = event.getKeyCode(); 10257 if (keyCode != KeyEvent.KEYCODE_STEM_PRIMARY) { 10258 return; 10259 } 10260 if (event.isDown() && event.getRepeatCount() == 0 && handled) { 10261 // Initial DOWN event is handled. Log the stem primary key press. 10262 Counter.logIncrementWithUid( 10263 "input.value_app_handled_stem_primary_key_gestures_count", 10264 Process.myUid()); 10265 } 10266 } 10267 isTerminalInputEvent(InputEvent event)10268 static boolean isTerminalInputEvent(InputEvent event) { 10269 if (event instanceof KeyEvent) { 10270 final KeyEvent keyEvent = (KeyEvent)event; 10271 return keyEvent.getAction() == KeyEvent.ACTION_UP; 10272 } else { 10273 final MotionEvent motionEvent = (MotionEvent)event; 10274 final int action = motionEvent.getAction(); 10275 return action == MotionEvent.ACTION_UP 10276 || action == MotionEvent.ACTION_CANCEL 10277 || action == MotionEvent.ACTION_HOVER_EXIT; 10278 } 10279 } 10280 scheduleConsumeBatchedInput()10281 void scheduleConsumeBatchedInput() { 10282 // If anything is currently scheduled to consume batched input then there's no point in 10283 // scheduling it again. 10284 if (!mConsumeBatchedInputScheduled && !mConsumeBatchedInputImmediatelyScheduled) { 10285 mConsumeBatchedInputScheduled = true; 10286 mChoreographer.postCallback(Choreographer.CALLBACK_INPUT, 10287 mConsumedBatchedInputRunnable, null); 10288 if (mAttachInfo.mThreadedRenderer != null) { 10289 mAttachInfo.mThreadedRenderer.notifyCallbackPending(); 10290 } 10291 } 10292 } 10293 unscheduleConsumeBatchedInput()10294 void unscheduleConsumeBatchedInput() { 10295 if (mConsumeBatchedInputScheduled) { 10296 mConsumeBatchedInputScheduled = false; 10297 mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT, 10298 mConsumedBatchedInputRunnable, null); 10299 } 10300 } 10301 scheduleConsumeBatchedInputImmediately()10302 void scheduleConsumeBatchedInputImmediately() { 10303 if (!mConsumeBatchedInputImmediatelyScheduled) { 10304 unscheduleConsumeBatchedInput(); 10305 mConsumeBatchedInputImmediatelyScheduled = true; 10306 mHandler.post(mConsumeBatchedInputImmediatelyRunnable); 10307 } 10308 } 10309 doConsumeBatchedInput(long frameTimeNanos)10310 boolean doConsumeBatchedInput(long frameTimeNanos) { 10311 final boolean consumedBatches; 10312 if (mInputEventReceiver != null) { 10313 consumedBatches = mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos); 10314 } else { 10315 consumedBatches = false; 10316 } 10317 doProcessInputEvents(); 10318 return consumedBatches; 10319 } 10320 10321 final class TraversalRunnable implements Runnable { 10322 @Override run()10323 public void run() { 10324 doTraversal(); 10325 } 10326 } 10327 final TraversalRunnable mTraversalRunnable = new TraversalRunnable(); 10328 10329 final class WindowInputEventReceiver extends InputEventReceiver { WindowInputEventReceiver(InputChannel inputChannel, Looper looper)10330 public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) { 10331 super(inputChannel, looper); 10332 } 10333 10334 @Override onInputEvent(InputEvent event)10335 public void onInputEvent(InputEvent event) { 10336 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventForCompatibility"); 10337 List<InputEvent> processedEvents; 10338 try { 10339 processedEvents = 10340 mInputCompatProcessor.processInputEventForCompatibility(event); 10341 } finally { 10342 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 10343 } 10344 if (processedEvents != null) { 10345 if (processedEvents.isEmpty()) { 10346 // InputEvent consumed by mInputCompatProcessor 10347 finishInputEvent(event, true); 10348 } else { 10349 for (int i = 0; i < processedEvents.size(); i++) { 10350 enqueueInputEvent( 10351 processedEvents.get(i), this, 10352 QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY, true); 10353 } 10354 } 10355 } else { 10356 enqueueInputEvent(event, this, 0, true); 10357 } 10358 } 10359 10360 @Override onBatchedInputEventPending(int source)10361 public void onBatchedInputEventPending(int source) { 10362 final boolean unbuffered = mUnbufferedInputDispatch 10363 || (source & mUnbufferedInputSource) != SOURCE_CLASS_NONE; 10364 if (unbuffered) { 10365 if (mConsumeBatchedInputScheduled) { 10366 unscheduleConsumeBatchedInput(); 10367 } 10368 // Consume event immediately if unbuffered input dispatch has been requested. 10369 consumeBatchedInputEvents(-1); 10370 return; 10371 } 10372 scheduleConsumeBatchedInput(); 10373 } 10374 10375 @Override onFocusEvent(boolean hasFocus)10376 public void onFocusEvent(boolean hasFocus) { 10377 windowFocusChanged(hasFocus); 10378 } 10379 10380 @Override onTouchModeChanged(boolean inTouchMode)10381 public void onTouchModeChanged(boolean inTouchMode) { 10382 touchModeChanged(inTouchMode); 10383 } 10384 10385 @Override onPointerCaptureEvent(boolean pointerCaptureEnabled)10386 public void onPointerCaptureEvent(boolean pointerCaptureEnabled) { 10387 dispatchPointerCaptureChanged(pointerCaptureEnabled); 10388 } 10389 10390 @Override onDragEvent(boolean isExiting, float x, float y)10391 public void onDragEvent(boolean isExiting, float x, float y) { 10392 // force DRAG_EXITED_EVENT if appropriate 10393 DragEvent event = DragEvent.obtain( 10394 isExiting ? DragEvent.ACTION_DRAG_EXITED : DragEvent.ACTION_DRAG_LOCATION, 10395 x, y, 0 /* offsetX */, 0 /* offsetY */, 0 /* flags */, null/* localState */, 10396 null/* description */, null /* data */, null /* dragSurface */, 10397 null /* dragAndDropPermissions */, false /* result */); 10398 dispatchDragEvent(event); 10399 } 10400 10401 @Override dispose()10402 public void dispose() { 10403 unscheduleConsumeBatchedInput(); 10404 super.dispose(); 10405 } 10406 } 10407 private WindowInputEventReceiver mInputEventReceiver; 10408 10409 final class InputMetricsListener 10410 implements HardwareRendererObserver.OnFrameMetricsAvailableListener { 10411 public long[] data = new long[FrameMetrics.Index.FRAME_STATS_COUNT]; 10412 10413 @Override onFrameMetricsAvailable(int dropCountSinceLastInvocation)10414 public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) { 10415 final int inputEventId = (int) data[FrameMetrics.Index.INPUT_EVENT_ID]; 10416 if (inputEventId == INVALID_INPUT_EVENT_ID) { 10417 return; 10418 } 10419 final long presentTime = data[FrameMetrics.Index.DISPLAY_PRESENT_TIME]; 10420 if (presentTime <= 0) { 10421 // Present time is not available for this frame. If the present time is not 10422 // available, we cannot compute end-to-end input latency metrics. 10423 return; 10424 } 10425 final long gpuCompletedTime = data[FrameMetrics.Index.GPU_COMPLETED]; 10426 if (mInputEventReceiver == null) { 10427 return; 10428 } 10429 if (gpuCompletedTime >= presentTime) { 10430 final double discrepancyMs = (gpuCompletedTime - presentTime) * 1E-6; 10431 final long vsyncId = data[FrameMetrics.Index.FRAME_TIMELINE_VSYNC_ID]; 10432 Log.w(TAG, "Not reporting timeline because gpuCompletedTime is " + discrepancyMs 10433 + "ms ahead of presentTime. FRAME_TIMELINE_VSYNC_ID=" + vsyncId 10434 + ", INPUT_EVENT_ID=" + inputEventId); 10435 // TODO(b/186664409): figure out why this sometimes happens 10436 return; 10437 } 10438 mInputEventReceiver.reportTimeline(inputEventId, gpuCompletedTime, presentTime); 10439 } 10440 } 10441 HardwareRendererObserver mHardwareRendererObserver; 10442 10443 final class ConsumeBatchedInputRunnable implements Runnable { 10444 @Override run()10445 public void run() { 10446 Trace.traceBegin(TRACE_TAG_VIEW, mTag); 10447 try { 10448 mConsumeBatchedInputScheduled = false; 10449 if (doConsumeBatchedInput(mChoreographer.getFrameTimeNanos())) { 10450 // If we consumed a batch here, we want to go ahead and schedule the 10451 // consumption of batched input events on the next frame. Otherwise, we would 10452 // wait until we have more input events pending and might get starved by other 10453 // things occurring in the process. 10454 scheduleConsumeBatchedInput(); 10455 } 10456 } finally { 10457 Trace.traceEnd(TRACE_TAG_VIEW); 10458 } 10459 } 10460 } 10461 final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable = 10462 new ConsumeBatchedInputRunnable(); 10463 boolean mConsumeBatchedInputScheduled; 10464 10465 final class ConsumeBatchedInputImmediatelyRunnable implements Runnable { 10466 @Override run()10467 public void run() { 10468 mConsumeBatchedInputImmediatelyScheduled = false; 10469 doConsumeBatchedInput(-1); 10470 } 10471 } 10472 final ConsumeBatchedInputImmediatelyRunnable mConsumeBatchedInputImmediatelyRunnable = 10473 new ConsumeBatchedInputImmediatelyRunnable(); 10474 boolean mConsumeBatchedInputImmediatelyScheduled; 10475 10476 final class InvalidateOnAnimationRunnable implements Runnable { 10477 private boolean mPosted; 10478 private final ArrayList<View> mViews = new ArrayList<View>(); 10479 private final ArrayList<AttachInfo.InvalidateInfo> mViewRects = 10480 new ArrayList<AttachInfo.InvalidateInfo>(); 10481 private View[] mTempViews; 10482 private AttachInfo.InvalidateInfo[] mTempViewRects; 10483 addView(View view)10484 public void addView(View view) { 10485 synchronized (this) { 10486 mViews.add(view); 10487 postIfNeededLocked(); 10488 } 10489 if (mAttachInfo.mThreadedRenderer != null) { 10490 mAttachInfo.mThreadedRenderer.notifyCallbackPending(); 10491 } 10492 } 10493 addViewRect(AttachInfo.InvalidateInfo info)10494 public void addViewRect(AttachInfo.InvalidateInfo info) { 10495 synchronized (this) { 10496 mViewRects.add(info); 10497 postIfNeededLocked(); 10498 } 10499 if (mAttachInfo.mThreadedRenderer != null) { 10500 mAttachInfo.mThreadedRenderer.notifyCallbackPending(); 10501 } 10502 } 10503 removeView(View view)10504 public void removeView(View view) { 10505 synchronized (this) { 10506 mViews.remove(view); 10507 10508 for (int i = mViewRects.size(); i-- > 0; ) { 10509 AttachInfo.InvalidateInfo info = mViewRects.get(i); 10510 if (info.target == view) { 10511 mViewRects.remove(i); 10512 info.recycle(); 10513 } 10514 } 10515 10516 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) { 10517 mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null); 10518 mPosted = false; 10519 } 10520 } 10521 } 10522 10523 @Override run()10524 public void run() { 10525 final int viewCount; 10526 final int viewRectCount; 10527 synchronized (this) { 10528 mPosted = false; 10529 10530 viewCount = mViews.size(); 10531 if (viewCount != 0) { 10532 mTempViews = mViews.toArray(mTempViews != null 10533 ? mTempViews : new View[viewCount]); 10534 mViews.clear(); 10535 } 10536 10537 viewRectCount = mViewRects.size(); 10538 if (viewRectCount != 0) { 10539 mTempViewRects = mViewRects.toArray(mTempViewRects != null 10540 ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]); 10541 mViewRects.clear(); 10542 } 10543 } 10544 10545 for (int i = 0; i < viewCount; i++) { 10546 mTempViews[i].invalidate(); 10547 mTempViews[i] = null; 10548 } 10549 10550 for (int i = 0; i < viewRectCount; i++) { 10551 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i]; 10552 info.target.invalidate(info.left, info.top, info.right, info.bottom); 10553 info.recycle(); 10554 } 10555 } 10556 postIfNeededLocked()10557 private void postIfNeededLocked() { 10558 if (!mPosted) { 10559 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null); 10560 mPosted = true; 10561 } 10562 } 10563 } 10564 final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable = 10565 new InvalidateOnAnimationRunnable(); 10566 dispatchInvalidateDelayed(View view, long delayMilliseconds)10567 public void dispatchInvalidateDelayed(View view, long delayMilliseconds) { 10568 Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view); 10569 mHandler.sendMessageDelayed(msg, delayMilliseconds); 10570 } 10571 dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info, long delayMilliseconds)10572 public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info, 10573 long delayMilliseconds) { 10574 final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info); 10575 mHandler.sendMessageDelayed(msg, delayMilliseconds); 10576 } 10577 dispatchInvalidateOnAnimation(View view)10578 public void dispatchInvalidateOnAnimation(View view) { 10579 mInvalidateOnAnimationRunnable.addView(view); 10580 } 10581 dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info)10582 public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) { 10583 mInvalidateOnAnimationRunnable.addViewRect(info); 10584 } 10585 10586 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) cancelInvalidate(View view)10587 public void cancelInvalidate(View view) { 10588 mHandler.removeMessages(MSG_INVALIDATE, view); 10589 // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning 10590 // them to the pool 10591 mHandler.removeMessages(MSG_INVALIDATE_RECT, view); 10592 mInvalidateOnAnimationRunnable.removeView(view); 10593 } 10594 10595 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) dispatchInputEvent(InputEvent event)10596 public void dispatchInputEvent(InputEvent event) { 10597 dispatchInputEvent(event, null); 10598 } 10599 10600 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) dispatchInputEvent(InputEvent event, InputEventReceiver receiver)10601 public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) { 10602 SomeArgs args = SomeArgs.obtain(); 10603 args.arg1 = event; 10604 args.arg2 = receiver; 10605 Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args); 10606 msg.setAsynchronous(true); 10607 mHandler.sendMessage(msg); 10608 } 10609 synthesizeInputEvent(InputEvent event)10610 public void synthesizeInputEvent(InputEvent event) { 10611 Message msg = mHandler.obtainMessage(MSG_SYNTHESIZE_INPUT_EVENT, event); 10612 msg.setAsynchronous(true); 10613 mHandler.sendMessage(msg); 10614 } 10615 10616 @UnsupportedAppUsage dispatchKeyFromIme(KeyEvent event)10617 public void dispatchKeyFromIme(KeyEvent event) { 10618 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event); 10619 msg.setAsynchronous(true); 10620 mHandler.sendMessage(msg); 10621 } 10622 dispatchKeyFromAutofill(KeyEvent event)10623 public void dispatchKeyFromAutofill(KeyEvent event) { 10624 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_AUTOFILL, event); 10625 msg.setAsynchronous(true); 10626 mHandler.sendMessage(msg); 10627 } 10628 10629 /** 10630 * Reinject unhandled {@link InputEvent}s in order to synthesize fallbacks events. 10631 * 10632 * Note that it is the responsibility of the caller of this API to recycle the InputEvent it 10633 * passes in. 10634 */ 10635 @UnsupportedAppUsage dispatchUnhandledInputEvent(InputEvent event)10636 public void dispatchUnhandledInputEvent(InputEvent event) { 10637 if (event instanceof MotionEvent) { 10638 event = MotionEvent.obtain((MotionEvent) event); 10639 } 10640 synthesizeInputEvent(event); 10641 } 10642 dispatchAppVisibility(boolean visible)10643 public void dispatchAppVisibility(boolean visible) { 10644 Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY); 10645 msg.arg1 = visible ? 1 : 0; 10646 mHandler.sendMessage(msg); 10647 } 10648 dispatchGetNewSurface()10649 public void dispatchGetNewSurface() { 10650 Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE); 10651 mHandler.sendMessage(msg); 10652 } 10653 10654 /** 10655 * Notifies this {@link ViewRootImpl} object that window focus has changed. 10656 */ windowFocusChanged(boolean hasFocus)10657 public void windowFocusChanged(boolean hasFocus) { 10658 synchronized (this) { 10659 mWindowFocusChanged = true; 10660 mUpcomingWindowFocus = hasFocus; 10661 } 10662 Message msg = Message.obtain(); 10663 msg.what = MSG_WINDOW_FOCUS_CHANGED; 10664 mHandler.sendMessage(msg); 10665 } 10666 10667 /** 10668 * Notifies this {@link ViewRootImpl} object that touch mode state has changed. 10669 */ touchModeChanged(boolean inTouchMode)10670 public void touchModeChanged(boolean inTouchMode) { 10671 synchronized (this) { 10672 mUpcomingInTouchMode = inTouchMode; 10673 } 10674 Message msg = Message.obtain(); 10675 msg.what = MSG_WINDOW_TOUCH_MODE_CHANGED; 10676 mHandler.sendMessage(msg); 10677 } 10678 dispatchWindowShown()10679 public void dispatchWindowShown() { 10680 mHandler.sendEmptyMessage(MSG_DISPATCH_WINDOW_SHOWN); 10681 } 10682 dispatchCloseSystemDialogs(String reason)10683 public void dispatchCloseSystemDialogs(String reason) { 10684 Message msg = Message.obtain(); 10685 msg.what = MSG_CLOSE_SYSTEM_DIALOGS; 10686 msg.obj = reason; 10687 mHandler.sendMessage(msg); 10688 } 10689 dispatchDragEvent(DragEvent event)10690 public void dispatchDragEvent(DragEvent event) { 10691 final int what; 10692 if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) { 10693 what = MSG_DISPATCH_DRAG_LOCATION_EVENT; 10694 mHandler.removeMessages(what); 10695 } else { 10696 what = MSG_DISPATCH_DRAG_EVENT; 10697 } 10698 Message msg = mHandler.obtainMessage(what, event); 10699 mHandler.sendMessage(msg); 10700 } 10701 dispatchCheckFocus()10702 public void dispatchCheckFocus() { 10703 if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) { 10704 // This will result in a call to checkFocus() below. 10705 mHandler.sendEmptyMessage(MSG_CHECK_FOCUS); 10706 } 10707 } 10708 dispatchRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId)10709 public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) { 10710 mHandler.obtainMessage( 10711 MSG_REQUEST_KEYBOARD_SHORTCUTS, deviceId, 0, receiver).sendToTarget(); 10712 } 10713 dispatchPointerCaptureChanged(boolean on)10714 private void dispatchPointerCaptureChanged(boolean on) { 10715 final int what = MSG_POINTER_CAPTURE_CHANGED; 10716 mHandler.removeMessages(what); 10717 Message msg = mHandler.obtainMessage(what); 10718 msg.arg1 = on ? 1 : 0; 10719 mHandler.sendMessage(msg); 10720 } 10721 10722 /** 10723 * Post a callback to send a 10724 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event. 10725 * This event is send at most once every 10726 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 10727 */ postSendWindowContentChangedCallback(View source, int changeType)10728 private void postSendWindowContentChangedCallback(View source, int changeType) { 10729 if (mSendWindowContentChangedAccessibilityEvent == null) { 10730 mSendWindowContentChangedAccessibilityEvent = 10731 new SendWindowContentChangedAccessibilityEvent(); 10732 } 10733 mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType); 10734 } 10735 10736 /** 10737 * Remove a posted callback to send a 10738 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event. 10739 */ removeSendWindowContentChangedCallback()10740 private void removeSendWindowContentChangedCallback() { 10741 if (mSendWindowContentChangedAccessibilityEvent != null) { 10742 mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent); 10743 } 10744 } 10745 10746 /** 10747 * Return the connection ID for the {@link AccessibilityInteractionController} of this instance. 10748 * @see AccessibilityNodeInfo#setQueryFromAppProcessEnabled 10749 */ getDirectAccessibilityConnectionId()10750 public int getDirectAccessibilityConnectionId() { 10751 return mAccessibilityInteractionConnectionManager.ensureDirectConnection(); 10752 } 10753 10754 @Override showContextMenuForChild(View originalView)10755 public boolean showContextMenuForChild(View originalView) { 10756 return false; 10757 } 10758 10759 @Override showContextMenuForChild(View originalView, float x, float y)10760 public boolean showContextMenuForChild(View originalView, float x, float y) { 10761 return false; 10762 } 10763 10764 @Override startActionModeForChild(View originalView, ActionMode.Callback callback)10765 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) { 10766 return null; 10767 } 10768 10769 @Override startActionModeForChild( View originalView, ActionMode.Callback callback, int type)10770 public ActionMode startActionModeForChild( 10771 View originalView, ActionMode.Callback callback, int type) { 10772 return null; 10773 } 10774 10775 @Override createContextMenu(ContextMenu menu)10776 public void createContextMenu(ContextMenu menu) { 10777 } 10778 10779 @Override childDrawableStateChanged(View child)10780 public void childDrawableStateChanged(View child) { 10781 } 10782 10783 @Override requestSendAccessibilityEvent(View child, AccessibilityEvent event)10784 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) { 10785 if (mView == null || mStopped || mPausedForTransition) { 10786 return false; 10787 } 10788 10789 // Immediately flush pending content changed event (if any) to preserve event order 10790 if (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED 10791 && mSendWindowContentChangedAccessibilityEvent != null 10792 && mSendWindowContentChangedAccessibilityEvent.mSource != null) { 10793 mSendWindowContentChangedAccessibilityEvent.removeCallbacksAndRun(); 10794 } 10795 10796 // Intercept accessibility focus events fired by virtual nodes to keep 10797 // track of accessibility focus position in such nodes. 10798 final int eventType = event.getEventType(); 10799 final View source = getSourceForAccessibilityEvent(event); 10800 switch (eventType) { 10801 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: { 10802 if (source != null) { 10803 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider(); 10804 if (provider != null) { 10805 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId( 10806 event.getSourceNodeId()); 10807 final AccessibilityNodeInfo node; 10808 node = provider.createAccessibilityNodeInfo(virtualNodeId); 10809 setAccessibilityFocus(source, node); 10810 } 10811 } 10812 } break; 10813 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: { 10814 if (source != null && source.getAccessibilityNodeProvider() != null) { 10815 setAccessibilityFocus(null, null); 10816 } 10817 } break; 10818 10819 10820 case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: { 10821 handleWindowContentChangedEvent(event); 10822 } break; 10823 } 10824 mAccessibilityManager.sendAccessibilityEvent(event); 10825 return true; 10826 } 10827 getSourceForAccessibilityEvent(AccessibilityEvent event)10828 private View getSourceForAccessibilityEvent(AccessibilityEvent event) { 10829 final long sourceNodeId = event.getSourceNodeId(); 10830 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId( 10831 sourceNodeId); 10832 return AccessibilityNodeIdManager.getInstance().findView(accessibilityViewId); 10833 } 10834 isAccessibilityFocusDirty()10835 private boolean isAccessibilityFocusDirty() { 10836 final Drawable drawable = mAttachInfo.mAccessibilityFocusDrawable; 10837 if (drawable != null) { 10838 final Rect bounds = mAttachInfo.mTmpInvalRect; 10839 final boolean hasFocus = getAccessibilityFocusedRect(bounds); 10840 if (!hasFocus) { 10841 bounds.setEmpty(); 10842 } 10843 if (!bounds.equals(drawable.getBounds())) { 10844 return true; 10845 } 10846 } 10847 return false; 10848 } 10849 10850 /** 10851 * Updates the focused virtual view, when necessary, in response to a 10852 * content changed event. 10853 * <p> 10854 * This is necessary to get updated bounds after a position change. 10855 * 10856 * @param event an accessibility event of type 10857 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} 10858 */ handleWindowContentChangedEvent(AccessibilityEvent event)10859 private void handleWindowContentChangedEvent(AccessibilityEvent event) { 10860 final View focusedHost = mAccessibilityFocusedHost; 10861 if (focusedHost == null || mAccessibilityFocusedVirtualView == null) { 10862 // No virtual view focused, nothing to do here. 10863 return; 10864 } 10865 10866 final AccessibilityNodeProvider provider = focusedHost.getAccessibilityNodeProvider(); 10867 if (provider == null) { 10868 // Error state: virtual view with no provider. Clear focus. 10869 mAccessibilityFocusedHost = null; 10870 mAccessibilityFocusedVirtualView = null; 10871 focusedHost.clearAccessibilityFocusNoCallbacks(0); 10872 return; 10873 } 10874 10875 // We only care about change types that may affect the bounds of the 10876 // focused virtual view. 10877 final int changes = event.getContentChangeTypes(); 10878 if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) == 0 10879 && changes != AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) { 10880 return; 10881 } 10882 10883 final long eventSourceNodeId = event.getSourceNodeId(); 10884 final int changedViewId = AccessibilityNodeInfo.getAccessibilityViewId(eventSourceNodeId); 10885 10886 // Search up the tree for subtree containment. 10887 boolean hostInSubtree = false; 10888 View root = mAccessibilityFocusedHost; 10889 while (root != null && !hostInSubtree) { 10890 if (changedViewId == root.getAccessibilityViewId()) { 10891 hostInSubtree = true; 10892 } else { 10893 final ViewParent parent = root.getParent(); 10894 if (parent instanceof View) { 10895 root = (View) parent; 10896 } else { 10897 root = null; 10898 } 10899 } 10900 } 10901 10902 // We care only about changes in subtrees containing the host view. 10903 if (!hostInSubtree) { 10904 return; 10905 } 10906 10907 final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId(); 10908 int focusedChildId = AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId); 10909 10910 // Refresh the node for the focused virtual view. 10911 final Rect oldBounds = mTempRect; 10912 mAccessibilityFocusedVirtualView.getBoundsInScreen(oldBounds); 10913 mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo(focusedChildId); 10914 if (mAccessibilityFocusedVirtualView == null) { 10915 // Error state: The node no longer exists. Clear focus. 10916 mAccessibilityFocusedHost = null; 10917 focusedHost.clearAccessibilityFocusNoCallbacks(0); 10918 10919 // This will probably fail, but try to keep the provider's internal 10920 // state consistent by clearing focus. 10921 provider.performAction(focusedChildId, 10922 AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(), null); 10923 invalidateRectOnScreen(oldBounds); 10924 } else { 10925 // The node was refreshed, invalidate bounds if necessary. 10926 final Rect newBounds = mAccessibilityFocusedVirtualView.getBoundsInScreen(); 10927 if (!oldBounds.equals(newBounds)) { 10928 oldBounds.union(newBounds); 10929 invalidateRectOnScreen(oldBounds); 10930 } 10931 } 10932 } 10933 10934 @Override notifySubtreeAccessibilityStateChanged(View child, View source, int changeType)10935 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) { 10936 postSendWindowContentChangedCallback(Objects.requireNonNull(source), changeType); 10937 } 10938 10939 @Override canResolveLayoutDirection()10940 public boolean canResolveLayoutDirection() { 10941 return true; 10942 } 10943 10944 @Override isLayoutDirectionResolved()10945 public boolean isLayoutDirectionResolved() { 10946 return true; 10947 } 10948 10949 @Override getLayoutDirection()10950 public int getLayoutDirection() { 10951 return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT; 10952 } 10953 10954 @Override canResolveTextDirection()10955 public boolean canResolveTextDirection() { 10956 return true; 10957 } 10958 10959 @Override isTextDirectionResolved()10960 public boolean isTextDirectionResolved() { 10961 return true; 10962 } 10963 10964 @Override getTextDirection()10965 public int getTextDirection() { 10966 return View.TEXT_DIRECTION_RESOLVED_DEFAULT; 10967 } 10968 10969 @Override canResolveTextAlignment()10970 public boolean canResolveTextAlignment() { 10971 return true; 10972 } 10973 10974 @Override isTextAlignmentResolved()10975 public boolean isTextAlignmentResolved() { 10976 return true; 10977 } 10978 10979 @Override getTextAlignment()10980 public int getTextAlignment() { 10981 return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT; 10982 } 10983 getCommonPredecessor(View first, View second)10984 private View getCommonPredecessor(View first, View second) { 10985 if (mTempHashSet == null) { 10986 mTempHashSet = new HashSet<View>(); 10987 } 10988 HashSet<View> seen = mTempHashSet; 10989 seen.clear(); 10990 View firstCurrent = first; 10991 while (firstCurrent != null) { 10992 seen.add(firstCurrent); 10993 ViewParent firstCurrentParent = firstCurrent.mParent; 10994 if (firstCurrentParent instanceof View) { 10995 firstCurrent = (View) firstCurrentParent; 10996 } else { 10997 firstCurrent = null; 10998 } 10999 } 11000 View secondCurrent = second; 11001 while (secondCurrent != null) { 11002 if (seen.contains(secondCurrent)) { 11003 seen.clear(); 11004 return secondCurrent; 11005 } 11006 ViewParent secondCurrentParent = secondCurrent.mParent; 11007 if (secondCurrentParent instanceof View) { 11008 secondCurrent = (View) secondCurrentParent; 11009 } else { 11010 secondCurrent = null; 11011 } 11012 } 11013 seen.clear(); 11014 return null; 11015 } 11016 checkThread()11017 void checkThread() { 11018 Thread current = Thread.currentThread(); 11019 if (mThread != current) { 11020 throw new CalledFromWrongThreadException( 11021 "Only the original thread that created a view hierarchy can touch its views." 11022 + " Expected: " + mThread.getName() 11023 + " Calling: " + current.getName()); 11024 } 11025 } 11026 11027 @Override requestDisallowInterceptTouchEvent(boolean disallowIntercept)11028 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { 11029 // ViewAncestor never intercepts touch event, so this can be a no-op 11030 } 11031 11032 @Override requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate)11033 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) { 11034 if (rectangle == null) { 11035 return scrollToRectOrFocus(null, immediate); 11036 } 11037 rectangle.offset(child.getLeft() - child.getScrollX(), 11038 child.getTop() - child.getScrollY()); 11039 final boolean scrolled = scrollToRectOrFocus(rectangle, immediate); 11040 mTempRect.set(rectangle); 11041 mTempRect.offset(0, -mCurScrollY); 11042 mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 11043 try { 11044 mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect); 11045 } catch (RemoteException re) { 11046 /* ignore */ 11047 } 11048 return scrolled; 11049 } 11050 11051 @Override childHasTransientStateChanged(View child, boolean hasTransientState)11052 public void childHasTransientStateChanged(View child, boolean hasTransientState) { 11053 // Do nothing. 11054 } 11055 11056 @Override onStartNestedScroll(View child, View target, int nestedScrollAxes)11057 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) { 11058 return false; 11059 } 11060 11061 @Override onStopNestedScroll(View target)11062 public void onStopNestedScroll(View target) { 11063 } 11064 11065 @Override onNestedScrollAccepted(View child, View target, int nestedScrollAxes)11066 public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) { 11067 } 11068 11069 @Override onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed)11070 public void onNestedScroll(View target, int dxConsumed, int dyConsumed, 11071 int dxUnconsumed, int dyUnconsumed) { 11072 } 11073 11074 @Override onNestedPreScroll(View target, int dx, int dy, int[] consumed)11075 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) { 11076 } 11077 11078 @Override onNestedFling(View target, float velocityX, float velocityY, boolean consumed)11079 public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) { 11080 return false; 11081 } 11082 11083 @Override onNestedPreFling(View target, float velocityX, float velocityY)11084 public boolean onNestedPreFling(View target, float velocityX, float velocityY) { 11085 return false; 11086 } 11087 11088 @Override onNestedPrePerformAccessibilityAction(View target, int action, Bundle args)11089 public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) { 11090 return false; 11091 } 11092 11093 /** 11094 * Checks the input event receiver for input availability. 11095 * May return false negatives. 11096 * @hide 11097 */ probablyHasInput()11098 public boolean probablyHasInput() { 11099 if (mInputEventReceiver == null) { 11100 return false; 11101 } 11102 return mInputEventReceiver.probablyHasInput(); 11103 } 11104 11105 /** 11106 * Adds a scroll capture callback to this window. 11107 * 11108 * @param callback the callback to add 11109 */ addScrollCaptureCallback(ScrollCaptureCallback callback)11110 public void addScrollCaptureCallback(ScrollCaptureCallback callback) { 11111 if (mRootScrollCaptureCallbacks == null) { 11112 mRootScrollCaptureCallbacks = new HashSet<>(); 11113 } 11114 mRootScrollCaptureCallbacks.add(callback); 11115 } 11116 11117 /** 11118 * Removes a scroll capture callback from this window. 11119 * 11120 * @param callback the callback to remove 11121 */ removeScrollCaptureCallback(ScrollCaptureCallback callback)11122 public void removeScrollCaptureCallback(ScrollCaptureCallback callback) { 11123 if (mRootScrollCaptureCallbacks != null) { 11124 mRootScrollCaptureCallbacks.remove(callback); 11125 if (mRootScrollCaptureCallbacks.isEmpty()) { 11126 mRootScrollCaptureCallbacks = null; 11127 } 11128 } 11129 } 11130 11131 /** 11132 * Dispatches a scroll capture request to the view hierarchy on the ui thread. 11133 * 11134 * @param listener for the response 11135 */ dispatchScrollCaptureRequest(@onNull IScrollCaptureResponseListener listener)11136 public void dispatchScrollCaptureRequest(@NonNull IScrollCaptureResponseListener listener) { 11137 mHandler.obtainMessage(MSG_REQUEST_SCROLL_CAPTURE, listener).sendToTarget(); 11138 } 11139 11140 // Make this VRI able to process back key without drop it. processingBackKey(boolean processing)11141 void processingBackKey(boolean processing) { 11142 mProcessingBackKey = processing; 11143 } 11144 11145 /** 11146 * Collect and include any ScrollCaptureCallback instances registered with the window. 11147 * 11148 * @see #addScrollCaptureCallback(ScrollCaptureCallback) 11149 * @param results an object to collect the results of the search 11150 */ collectRootScrollCaptureTargets(ScrollCaptureSearchResults results)11151 private void collectRootScrollCaptureTargets(ScrollCaptureSearchResults results) { 11152 if (mRootScrollCaptureCallbacks == null) { 11153 return; 11154 } 11155 for (ScrollCaptureCallback cb : mRootScrollCaptureCallbacks) { 11156 // Add to the list for consideration 11157 Point offset = new Point(mView.getLeft(), mView.getTop()); 11158 Rect rect = new Rect(0, 0, mView.getWidth(), mView.getHeight()); 11159 results.addTarget(new ScrollCaptureTarget(mView, rect, offset, cb)); 11160 } 11161 } 11162 11163 /** 11164 * Update the timeout for scroll capture requests. Only affects this view root. 11165 * The default value is {@link #SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS}. 11166 * 11167 * @param timeMillis the new timeout in milliseconds 11168 */ setScrollCaptureRequestTimeout(int timeMillis)11169 public void setScrollCaptureRequestTimeout(int timeMillis) { 11170 mScrollCaptureRequestTimeout = timeMillis; 11171 } 11172 11173 /** 11174 * Get the current timeout for scroll capture requests. 11175 * 11176 * @return the timeout in milliseconds 11177 */ getScrollCaptureRequestTimeout()11178 public long getScrollCaptureRequestTimeout() { 11179 return mScrollCaptureRequestTimeout; 11180 } 11181 11182 /** 11183 * Handles an inbound request for scroll capture from the system. A search will be 11184 * dispatched through the view tree to locate scrolling content. 11185 * <p> 11186 * A call to 11187 * {@link IScrollCaptureResponseListener#onScrollCaptureResponse} will follow. 11188 * 11189 * @param listener to receive responses 11190 * @see ScrollCaptureSearchResults 11191 */ handleScrollCaptureRequest(@onNull IScrollCaptureResponseListener listener)11192 public void handleScrollCaptureRequest(@NonNull IScrollCaptureResponseListener listener) { 11193 ScrollCaptureSearchResults results = 11194 new ScrollCaptureSearchResults(mContext.getMainExecutor()); 11195 11196 // Window (root) level callbacks 11197 collectRootScrollCaptureTargets(results); 11198 11199 // Search through View-tree 11200 View rootView = getView(); 11201 if (rootView != null) { 11202 Point point = new Point(); 11203 Rect rect = new Rect(0, 0, rootView.getWidth(), rootView.getHeight()); 11204 getChildVisibleRect(rootView, rect, point); 11205 rootView.dispatchScrollCaptureSearch(rect, point, results::addTarget); 11206 } 11207 Runnable onComplete = () -> dispatchScrollCaptureSearchResponse(listener, results); 11208 results.setOnCompleteListener(onComplete); 11209 if (!results.isComplete()) { 11210 mHandler.postDelayed(results::finish, getScrollCaptureRequestTimeout()); 11211 } 11212 } 11213 11214 /** Called by {@link #handleScrollCaptureRequest} when a result is returned */ dispatchScrollCaptureSearchResponse( @onNull IScrollCaptureResponseListener listener, @NonNull ScrollCaptureSearchResults results)11215 private void dispatchScrollCaptureSearchResponse( 11216 @NonNull IScrollCaptureResponseListener listener, 11217 @NonNull ScrollCaptureSearchResults results) { 11218 11219 ScrollCaptureTarget selectedTarget = results.getTopResult(); 11220 11221 ScrollCaptureResponse.Builder response = new ScrollCaptureResponse.Builder(); 11222 response.setWindowTitle(getTitle().toString()); 11223 response.setPackageName(mContext.getPackageName()); 11224 11225 StringWriter writer = new StringWriter(); 11226 IndentingPrintWriter pw = new IndentingPrintWriter(writer); 11227 results.dump(pw); 11228 pw.flush(); 11229 response.addMessage(writer.toString()); 11230 11231 if (selectedTarget == null) { 11232 response.setDescription("No scrollable targets found in window"); 11233 try { 11234 listener.onScrollCaptureResponse(response.build()); 11235 } catch (RemoteException e) { 11236 Log.e(TAG, "Failed to send scroll capture search result", e); 11237 } 11238 return; 11239 } 11240 11241 response.setDescription("Connected"); 11242 11243 // Compute area covered by scrolling content within window 11244 Rect boundsInWindow = new Rect(); 11245 View containingView = selectedTarget.getContainingView(); 11246 containingView.getLocationInWindow(mAttachInfo.mTmpLocation); 11247 boundsInWindow.set(selectedTarget.getScrollBounds()); 11248 boundsInWindow.offset(mAttachInfo.mTmpLocation[0], mAttachInfo.mTmpLocation[1]); 11249 response.setBoundsInWindow(boundsInWindow); 11250 11251 // Compute the area on screen covered by the window 11252 Rect boundsOnScreen = new Rect(); 11253 mView.getLocationOnScreen(mAttachInfo.mTmpLocation); 11254 boundsOnScreen.set(0, 0, mView.getWidth(), mView.getHeight()); 11255 boundsOnScreen.offset(mAttachInfo.mTmpLocation[0], mAttachInfo.mTmpLocation[1]); 11256 response.setWindowBounds(boundsOnScreen); 11257 11258 // Create a connection and return it to the caller 11259 ScrollCaptureConnection connection = new ScrollCaptureConnection( 11260 mView.getContext().getMainExecutor(), selectedTarget); 11261 response.setConnection(connection); 11262 11263 try { 11264 listener.onScrollCaptureResponse(response.build()); 11265 } catch (RemoteException e) { 11266 if (DEBUG_SCROLL_CAPTURE) { 11267 Log.w(TAG, "Failed to send scroll capture search response.", e); 11268 } 11269 connection.close(); 11270 } 11271 } 11272 reportNextDraw(String reason)11273 private void reportNextDraw(String reason) { 11274 if (DEBUG_BLAST) { 11275 Log.d(mTag, "reportNextDraw " + Debug.getCallers(5)); 11276 } 11277 mReportNextDraw = true; 11278 mLastReportNextDrawReason = reason; 11279 } 11280 11281 /** 11282 * Force the window to report its next draw. 11283 * <p> 11284 * This method is only supposed to be used to speed up the interaction from SystemUI and window 11285 * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE 11286 * unless you fully understand this interaction. 11287 * 11288 * @param syncBuffer If true, the transaction that contains the buffer from the draw should be 11289 * sent to system to be synced. If false, VRI will not try to sync the buffer, 11290 * but only report back that a buffer was drawn. 11291 * @param reason A debug string indicating the reason for reporting the next draw 11292 * @hide 11293 */ setReportNextDraw(boolean syncBuffer, String reason)11294 public void setReportNextDraw(boolean syncBuffer, String reason) { 11295 mSyncBuffer = syncBuffer; 11296 reportNextDraw(reason); 11297 invalidate(); 11298 } 11299 changeCanvasOpacity(boolean opaque)11300 void changeCanvasOpacity(boolean opaque) { 11301 Log.d(mTag, "changeCanvasOpacity: opaque=" + opaque); 11302 opaque = opaque & ((mView.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0); 11303 if (mAttachInfo.mThreadedRenderer != null) { 11304 mAttachInfo.mThreadedRenderer.setOpaque(opaque); 11305 } 11306 } 11307 11308 /** 11309 * Dispatches a KeyEvent to all registered key fallback handlers. 11310 * 11311 * @param event 11312 * @return {@code true} if the event was handled, {@code false} otherwise. 11313 */ dispatchUnhandledKeyEvent(KeyEvent event)11314 public boolean dispatchUnhandledKeyEvent(KeyEvent event) { 11315 return mUnhandledKeyManager.dispatch(mView, event); 11316 } 11317 11318 class TakenSurfaceHolder extends BaseSurfaceHolder { 11319 @Override onAllowLockCanvas()11320 public boolean onAllowLockCanvas() { 11321 return mDrawingAllowed; 11322 } 11323 11324 @Override onRelayoutContainer()11325 public void onRelayoutContainer() { 11326 // Not currently interesting -- from changing between fixed and layout size. 11327 } 11328 11329 @Override setFormat(int format)11330 public void setFormat(int format) { 11331 ((RootViewSurfaceTaker)mView).setSurfaceFormat(format); 11332 } 11333 11334 @Override setType(int type)11335 public void setType(int type) { 11336 ((RootViewSurfaceTaker)mView).setSurfaceType(type); 11337 } 11338 11339 @Override onUpdateSurface()11340 public void onUpdateSurface() { 11341 // We take care of format and type changes on our own. 11342 throw new IllegalStateException("Shouldn't be here"); 11343 } 11344 11345 @Override isCreating()11346 public boolean isCreating() { 11347 return mIsCreating; 11348 } 11349 11350 @Override setFixedSize(int width, int height)11351 public void setFixedSize(int width, int height) { 11352 throw new UnsupportedOperationException( 11353 "Currently only support sizing from layout"); 11354 } 11355 11356 @Override setKeepScreenOn(boolean screenOn)11357 public void setKeepScreenOn(boolean screenOn) { 11358 ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn); 11359 } 11360 } 11361 11362 static class W extends IWindow.Stub implements WindowStateTransactionItem.TransactionListener { 11363 private final WeakReference<ViewRootImpl> mViewAncestor; 11364 private final IWindowSession mWindowSession; 11365 private boolean mIsFromTransactionItem; 11366 W(ViewRootImpl viewAncestor)11367 W(ViewRootImpl viewAncestor) { 11368 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor); 11369 mWindowSession = viewAncestor.mWindowSession; 11370 } 11371 11372 @Override onExecutingWindowStateTransactionItem()11373 public void onExecutingWindowStateTransactionItem() { 11374 mIsFromTransactionItem = true; 11375 } 11376 11377 @Override resized(ClientWindowFrames frames, boolean reportDraw, MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing, @Nullable ActivityWindowInfo activityWindowInfo)11378 public void resized(ClientWindowFrames frames, boolean reportDraw, 11379 MergedConfiguration mergedConfiguration, InsetsState insetsState, 11380 boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, 11381 boolean dragResizing, @Nullable ActivityWindowInfo activityWindowInfo) { 11382 final boolean isFromResizeItem = mIsFromTransactionItem; 11383 mIsFromTransactionItem = false; 11384 // Although this is a AIDL method, it will only be triggered in local process through 11385 // either WindowStateResizeItem or WindowlessWindowManager. 11386 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11387 if (viewAncestor == null) { 11388 return; 11389 } 11390 if (insetsState.isSourceOrDefaultVisible(ID_IME, Type.ime())) { 11391 ImeTracing.getInstance().triggerClientDump("ViewRootImpl.W#resized", 11392 viewAncestor.getInsetsController().getHost().getInputMethodManager(), 11393 null /* icProto */); 11394 } 11395 // If the UI thread is the same as the current thread that is dispatching 11396 // WindowStateResizeItem, then it can run directly. 11397 if (isFromResizeItem && viewAncestor.mHandler.getLooper() 11398 == ActivityThread.currentActivityThread().getLooper()) { 11399 viewAncestor.handleResized(frames, reportDraw, mergedConfiguration, insetsState, 11400 forceLayout, alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing, 11401 activityWindowInfo); 11402 return; 11403 } 11404 // The the parameters from WindowStateResizeItem are already copied. 11405 final boolean needsCopy = 11406 !isFromResizeItem && (Binder.getCallingPid() == Process.myPid()); 11407 if (needsCopy) { 11408 insetsState = new InsetsState(insetsState, true /* copySource */); 11409 frames = new ClientWindowFrames(frames); 11410 mergedConfiguration = new MergedConfiguration(mergedConfiguration); 11411 } 11412 viewAncestor.dispatchResized(frames, reportDraw, mergedConfiguration, insetsState, 11413 forceLayout, alwaysConsumeSystemBars, displayId, syncSeqId, dragResizing, 11414 activityWindowInfo); 11415 } 11416 11417 @Override insetsControlChanged(InsetsState insetsState, InsetsSourceControl.Array activeControls)11418 public void insetsControlChanged(InsetsState insetsState, 11419 InsetsSourceControl.Array activeControls) { 11420 final boolean isFromInsetsControlChangeItem; 11421 if (insetsControlChangedItem()) { 11422 isFromInsetsControlChangeItem = mIsFromTransactionItem; 11423 mIsFromTransactionItem = false; 11424 } else { 11425 isFromInsetsControlChangeItem = false; 11426 } 11427 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11428 if (viewAncestor == null) { 11429 if (isFromInsetsControlChangeItem) { 11430 activeControls.release(); 11431 } 11432 return; 11433 } 11434 if (insetsState.isSourceOrDefaultVisible(ID_IME, Type.ime())) { 11435 ImeTracing.getInstance().triggerClientDump( 11436 "ViewRootImpl#dispatchInsetsControlChanged", 11437 viewAncestor.getInsetsController().getHost().getInputMethodManager(), 11438 null /* icProto */); 11439 } 11440 // If the UI thread is the same as the current thread that is dispatching 11441 // WindowStateInsetsControlChangeItem, then it can run directly. 11442 if (isFromInsetsControlChangeItem && viewAncestor.mHandler.getLooper() 11443 == ActivityThread.currentActivityThread().getLooper()) { 11444 viewAncestor.handleInsetsControlChanged(insetsState, activeControls); 11445 return; 11446 } 11447 // The parameters from WindowStateInsetsControlChangeItem are already copied. 11448 final boolean needsCopy = 11449 !isFromInsetsControlChangeItem && (Binder.getCallingPid() == Process.myPid()); 11450 if (needsCopy) { 11451 insetsState = new InsetsState(insetsState, true /* copySource */); 11452 activeControls = new InsetsSourceControl.Array( 11453 activeControls, true /* copyControls */); 11454 } 11455 11456 viewAncestor.dispatchInsetsControlChanged(insetsState, activeControls); 11457 } 11458 11459 @Override showInsets(@nsetsType int types, boolean fromIme, @Nullable ImeTracker.Token statsToken)11460 public void showInsets(@InsetsType int types, boolean fromIme, 11461 @Nullable ImeTracker.Token statsToken) { 11462 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11463 if (fromIme) { 11464 ImeTracing.getInstance().triggerClientDump("ViewRootImpl.W#showInsets", 11465 viewAncestor.getInsetsController().getHost().getInputMethodManager(), 11466 null /* icProto */); 11467 } 11468 if (viewAncestor != null) { 11469 ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_SHOW_INSETS); 11470 viewAncestor.showInsets(types, fromIme, statsToken); 11471 } else { 11472 ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_SHOW_INSETS); 11473 } 11474 } 11475 11476 @Override hideInsets(@nsetsType int types, boolean fromIme, @Nullable ImeTracker.Token statsToken)11477 public void hideInsets(@InsetsType int types, boolean fromIme, 11478 @Nullable ImeTracker.Token statsToken) { 11479 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11480 if (fromIme) { 11481 ImeTracing.getInstance().triggerClientDump("ViewRootImpl.W#hideInsets", 11482 viewAncestor.getInsetsController().getHost().getInputMethodManager(), 11483 null /* icProto */); 11484 } 11485 if (viewAncestor != null) { 11486 ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_HIDE_INSETS); 11487 viewAncestor.hideInsets(types, fromIme, statsToken); 11488 } else { 11489 ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_HIDE_INSETS); 11490 } 11491 } 11492 11493 @Override moved(int newX, int newY)11494 public void moved(int newX, int newY) { 11495 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11496 if (viewAncestor != null) { 11497 viewAncestor.dispatchMoved(newX, newY); 11498 } 11499 } 11500 11501 @Override dispatchAppVisibility(boolean visible)11502 public void dispatchAppVisibility(boolean visible) { 11503 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11504 if (viewAncestor != null) { 11505 viewAncestor.dispatchAppVisibility(visible); 11506 } 11507 } 11508 11509 @Override dispatchGetNewSurface()11510 public void dispatchGetNewSurface() { 11511 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11512 if (viewAncestor != null) { 11513 viewAncestor.dispatchGetNewSurface(); 11514 } 11515 } 11516 checkCallingPermission(String permission)11517 private static int checkCallingPermission(String permission) { 11518 try { 11519 return ActivityManager.getService().checkPermission( 11520 permission, Binder.getCallingPid(), Binder.getCallingUid()); 11521 } catch (RemoteException e) { 11522 return PackageManager.PERMISSION_DENIED; 11523 } 11524 } 11525 11526 @Override executeCommand(String command, String parameters, ParcelFileDescriptor out)11527 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) { 11528 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11529 if (viewAncestor != null) { 11530 final View view = viewAncestor.mView; 11531 if (view != null) { 11532 if (checkCallingPermission(Manifest.permission.DUMP) != 11533 PackageManager.PERMISSION_GRANTED) { 11534 throw new SecurityException("Insufficient permissions to invoke" 11535 + " executeCommand() from pid=" + Binder.getCallingPid() 11536 + ", uid=" + Binder.getCallingUid()); 11537 } 11538 11539 OutputStream clientStream = null; 11540 try { 11541 clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out); 11542 ViewDebug.dispatchCommand(view, command, parameters, clientStream); 11543 } catch (IOException e) { 11544 e.printStackTrace(); 11545 } finally { 11546 if (clientStream != null) { 11547 try { 11548 clientStream.close(); 11549 } catch (IOException e) { 11550 e.printStackTrace(); 11551 } 11552 } 11553 } 11554 } 11555 } 11556 } 11557 11558 @Override closeSystemDialogs(String reason)11559 public void closeSystemDialogs(String reason) { 11560 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11561 if (viewAncestor != null) { 11562 viewAncestor.dispatchCloseSystemDialogs(reason); 11563 } 11564 } 11565 11566 @Override dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, float zoom, boolean sync)11567 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, 11568 float zoom, boolean sync) { 11569 if (sync) { 11570 try { 11571 mWindowSession.wallpaperOffsetsComplete(asBinder()); 11572 } catch (RemoteException e) { 11573 } 11574 } 11575 } 11576 11577 @Override dispatchWallpaperCommand(String action, int x, int y, int z, Bundle extras, boolean sync)11578 public void dispatchWallpaperCommand(String action, int x, int y, 11579 int z, Bundle extras, boolean sync) { 11580 if (sync) { 11581 try { 11582 mWindowSession.wallpaperCommandComplete(asBinder(), null); 11583 } catch (RemoteException e) { 11584 } 11585 } 11586 } 11587 11588 /* Drag/drop */ 11589 @Override dispatchDragEvent(DragEvent event)11590 public void dispatchDragEvent(DragEvent event) { 11591 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11592 if (viewAncestor != null) { 11593 viewAncestor.dispatchDragEvent(event); 11594 } 11595 } 11596 11597 @Override dispatchWindowShown()11598 public void dispatchWindowShown() { 11599 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11600 if (viewAncestor != null) { 11601 viewAncestor.dispatchWindowShown(); 11602 } 11603 } 11604 11605 @Override requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId)11606 public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) { 11607 ViewRootImpl viewAncestor = mViewAncestor.get(); 11608 if (viewAncestor != null) { 11609 viewAncestor.dispatchRequestKeyboardShortcuts(receiver, deviceId); 11610 } 11611 } 11612 11613 @Override requestScrollCapture(IScrollCaptureResponseListener listener)11614 public void requestScrollCapture(IScrollCaptureResponseListener listener) { 11615 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11616 if (viewAncestor != null) { 11617 viewAncestor.dispatchScrollCaptureRequest(listener); 11618 } 11619 } 11620 11621 @Override dumpWindow(ParcelFileDescriptor pfd)11622 public void dumpWindow(ParcelFileDescriptor pfd) { 11623 final ViewRootImpl viewAncestor = mViewAncestor.get(); 11624 if (viewAncestor == null) { 11625 return; 11626 } 11627 viewAncestor.mHandler.postAtFrontOfQueue(() -> { 11628 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); 11629 try { 11630 PrintWriter pw = new FastPrintWriter(new FileOutputStream( 11631 pfd.getFileDescriptor())); 11632 viewAncestor.dump("", pw); 11633 pw.flush(); 11634 } finally { 11635 IoUtils.closeQuietly(pfd); 11636 StrictMode.setThreadPolicy(oldPolicy); 11637 } 11638 }); 11639 } 11640 } 11641 11642 public static final class CalledFromWrongThreadException extends AndroidRuntimeException { 11643 @UnsupportedAppUsage CalledFromWrongThreadException(String msg)11644 public CalledFromWrongThreadException(String msg) { 11645 super(msg); 11646 } 11647 } 11648 getRunQueue()11649 static HandlerActionQueue getRunQueue() { 11650 HandlerActionQueue rq = sRunQueues.get(); 11651 if (rq != null) { 11652 return rq; 11653 } 11654 rq = new HandlerActionQueue(); 11655 sRunQueues.set(rq); 11656 return rq; 11657 } 11658 11659 /** 11660 * Start a drag resizing which will inform all listeners that a window resize is taking place. 11661 */ startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets, Rect stableInsets)11662 private void startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets, 11663 Rect stableInsets) { 11664 if (!mDragResizing) { 11665 mDragResizing = true; 11666 if (mUseMTRenderer) { 11667 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { 11668 mWindowCallbacks.get(i).onWindowDragResizeStart( 11669 initialBounds, fullscreen, systemInsets, stableInsets); 11670 } 11671 } 11672 mFullRedrawNeeded = true; 11673 } 11674 } 11675 11676 /** 11677 * End a drag resize which will inform all listeners that a window resize has ended. 11678 */ endDragResizing()11679 private void endDragResizing() { 11680 if (mDragResizing) { 11681 mDragResizing = false; 11682 if (mUseMTRenderer) { 11683 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { 11684 mWindowCallbacks.get(i).onWindowDragResizeEnd(); 11685 } 11686 } 11687 mFullRedrawNeeded = true; 11688 } 11689 } 11690 updateContentDrawBounds()11691 private boolean updateContentDrawBounds() { 11692 boolean updated = false; 11693 if (mUseMTRenderer) { 11694 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { 11695 updated |= 11696 mWindowCallbacks.get(i).onContentDrawn(mWindowAttributes.surfaceInsets.left, 11697 mWindowAttributes.surfaceInsets.top, mWidth, mHeight); 11698 } 11699 } 11700 return updated | (mDragResizing && mReportNextDraw); 11701 } 11702 requestDrawWindow()11703 private void requestDrawWindow() { 11704 if (!mUseMTRenderer) { 11705 return; 11706 } 11707 // Only wait if it will report next draw. 11708 if (mReportNextDraw) { 11709 mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size()); 11710 } 11711 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { 11712 mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw); 11713 } 11714 } 11715 getSurfaceControl()11716 public SurfaceControl getSurfaceControl() { 11717 return mSurfaceControl; 11718 } 11719 11720 /** 11721 * @return Returns a token used to identify the windows input channel. 11722 */ getInputToken()11723 public IBinder getInputToken() { 11724 if (mInputEventReceiver == null) { 11725 return null; 11726 } 11727 return mInputEventReceiver.getToken(); 11728 } 11729 11730 /** 11731 * {@inheritDoc} 11732 */ 11733 @NonNull 11734 @Override getInputTransferToken()11735 public InputTransferToken getInputTransferToken() { 11736 IBinder inputToken = getInputToken(); 11737 if (inputToken == null) { 11738 throw new IllegalStateException( 11739 "Called getInputTransferToken for Window with no input channel"); 11740 } 11741 return new InputTransferToken(inputToken); 11742 } 11743 @NonNull getWindowToken()11744 public IBinder getWindowToken() { 11745 return mAttachInfo.mWindowToken; 11746 } 11747 11748 /** 11749 * Class for managing the accessibility interaction connection 11750 * based on the global accessibility state. 11751 */ 11752 final class AccessibilityInteractionConnectionManager 11753 implements AccessibilityStateChangeListener { 11754 private int mDirectConnectionId = AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID; 11755 11756 @Override onAccessibilityStateChanged(boolean enabled)11757 public void onAccessibilityStateChanged(boolean enabled) { 11758 if (enabled) { 11759 ensureConnection(); 11760 setAccessibilityWindowAttributesIfNeeded(); 11761 if (mAttachInfo.mHasWindowFocus && (mView != null)) { 11762 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 11763 View focusedView = mView.findFocus(); 11764 if (focusedView != null && focusedView != mView) { 11765 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 11766 } 11767 } 11768 if (mAttachInfo.mLeashedParentToken != null) { 11769 mAccessibilityManager.associateEmbeddedHierarchy( 11770 mAttachInfo.mLeashedParentToken, mLeashToken); 11771 } 11772 } else { 11773 ensureNoConnection(); 11774 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget(); 11775 } 11776 } 11777 ensureConnection()11778 public void ensureConnection() { 11779 final boolean registered = mAttachInfo.mAccessibilityWindowId 11780 != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 11781 if (!registered) { 11782 mAttachInfo.mAccessibilityWindowId = 11783 mAccessibilityManager.addAccessibilityInteractionConnection(mWindow, 11784 mLeashToken, 11785 mContext.getPackageName(), 11786 new AccessibilityInteractionConnection(ViewRootImpl.this)); 11787 } 11788 } 11789 ensureNoConnection()11790 public void ensureNoConnection() { 11791 final boolean registered = mAttachInfo.mAccessibilityWindowId 11792 != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 11793 if (registered) { 11794 mAttachInfo.mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 11795 mAccessibilityWindowAttributes = null; 11796 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow); 11797 } 11798 } 11799 ensureDirectConnection()11800 public int ensureDirectConnection() { 11801 if (mDirectConnectionId == AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID) { 11802 mDirectConnectionId = AccessibilityInteractionClient.addDirectConnection( 11803 new AccessibilityInteractionConnection(ViewRootImpl.this), 11804 mAccessibilityManager); 11805 // Notify listeners in the app process. 11806 mAccessibilityManager.notifyAccessibilityStateChanged(); 11807 } 11808 return mDirectConnectionId; 11809 } 11810 ensureNoDirectConnection()11811 public void ensureNoDirectConnection() { 11812 if (mDirectConnectionId != AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID) { 11813 AccessibilityInteractionClient.removeConnection(mDirectConnectionId); 11814 mDirectConnectionId = AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID; 11815 // Notify listeners in the app process. 11816 mAccessibilityManager.notifyAccessibilityStateChanged(); 11817 } 11818 } 11819 } 11820 11821 final class HighContrastTextManager implements HighTextContrastChangeListener { HighContrastTextManager()11822 HighContrastTextManager() { 11823 ThreadedRenderer.setHighContrastText(mAccessibilityManager.isHighTextContrastEnabled()); 11824 } 11825 @Override onHighTextContrastStateChanged(boolean enabled)11826 public void onHighTextContrastStateChanged(boolean enabled) { 11827 ThreadedRenderer.setHighContrastText(enabled); 11828 11829 // Destroy Displaylists so they can be recreated with high contrast recordings 11830 destroyHardwareResources(); 11831 11832 // Schedule redraw, which will rerecord + redraw all text 11833 invalidate(); 11834 } 11835 } 11836 11837 /** 11838 * This class is an interface this ViewAncestor provides to the 11839 * AccessibilityManagerService to the latter can interact with 11840 * the view hierarchy in this ViewAncestor. 11841 */ 11842 static final class AccessibilityInteractionConnection 11843 extends IAccessibilityInteractionConnection.Stub { 11844 private final WeakReference<ViewRootImpl> mViewRootImpl; 11845 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl)11846 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) { 11847 mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl); 11848 } 11849 11850 @Override findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix, Bundle args)11851 public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, 11852 Region interactiveRegion, int interactionId, 11853 IAccessibilityInteractionConnectionCallback callback, int flags, 11854 int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix, 11855 Bundle args) { 11856 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 11857 if (viewRootImpl != null && viewRootImpl.mView != null) { 11858 viewRootImpl.getAccessibilityInteractionController() 11859 .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId, 11860 interactiveRegion, interactionId, callback, flags, interrogatingPid, 11861 interrogatingTid, spec, matrix, args); 11862 } else { 11863 // We cannot make the call and notify the caller so it does not wait. 11864 try { 11865 callback.setFindAccessibilityNodeInfosResult(null, interactionId); 11866 } catch (RemoteException re) { 11867 /* best effort - ignore */ 11868 } 11869 } 11870 } 11871 11872 @Override performAccessibilityAction(long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid)11873 public void performAccessibilityAction(long accessibilityNodeId, int action, 11874 Bundle arguments, int interactionId, 11875 IAccessibilityInteractionConnectionCallback callback, int flags, 11876 int interrogatingPid, long interrogatingTid) { 11877 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 11878 if (viewRootImpl != null && viewRootImpl.mView != null) { 11879 viewRootImpl.getAccessibilityInteractionController() 11880 .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments, 11881 interactionId, callback, flags, interrogatingPid, interrogatingTid); 11882 } else { 11883 // We cannot make the call and notify the caller so it does not wait. 11884 try { 11885 callback.setPerformAccessibilityActionResult(false, interactionId); 11886 } catch (RemoteException re) { 11887 /* best effort - ignore */ 11888 } 11889 } 11890 } 11891 11892 @Override findAccessibilityNodeInfosByViewId(long accessibilityNodeId, String viewId, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix)11893 public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId, 11894 String viewId, Region interactiveRegion, int interactionId, 11895 IAccessibilityInteractionConnectionCallback callback, int flags, 11896 int interrogatingPid, long interrogatingTid, MagnificationSpec spec, 11897 float[] matrix) { 11898 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 11899 if (viewRootImpl != null && viewRootImpl.mView != null) { 11900 viewRootImpl.getAccessibilityInteractionController() 11901 .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId, 11902 viewId, interactiveRegion, interactionId, callback, flags, 11903 interrogatingPid, interrogatingTid, spec, matrix); 11904 } else { 11905 // We cannot make the call and notify the caller so it does not wait. 11906 try { 11907 callback.setFindAccessibilityNodeInfoResult(null, interactionId); 11908 } catch (RemoteException re) { 11909 /* best effort - ignore */ 11910 } 11911 } 11912 } 11913 11914 @Override findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix)11915 public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, 11916 Region interactiveRegion, int interactionId, 11917 IAccessibilityInteractionConnectionCallback callback, int flags, 11918 int interrogatingPid, long interrogatingTid, MagnificationSpec spec, 11919 float[] matrix) { 11920 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 11921 if (viewRootImpl != null && viewRootImpl.mView != null) { 11922 viewRootImpl.getAccessibilityInteractionController() 11923 .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text, 11924 interactiveRegion, interactionId, callback, flags, interrogatingPid, 11925 interrogatingTid, spec, matrix); 11926 } else { 11927 // We cannot make the call and notify the caller so it does not wait. 11928 try { 11929 callback.setFindAccessibilityNodeInfosResult(null, interactionId); 11930 } catch (RemoteException re) { 11931 /* best effort - ignore */ 11932 } 11933 } 11934 } 11935 11936 @Override findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix)11937 public void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion, 11938 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, 11939 int interrogatingPid, long interrogatingTid, MagnificationSpec spec, 11940 float[] matrix) { 11941 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 11942 if (viewRootImpl != null && viewRootImpl.mView != null) { 11943 viewRootImpl.getAccessibilityInteractionController() 11944 .findFocusClientThread(accessibilityNodeId, focusType, interactiveRegion, 11945 interactionId, callback, flags, interrogatingPid, interrogatingTid, 11946 spec, matrix); 11947 } else { 11948 // We cannot make the call and notify the caller so it does not wait. 11949 try { 11950 callback.setFindAccessibilityNodeInfoResult(null, interactionId); 11951 } catch (RemoteException re) { 11952 /* best effort - ignore */ 11953 } 11954 } 11955 } 11956 11957 @Override focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix)11958 public void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion, 11959 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, 11960 int interrogatingPid, long interrogatingTid, MagnificationSpec spec, 11961 float[] matrix) { 11962 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 11963 if (viewRootImpl != null && viewRootImpl.mView != null) { 11964 viewRootImpl.getAccessibilityInteractionController() 11965 .focusSearchClientThread(accessibilityNodeId, direction, interactiveRegion, 11966 interactionId, callback, flags, interrogatingPid, interrogatingTid, 11967 spec, matrix); 11968 } else { 11969 // We cannot make the call and notify the caller so it does not wait. 11970 try { 11971 callback.setFindAccessibilityNodeInfoResult(null, interactionId); 11972 } catch (RemoteException re) { 11973 /* best effort - ignore */ 11974 } 11975 } 11976 } 11977 11978 @Override clearAccessibilityFocus()11979 public void clearAccessibilityFocus() { 11980 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 11981 if (viewRootImpl != null && viewRootImpl.mView != null) { 11982 viewRootImpl.getAccessibilityInteractionController() 11983 .clearAccessibilityFocusClientThread(); 11984 } 11985 } 11986 11987 @Override notifyOutsideTouch()11988 public void notifyOutsideTouch() { 11989 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 11990 if (viewRootImpl != null && viewRootImpl.mView != null) { 11991 viewRootImpl.getAccessibilityInteractionController() 11992 .notifyOutsideTouchClientThread(); 11993 } 11994 } 11995 11996 @Override takeScreenshotOfWindow(int interactionId, ScreenCapture.ScreenCaptureListener listener, IAccessibilityInteractionConnectionCallback callback)11997 public void takeScreenshotOfWindow(int interactionId, 11998 ScreenCapture.ScreenCaptureListener listener, 11999 IAccessibilityInteractionConnectionCallback callback) { 12000 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 12001 if (viewRootImpl != null && viewRootImpl.mView != null) { 12002 viewRootImpl.getAccessibilityInteractionController() 12003 .takeScreenshotOfWindowClientThread(interactionId, listener, callback); 12004 } else { 12005 try { 12006 callback.sendTakeScreenshotOfWindowError( 12007 AccessibilityService.ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR, 12008 interactionId); 12009 } catch (RemoteException re) { 12010 /* best effort - ignore */ 12011 } 12012 } 12013 } 12014 attachAccessibilityOverlayToWindow( SurfaceControl sc, int interactionId, IAccessibilityInteractionConnectionCallback callback)12015 public void attachAccessibilityOverlayToWindow( 12016 SurfaceControl sc, 12017 int interactionId, 12018 IAccessibilityInteractionConnectionCallback callback) { 12019 ViewRootImpl viewRootImpl = mViewRootImpl.get(); 12020 if (viewRootImpl != null) { 12021 viewRootImpl 12022 .getAccessibilityInteractionController() 12023 .attachAccessibilityOverlayToWindowClientThread( 12024 sc, interactionId, callback); 12025 } 12026 } 12027 } 12028 12029 /** 12030 * Gets an accessibility embedded connection interface for this ViewRootImpl. 12031 * @hide 12032 */ getAccessibilityEmbeddedConnection()12033 public IAccessibilityEmbeddedConnection getAccessibilityEmbeddedConnection() { 12034 if (mAccessibilityEmbeddedConnection == null) { 12035 mAccessibilityEmbeddedConnection = new AccessibilityEmbeddedConnection( 12036 ViewRootImpl.this); 12037 } 12038 return mAccessibilityEmbeddedConnection; 12039 } 12040 12041 private class SendWindowContentChangedAccessibilityEvent implements Runnable { 12042 private int mChangeTypes = 0; 12043 12044 public View mSource; 12045 public long mLastEventTimeMillis; 12046 /** 12047 * Keep track of action that caused the event. 12048 * This is empty if there's no performing actions for pending events. 12049 * This is zero if there're multiple events performed for pending events. 12050 */ 12051 @NonNull public OptionalInt mAction = OptionalInt.empty(); 12052 /** 12053 * Override for {@link AccessibilityEvent#originStackTrace} to provide the stack trace 12054 * of the original {@link #runOrPost} call instead of one for sending the delayed event 12055 * from a looper. 12056 */ 12057 public StackTraceElement[] mOrigin; 12058 12059 @Override run()12060 public void run() { 12061 // Protect against re-entrant code and attempt to do the right thing in the case that 12062 // we're multithreaded. 12063 View source = mSource; 12064 mSource = null; 12065 if (source == null) { 12066 Log.e(TAG, "Accessibility content change has no source"); 12067 return; 12068 } 12069 // The accessibility may be turned off while we were waiting so check again. 12070 if (mAccessibilityManager.isEnabled()) { 12071 mLastEventTimeMillis = SystemClock.uptimeMillis(); 12072 AccessibilityEvent event = AccessibilityEvent.obtain(); 12073 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 12074 event.setContentChangeTypes(mChangeTypes); 12075 if (mAction.isPresent()) event.setAction(mAction.getAsInt()); 12076 if (AccessibilityEvent.DEBUG_ORIGIN) event.originStackTrace = mOrigin; 12077 source.sendAccessibilityEventUnchecked(event); 12078 } else { 12079 mLastEventTimeMillis = 0; 12080 } 12081 // In any case reset to initial state. 12082 source.resetSubtreeAccessibilityStateChanged(); 12083 mChangeTypes = 0; 12084 mAction = OptionalInt.empty(); 12085 if (AccessibilityEvent.DEBUG_ORIGIN) mOrigin = null; 12086 } 12087 runOrPost(View source, int changeType)12088 public void runOrPost(View source, int changeType) { 12089 if (mHandler.getLooper() != Looper.myLooper()) { 12090 CalledFromWrongThreadException e = new CalledFromWrongThreadException("Only the " 12091 + "original thread that created a view hierarchy can touch its views."); 12092 // TODO: Throw the exception 12093 Log.e(TAG, "Accessibility content change on non-UI thread. Future Android " 12094 + "versions will throw an exception.", e); 12095 // Attempt to recover. This code does not eliminate the thread safety issue, but 12096 // it should force any issues to happen near the above log. 12097 mHandler.removeCallbacks(this); 12098 if (mSource != null) { 12099 // Dispatch whatever was pending. It's still possible that the runnable started 12100 // just before we removed the callbacks, and bad things will happen, but at 12101 // least they should happen very close to the logged error. 12102 run(); 12103 } 12104 } 12105 12106 if (!canContinueThrottle(source, changeType)) { 12107 removeCallbacksAndRun(); 12108 } 12109 12110 if (mSource != null) { 12111 if (fixMergedContentChangeEventV2()) { 12112 View newSource = getCommonPredecessor(mSource, source); 12113 if (newSource != null) { 12114 newSource = newSource.getSelfOrParentImportantForA11y(); 12115 } 12116 if (newSource == null) { 12117 // If there is no common predecessor, then mSource points to 12118 // a removed view, hence in this case always prefer the source. 12119 newSource = source; 12120 } 12121 12122 mChangeTypes |= changeType; 12123 if (mSource != newSource) { 12124 mChangeTypes |= AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE; 12125 mSource = newSource; 12126 } 12127 } else { 12128 // If there is no common predecessor, then mSource points to 12129 // a removed view, hence in this case always prefer the source. 12130 View predecessor = getCommonPredecessor(mSource, source); 12131 if (predecessor != null) { 12132 predecessor = predecessor.getSelfOrParentImportantForA11y(); 12133 } 12134 mSource = (predecessor != null) ? predecessor : source; 12135 mChangeTypes |= changeType; 12136 } 12137 12138 final int performingAction = mAccessibilityManager.getPerformingAction(); 12139 if (performingAction != 0) { 12140 if (mAction.isEmpty()) { 12141 mAction = OptionalInt.of(performingAction); 12142 } else if (mAction.getAsInt() != performingAction) { 12143 // Multiple actions are performed for pending events. We cannot decide one 12144 // action here. 12145 // We're doing best effort to set action value, and it's fine to set 12146 // no action this case. 12147 mAction = OptionalInt.of(0); 12148 } 12149 } 12150 12151 return; 12152 } 12153 mSource = source; 12154 mChangeTypes = changeType; 12155 if (mAccessibilityManager.getPerformingAction() != 0) { 12156 mAction = OptionalInt.of(mAccessibilityManager.getPerformingAction()); 12157 } 12158 if (AccessibilityEvent.DEBUG_ORIGIN) { 12159 mOrigin = Thread.currentThread().getStackTrace(); 12160 } 12161 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis; 12162 final long minEventIntervalMillis = 12163 ViewConfiguration.getSendRecurringAccessibilityEventsInterval(); 12164 if (timeSinceLastMillis >= minEventIntervalMillis) { 12165 removeCallbacksAndRun(); 12166 } else { 12167 mHandler.postDelayed(this, minEventIntervalMillis - timeSinceLastMillis); 12168 } 12169 } 12170 removeCallbacksAndRun()12171 public void removeCallbacksAndRun() { 12172 mHandler.removeCallbacks(this); 12173 run(); 12174 } 12175 canContinueThrottle(View source, int changeType)12176 private boolean canContinueThrottle(View source, int changeType) { 12177 if (!reduceWindowContentChangedEventThrottle()) { 12178 // Old behavior. Always throttle. 12179 return true; 12180 } 12181 if (mSource == null) { 12182 // We don't have a pending event. 12183 return true; 12184 } 12185 if (mSource == source) { 12186 // We can merge a new event with a pending event from the same source. 12187 return true; 12188 } 12189 // We can merge subtree change events. 12190 return changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE 12191 && mChangeTypes == AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE; 12192 } 12193 } 12194 12195 private static class UnhandledKeyManager { 12196 // This is used to ensure that unhandled events are only dispatched once. We attempt 12197 // to dispatch more than once in order to achieve a certain order. Specifically, if we 12198 // are in an Activity or Dialog (and have a Window.Callback), the unhandled events should 12199 // be dispatched after the view hierarchy, but before the Callback. However, if we aren't 12200 // in an activity, we still want unhandled keys to be dispatched. 12201 private boolean mDispatched = true; 12202 12203 // Keeps track of which Views have unhandled key focus for which keys. This doesn't 12204 // include modifiers. 12205 private final SparseArray<WeakReference<View>> mCapturedKeys = new SparseArray<>(); 12206 12207 // The current receiver. This value is transient and used between the pre-dispatch and 12208 // pre-view phase to ensure that other input-stages don't interfere with tracking. 12209 private WeakReference<View> mCurrentReceiver = null; 12210 dispatch(View root, KeyEvent event)12211 boolean dispatch(View root, KeyEvent event) { 12212 if (mDispatched) { 12213 return false; 12214 } 12215 View consumer; 12216 try { 12217 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "UnhandledKeyEvent dispatch"); 12218 mDispatched = true; 12219 12220 consumer = root.dispatchUnhandledKeyEvent(event); 12221 12222 // If an unhandled listener handles one, then keep track of it so that the 12223 // consuming view is first to receive its repeats and release as well. 12224 if (event.getAction() == KeyEvent.ACTION_DOWN) { 12225 int keycode = event.getKeyCode(); 12226 if (consumer != null && !KeyEvent.isModifierKey(keycode)) { 12227 mCapturedKeys.put(keycode, new WeakReference<>(consumer)); 12228 } 12229 } 12230 } finally { 12231 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 12232 } 12233 return consumer != null; 12234 } 12235 12236 /** 12237 * Called before the event gets dispatched to anything 12238 */ preDispatch(KeyEvent event)12239 void preDispatch(KeyEvent event) { 12240 // Always clean-up 'up' events since it's possible for earlier dispatch stages to 12241 // consume them without consuming the corresponding 'down' event. 12242 mCurrentReceiver = null; 12243 if (event.getAction() == KeyEvent.ACTION_UP) { 12244 int idx = mCapturedKeys.indexOfKey(event.getKeyCode()); 12245 if (idx >= 0) { 12246 mCurrentReceiver = mCapturedKeys.valueAt(idx); 12247 mCapturedKeys.removeAt(idx); 12248 } 12249 } 12250 } 12251 12252 /** 12253 * Called before the event gets dispatched to the view hierarchy 12254 * @return {@code true} if an unhandled handler has focus and consumed the event 12255 */ preViewDispatch(KeyEvent event)12256 boolean preViewDispatch(KeyEvent event) { 12257 mDispatched = false; 12258 if (mCurrentReceiver == null) { 12259 mCurrentReceiver = mCapturedKeys.get(event.getKeyCode()); 12260 } 12261 if (mCurrentReceiver != null) { 12262 View target = mCurrentReceiver.get(); 12263 if (event.getAction() == KeyEvent.ACTION_UP) { 12264 mCurrentReceiver = null; 12265 } 12266 if (target != null && target.isAttachedToWindow()) { 12267 target.onUnhandledKeyEvent(event); 12268 } 12269 // consume anyways so that we don't feed uncaptured key events to other views 12270 return true; 12271 } 12272 return false; 12273 } 12274 } 12275 12276 /** 12277 * @hide 12278 */ setDisplayDecoration(boolean displayDecoration)12279 public void setDisplayDecoration(boolean displayDecoration) { 12280 if (displayDecoration == mDisplayDecorationCached) return; 12281 12282 mDisplayDecorationCached = displayDecoration; 12283 12284 if (mSurfaceControl.isValid()) { 12285 updateDisplayDecoration(); 12286 } 12287 } 12288 updateDisplayDecoration()12289 private void updateDisplayDecoration() { 12290 mTransaction.setDisplayDecoration(mSurfaceControl, mDisplayDecorationCached).apply(); 12291 } 12292 12293 /** 12294 * Sends a list of blur regions to SurfaceFlinger, tagged with a frame. 12295 * 12296 * @param regionCopy List of regions 12297 * @param frameNumber Frame where it should be applied (or current when using BLAST) 12298 */ dispatchBlurRegions(float[][] regionCopy, long frameNumber)12299 public void dispatchBlurRegions(float[][] regionCopy, long frameNumber) { 12300 final SurfaceControl surfaceControl = getSurfaceControl(); 12301 if (!surfaceControl.isValid()) { 12302 return; 12303 } 12304 12305 SurfaceControl.Transaction transaction = new SurfaceControl.Transaction(); 12306 transaction.setBlurRegions(surfaceControl, regionCopy); 12307 12308 if (mBlastBufferQueue != null) { 12309 mBlastBufferQueue.mergeWithNextTransaction(transaction, frameNumber); 12310 } 12311 } 12312 12313 /** 12314 * Creates a background blur drawable for the backing {@link Surface}. 12315 */ createBackgroundBlurDrawable()12316 public BackgroundBlurDrawable createBackgroundBlurDrawable() { 12317 return mBlurRegionAggregator.createBackgroundBlurDrawable(mContext); 12318 } 12319 12320 @Override onDescendantUnbufferedRequested()12321 public void onDescendantUnbufferedRequested() { 12322 mUnbufferedInputSource = mView.mUnbufferedInputSource; 12323 } 12324 getSurfaceSequenceId()12325 int getSurfaceSequenceId() { 12326 return mSurfaceSequenceId; 12327 } 12328 12329 /** 12330 * Merges the transaction passed in with the next transaction in BLASTBufferQueue. This ensures 12331 * you can add transactions to the upcoming frame. 12332 */ mergeWithNextTransaction(Transaction t, long frameNumber)12333 public void mergeWithNextTransaction(Transaction t, long frameNumber) { 12334 if (mBlastBufferQueue != null) { 12335 mBlastBufferQueue.mergeWithNextTransaction(t, frameNumber); 12336 } else { 12337 t.apply(); 12338 } 12339 } 12340 12341 @Override buildReparentTransaction( @onNull SurfaceControl child)12342 @Nullable public SurfaceControl.Transaction buildReparentTransaction( 12343 @NonNull SurfaceControl child) { 12344 if (mSurfaceControl.isValid()) { 12345 Transaction t = new Transaction(); 12346 return t.reparent(child, updateAndGetBoundsLayer(t)); 12347 } 12348 return null; 12349 } 12350 12351 @Override applyTransactionOnDraw(@onNull SurfaceControl.Transaction t)12352 public boolean applyTransactionOnDraw(@NonNull SurfaceControl.Transaction t) { 12353 if (mRemoved || !isHardwareEnabled()) { 12354 logAndTrace("applyTransactionOnDraw applyImmediately"); 12355 t.apply(); 12356 } else { 12357 Trace.instant(Trace.TRACE_TAG_VIEW, "applyTransactionOnDraw-" + mTag); 12358 // Copy and clear the passed in transaction for thread safety. The new transaction is 12359 // accessed on the render thread. 12360 mPendingTransaction.merge(t); 12361 mHasPendingTransactions = true; 12362 } 12363 return true; 12364 } 12365 12366 @Override getBufferTransformHint()12367 public @SurfaceControl.BufferTransform int getBufferTransformHint() { 12368 // TODO(b/326482114) We use mPreviousTransformHint (calculated using mDisplay's rotation) 12369 // instead of mSurfaceControl#getTransformHint because there's a race where SurfaceFlinger 12370 // can set an incorrect transform hint for a few frames before it is aware of the updated 12371 // display rotation. 12372 if (enableBufferTransformHintFromDisplay()) { 12373 return mPreviousTransformHint; 12374 } 12375 12376 if (mSurfaceControl.isValid()) { 12377 return mSurfaceControl.getTransformHint(); 12378 } else { 12379 return SurfaceControl.BUFFER_TRANSFORM_IDENTITY; 12380 } 12381 } 12382 12383 @Override addOnBufferTransformHintChangedListener( OnBufferTransformHintChangedListener listener)12384 public void addOnBufferTransformHintChangedListener( 12385 OnBufferTransformHintChangedListener listener) { 12386 Objects.requireNonNull(listener); 12387 if (mTransformHintListeners.contains(listener)) { 12388 throw new IllegalArgumentException( 12389 "attempt to call addOnBufferTransformHintChangedListener() " 12390 + "with a previously registered listener"); 12391 } 12392 mTransformHintListeners.add(listener); 12393 } 12394 12395 @Override removeOnBufferTransformHintChangedListener( OnBufferTransformHintChangedListener listener)12396 public void removeOnBufferTransformHintChangedListener( 12397 OnBufferTransformHintChangedListener listener) { 12398 Objects.requireNonNull(listener); 12399 mTransformHintListeners.remove(listener); 12400 } 12401 dispatchTransformHintChanged(@urfaceControl.BufferTransform int hint)12402 private void dispatchTransformHintChanged(@SurfaceControl.BufferTransform int hint) { 12403 if (mTransformHintListeners.isEmpty()) { 12404 return; 12405 } 12406 ArrayList<OnBufferTransformHintChangedListener> listeners = 12407 (ArrayList<OnBufferTransformHintChangedListener>) mTransformHintListeners.clone(); 12408 for (int i = 0; i < listeners.size(); i++) { 12409 OnBufferTransformHintChangedListener listener = listeners.get(i); 12410 listener.onBufferTransformHintChanged(hint); 12411 } 12412 } 12413 12414 /** 12415 * Shows or hides a Camera app compat toggle for stretched issues with the requested state 12416 * for the corresponding activity. 12417 * 12418 * @param showControl Whether the control should be shown or hidden. 12419 * @param transformationApplied Whether the treatment is already applied. 12420 * @param callback The callback executed when the user clicks on a control. 12421 */ requestCompatCameraControl(boolean showControl, boolean transformationApplied, ICompatCameraControlCallback callback)12422 public void requestCompatCameraControl(boolean showControl, boolean transformationApplied, 12423 ICompatCameraControlCallback callback) { 12424 mActivityConfigCallback.requestCompatCameraControl( 12425 showControl, transformationApplied, callback); 12426 } 12427 wasRelayoutRequested()12428 boolean wasRelayoutRequested() { 12429 return mRelayoutRequested; 12430 } 12431 forceWmRelayout()12432 void forceWmRelayout() { 12433 mForceNextWindowRelayout = true; 12434 scheduleTraversals(); 12435 } 12436 12437 /** 12438 * Returns the {@link OnBackInvokedDispatcher} on the decor view if one exists, or the 12439 * fallback {@link OnBackInvokedDispatcher} instance. 12440 */ 12441 @NonNull getOnBackInvokedDispatcher()12442 public WindowOnBackInvokedDispatcher getOnBackInvokedDispatcher() { 12443 return mOnBackInvokedDispatcher; 12444 } 12445 12446 @NonNull 12447 @Override findOnBackInvokedDispatcherForChild( @onNull View child, @NonNull View requester)12448 public OnBackInvokedDispatcher findOnBackInvokedDispatcherForChild( 12449 @NonNull View child, @NonNull View requester) { 12450 return getOnBackInvokedDispatcher(); 12451 } 12452 12453 /** 12454 * When this ViewRootImpl is added to the window manager, transfers the first 12455 * {@link OnBackInvokedCallback} to be called to the server. 12456 */ registerBackCallbackOnWindow()12457 private void registerBackCallbackOnWindow() { 12458 if (OnBackInvokedDispatcher.DEBUG) { 12459 Log.d(OnBackInvokedDispatcher.TAG, TextUtils.formatSimple( 12460 "ViewRootImpl.registerBackCallbackOnWindow. Dispatcher:%s Package:%s " 12461 + "IWindow:%s Session:%s", 12462 mOnBackInvokedDispatcher, mBasePackageName, mWindow, mWindowSession)); 12463 } 12464 mOnBackInvokedDispatcher.attachToWindow(mWindowSession, mWindow, 12465 mImeBackAnimationController); 12466 } 12467 sendBackKeyEvent(int action)12468 private void sendBackKeyEvent(int action) { 12469 long when = SystemClock.uptimeMillis(); 12470 final KeyEvent ev = new KeyEvent(when, when, action, 12471 KeyEvent.KEYCODE_BACK, 0 /* repeat */, 0 /* metaState */, 12472 KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */, 12473 KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY, 12474 InputDevice.SOURCE_KEYBOARD); 12475 enqueueInputEvent(ev, null /* receiver */, 0 /* flags */, true /* processImmediately */); 12476 } 12477 registerCompatOnBackInvokedCallback()12478 private void registerCompatOnBackInvokedCallback() { 12479 mCompatOnBackInvokedCallback = () -> { 12480 try { 12481 processingBackKey(true); 12482 sendBackKeyEvent(KeyEvent.ACTION_DOWN); 12483 sendBackKeyEvent(KeyEvent.ACTION_UP); 12484 } finally { 12485 processingBackKey(false); 12486 } 12487 }; 12488 if (mOnBackInvokedDispatcher.hasImeOnBackInvokedDispatcher()) { 12489 Log.d(TAG, "Skip registering CompatOnBackInvokedCallback on IME dispatcher"); 12490 return; 12491 } 12492 mOnBackInvokedDispatcher.registerOnBackInvokedCallback( 12493 OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCompatOnBackInvokedCallback); 12494 } 12495 12496 @Override setTouchableRegion(Region r)12497 public void setTouchableRegion(Region r) { 12498 if (r != null) { 12499 mTouchableRegion = new Region(r); 12500 } else { 12501 mTouchableRegion = null; 12502 } 12503 mLastGivenInsets.reset(); 12504 requestLayout(); 12505 } 12506 getWindowSession()12507 IWindowSession getWindowSession() { 12508 return mWindowSession; 12509 } 12510 registerCallbacksForSync(boolean syncBuffer, final SurfaceSyncGroup surfaceSyncGroup)12511 private void registerCallbacksForSync(boolean syncBuffer, 12512 final SurfaceSyncGroup surfaceSyncGroup) { 12513 if (!isHardwareEnabled()) { 12514 return; 12515 } 12516 12517 if (DEBUG_BLAST) { 12518 Log.d(mTag, "registerCallbacksForSync syncBuffer=" + syncBuffer); 12519 } 12520 12521 final Transaction t; 12522 if (mHasPendingTransactions) { 12523 t = new Transaction(); 12524 t.merge(mPendingTransaction); 12525 } else { 12526 t = null; 12527 } 12528 12529 mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() { 12530 @Override 12531 public void onFrameDraw(long frame) { 12532 } 12533 12534 @Override 12535 public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) { 12536 if (DEBUG_BLAST) { 12537 Log.d(mTag, 12538 "Received frameDrawingCallback syncResult=" + syncResult + " frameNum=" 12539 + frame + "."); 12540 } 12541 if (t != null) { 12542 mergeWithNextTransaction(t, frame); 12543 } 12544 12545 // If the syncResults are SYNC_LOST_SURFACE_REWARD_IF_FOUND or 12546 // SYNC_CONTEXT_IS_STOPPED it means nothing will draw. There's no need to set up 12547 // any blast sync or commit callback, and the code should directly call 12548 // pendingDrawFinished. 12549 if ((syncResult 12550 & (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) { 12551 surfaceSyncGroup.addTransaction( 12552 mBlastBufferQueue.gatherPendingTransactions(frame)); 12553 surfaceSyncGroup.markSyncReady(); 12554 return null; 12555 } 12556 12557 if (DEBUG_BLAST) { 12558 Log.d(mTag, "Setting up sync and frameCommitCallback"); 12559 } 12560 12561 if (syncBuffer) { 12562 boolean result = mBlastBufferQueue.syncNextTransaction(transaction -> { 12563 Runnable timeoutRunnable = () -> Log.e(mTag, 12564 "Failed to submit the sync transaction after 4s. Likely to ANR " 12565 + "soon"); 12566 mHandler.postDelayed(timeoutRunnable, 4000L * Build.HW_TIMEOUT_MULTIPLIER); 12567 transaction.addTransactionCommittedListener(mSimpleExecutor, 12568 () -> mHandler.removeCallbacks(timeoutRunnable)); 12569 surfaceSyncGroup.addTransaction(transaction); 12570 surfaceSyncGroup.markSyncReady(); 12571 }); 12572 if (!result) { 12573 // syncNextTransaction can only return false if something is already trying 12574 // to sync the same frame in the same BBQ. That shouldn't be possible, but 12575 // if it did happen, invoke markSyncReady so the active SSG doesn't get 12576 // stuck. 12577 Log.w(mTag, "Unable to syncNextTransaction. Possibly something else is" 12578 + " trying to sync?"); 12579 surfaceSyncGroup.markSyncReady(); 12580 } 12581 } 12582 12583 return didProduceBuffer -> { 12584 if (DEBUG_BLAST) { 12585 Log.d(mTag, "Received frameCommittedCallback" 12586 + " lastAttemptedDrawFrameNum=" + frame 12587 + " didProduceBuffer=" + didProduceBuffer); 12588 } 12589 12590 // If frame wasn't drawn, clear out the next transaction so it doesn't affect 12591 // the next draw attempt. The next transaction and transaction complete callback 12592 // were only set for the current draw attempt. 12593 if (!didProduceBuffer) { 12594 mBlastBufferQueue.clearSyncTransaction(); 12595 12596 // Gather the transactions that were sent to mergeWithNextTransaction 12597 // since the frame didn't draw on this vsync. It's possible the frame will 12598 // draw later, but it's better to not be sync than to block on a frame that 12599 // may never come. 12600 surfaceSyncGroup.addTransaction( 12601 mBlastBufferQueue.gatherPendingTransactions(frame)); 12602 surfaceSyncGroup.markSyncReady(); 12603 return; 12604 } 12605 12606 // If we didn't request to sync a buffer, then we won't get the 12607 // syncNextTransaction callback. Instead, just report back to the Syncer so it 12608 // knows that this sync request is complete. 12609 if (!syncBuffer) { 12610 surfaceSyncGroup.markSyncReady(); 12611 } 12612 }; 12613 } 12614 }); 12615 } 12616 12617 /** 12618 * This code will ensure that if multiple SurfaceSyncGroups are created for the same 12619 * ViewRootImpl the SurfaceSyncGroups will maintain an order. The scenario that could occur 12620 * is the following: 12621 * <p> 12622 * 1. SSG1 is created that includes the target VRI. There could be other VRIs in SSG1 12623 * 2. The target VRI draws its frame and marks its own active SSG as ready, but SSG1 is still 12624 * waiting on other things in the SSG 12625 * 3. Another SSG2 is created for the target VRI. The second frame renders and marks its own 12626 * second SSG as complete. SSG2 has nothing else to wait on, so it will apply at this point, 12627 * even though SSG1 has not finished. 12628 * 4. Frame2 will get to SF first and Frame1 will later get to SF when SSG1 completes. 12629 * <p> 12630 * The code below ensures the SSGs that contains the VRI maintain an order. We create a new SSG 12631 * that's a safeguard SSG. Its only job is to prevent the next active SSG from completing. 12632 * The current active SSG for VRI will add a transaction committed callback and when that's 12633 * invoked, it will mark the safeguard SSG as ready. If a new request to create a SSG comes 12634 * in and the safeguard SSG is not null, it's added as part of the new active SSG. A new 12635 * safeguard SSG is created to correspond to the new active SSG. This creates a chain to 12636 * ensure the latter SSG always waits for the former SSG's transaction to get to SF. 12637 */ safeguardOverlappingSyncs(SurfaceSyncGroup activeSurfaceSyncGroup)12638 private void safeguardOverlappingSyncs(SurfaceSyncGroup activeSurfaceSyncGroup) { 12639 SurfaceSyncGroup safeguardSsg = new SurfaceSyncGroup("Safeguard-" + mTag); 12640 // Always disable timeout on the safeguard sync 12641 safeguardSsg.toggleTimeout(false /* enable */); 12642 synchronized (mPreviousSyncSafeguardLock) { 12643 if (mPreviousSyncSafeguard != null) { 12644 activeSurfaceSyncGroup.add(mPreviousSyncSafeguard, null /* runnable */); 12645 // Temporarily disable the timeout on the SSG that will contain the buffer. This 12646 // is to ensure we don't timeout the active SSG before the previous one completes to 12647 // ensure the order is maintained. The previous SSG has a timeout on its own SSG 12648 // so it's guaranteed to complete. 12649 activeSurfaceSyncGroup.toggleTimeout(false /* enable */); 12650 mPreviousSyncSafeguard.addSyncCompleteCallback(mSimpleExecutor, () -> { 12651 // Once we receive that the previous sync guard has been invoked, we can re-add 12652 // the timeout on the active sync to ensure we eventually complete so it's not 12653 // stuck permanently. 12654 activeSurfaceSyncGroup.toggleTimeout(true /*enable */); 12655 }); 12656 } 12657 mPreviousSyncSafeguard = safeguardSsg; 12658 } 12659 12660 Transaction t = new Transaction(); 12661 t.addTransactionCommittedListener(mSimpleExecutor, () -> { 12662 safeguardSsg.markSyncReady(); 12663 synchronized (mPreviousSyncSafeguardLock) { 12664 if (mPreviousSyncSafeguard == safeguardSsg) { 12665 mPreviousSyncSafeguard = null; 12666 } 12667 } 12668 }); 12669 activeSurfaceSyncGroup.addTransaction(t); 12670 } 12671 12672 @Override getOrCreateSurfaceSyncGroup()12673 public SurfaceSyncGroup getOrCreateSurfaceSyncGroup() { 12674 boolean newSyncGroup = false; 12675 if (mActiveSurfaceSyncGroup == null) { 12676 mActiveSurfaceSyncGroup = new SurfaceSyncGroup(mTag); 12677 mActiveSurfaceSyncGroup.setAddedToSyncListener(() -> { 12678 Runnable runnable = () -> { 12679 // Check if it's already 0 because the timeout could have reset the count to 12680 // 0 and we don't want to go negative. 12681 if (mNumPausedForSync > 0) { 12682 mNumPausedForSync--; 12683 } 12684 if (mNumPausedForSync == 0) { 12685 mHandler.removeMessages(MSG_PAUSED_FOR_SYNC_TIMEOUT); 12686 if (!mIsInTraversal) { 12687 scheduleTraversals(); 12688 } 12689 } 12690 }; 12691 12692 if (Thread.currentThread() == mThread) { 12693 runnable.run(); 12694 } else { 12695 mHandler.post(runnable); 12696 } 12697 }); 12698 newSyncGroup = true; 12699 } 12700 12701 Trace.instant(Trace.TRACE_TAG_VIEW, 12702 "getOrCreateSurfaceSyncGroup isNew=" + newSyncGroup + " " + mTag); 12703 12704 if (DEBUG_BLAST) { 12705 if (newSyncGroup) { 12706 Log.d(mTag, "Creating new active sync group " + mActiveSurfaceSyncGroup.getName()); 12707 } else { 12708 Log.d(mTag, "Return already created active sync group " 12709 + mActiveSurfaceSyncGroup.getName()); 12710 } 12711 } 12712 12713 mNumPausedForSync++; 12714 mHandler.removeMessages(MSG_PAUSED_FOR_SYNC_TIMEOUT); 12715 mHandler.sendEmptyMessageDelayed(MSG_PAUSED_FOR_SYNC_TIMEOUT, 12716 1000 * Build.HW_TIMEOUT_MULTIPLIER); 12717 return mActiveSurfaceSyncGroup; 12718 }; 12719 12720 private final Executor mSimpleExecutor = Runnable::run; 12721 updateSyncInProgressCount(SurfaceSyncGroup syncGroup)12722 private void updateSyncInProgressCount(SurfaceSyncGroup syncGroup) { 12723 if (mAttachInfo.mThreadedRenderer == null) { 12724 return; 12725 } 12726 12727 synchronized (sSyncProgressLock) { 12728 if (sNumSyncsInProgress++ == 0) { 12729 HardwareRenderer.setRtAnimationsEnabled(false); 12730 } 12731 } 12732 12733 syncGroup.addSyncCompleteCallback(mSimpleExecutor, () -> { 12734 synchronized (sSyncProgressLock) { 12735 if (--sNumSyncsInProgress == 0) { 12736 HardwareRenderer.setRtAnimationsEnabled(true); 12737 } 12738 } 12739 }); 12740 } 12741 addToSync(SurfaceSyncGroup syncable)12742 void addToSync(SurfaceSyncGroup syncable) { 12743 if (mActiveSurfaceSyncGroup == null) { 12744 return; 12745 } 12746 mActiveSurfaceSyncGroup.add(syncable, null /* Runnable */); 12747 } 12748 12749 @Override setChildBoundingInsets(@onNull Rect insets)12750 public void setChildBoundingInsets(@NonNull Rect insets) { 12751 if (insets.left < 0 || insets.top < 0 || insets.right < 0 || insets.bottom < 0) { 12752 throw new IllegalArgumentException("Negative insets passed to setChildBoundingInsets."); 12753 } 12754 mChildBoundingInsets.set(insets); 12755 mChildBoundingInsetsChanged = true; 12756 scheduleTraversals(); 12757 } 12758 12759 logAndTrace(String msg)12760 private void logAndTrace(String msg) { 12761 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 12762 Trace.instant(Trace.TRACE_TAG_VIEW, mTag + "-" + msg); 12763 } 12764 if (DEBUG_BLAST) { 12765 Log.d(mTag, msg); 12766 } 12767 EventLog.writeEvent(LOGTAG_VIEWROOT_DRAW_EVENT, mTag, msg); 12768 } 12769 12770 /** 12771 * Views that are animating with the ThreadedRenderer don't use the normal invalidation 12772 * path, so the value won't be updated through performTraversals. This reads the votes 12773 * from those views. 12774 */ updateFrameRateFromThreadedRendererViews()12775 private void updateFrameRateFromThreadedRendererViews() { 12776 ArrayList<View> views = mThreadedRendererViews; 12777 for (int i = views.size() - 1; i >= 0; i--) { 12778 View view = views.get(i); 12779 View.AttachInfo attachInfo = view.mAttachInfo; 12780 if (attachInfo == null || attachInfo.mViewRootImpl != this) { 12781 views.remove(i); 12782 } else { 12783 view.votePreferredFrameRate(); 12784 } 12785 } 12786 } 12787 12788 /** 12789 * Sets the mPreferredFrameRateCategory from the high, high_hint, normal, and low counts. 12790 */ setCategoryFromCategoryCounts()12791 private void setCategoryFromCategoryCounts() { 12792 switch (mPreferredFrameRateCategory) { 12793 case FRAME_RATE_CATEGORY_LOW -> mFrameRateCategoryLowCount = FRAME_RATE_CATEGORY_COUNT; 12794 case FRAME_RATE_CATEGORY_NORMAL -> 12795 mFrameRateCategoryNormalCount = FRAME_RATE_CATEGORY_COUNT; 12796 case FRAME_RATE_CATEGORY_HIGH_HINT -> 12797 mFrameRateCategoryHighHintCount = FRAME_RATE_CATEGORY_COUNT; 12798 case FRAME_RATE_CATEGORY_HIGH -> 12799 mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT; 12800 } 12801 12802 // If it's currently an intermittent update, 12803 // we should keep mPreferredFrameRateCategory as NORMAL 12804 if (intermittentUpdateState() == INTERMITTENT_STATE_INTERMITTENT) { 12805 return; 12806 } 12807 12808 if (mFrameRateCategoryHighCount > 0) { 12809 mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH; 12810 } else if (mFrameRateCategoryHighHintCount > 0) { 12811 mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH_HINT; 12812 } else if (mFrameRateCategoryNormalCount > 0) { 12813 mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NORMAL; 12814 } else if (mFrameRateCategoryLowCount > 0) { 12815 mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_LOW; 12816 } 12817 } 12818 setPreferredFrameRateCategory(int preferredFrameRateCategory)12819 private void setPreferredFrameRateCategory(int preferredFrameRateCategory) { 12820 if (!shouldSetFrameRateCategory()) { 12821 return; 12822 } 12823 12824 int frameRateCategory; 12825 int frameRateReason; 12826 String view; 12827 12828 if (mIsFrameRateBoosting || mInsetsAnimationRunning) { 12829 frameRateCategory = FRAME_RATE_CATEGORY_HIGH; 12830 frameRateReason = FRAME_RATE_CATEGORY_REASON_BOOST; 12831 view = null; 12832 } else if (mIsTouchBoosting && preferredFrameRateCategory < FRAME_RATE_CATEGORY_HIGH_HINT) { 12833 frameRateCategory = FRAME_RATE_CATEGORY_HIGH_HINT; 12834 frameRateReason = FRAME_RATE_CATEGORY_REASON_TOUCH; 12835 view = null; 12836 } else { 12837 frameRateCategory = preferredFrameRateCategory; 12838 frameRateReason = mFrameRateCategoryChangeReason; 12839 view = mFrameRateCategoryView; 12840 } 12841 12842 boolean traceFrameRateCategory = false; 12843 try { 12844 if (frameRateCategory != FRAME_RATE_CATEGORY_DEFAULT 12845 && mLastPreferredFrameRateCategory != frameRateCategory) { 12846 traceFrameRateCategory = Trace.isTagEnabled(Trace.TRACE_TAG_VIEW); 12847 if (traceFrameRateCategory) { 12848 String reason = reasonToString(frameRateReason); 12849 String sourceView = view == null ? "-" : view; 12850 String category = categoryToString(frameRateCategory); 12851 Trace.traceBegin( 12852 Trace.TRACE_TAG_VIEW, "ViewRootImpl#setFrameRateCategory " 12853 + category + ", reason " + reason + ", " 12854 + sourceView); 12855 } 12856 if (sToolkitFrameRateFunctionEnablingReadOnlyFlagValue) { 12857 mFrameRateTransaction.setFrameRateCategory(mSurfaceControl, 12858 frameRateCategory, false).applyAsyncUnsafe(); 12859 } 12860 mLastPreferredFrameRateCategory = frameRateCategory; 12861 } 12862 } catch (Exception e) { 12863 Log.e(mTag, "Unable to set frame rate category", e); 12864 } finally { 12865 if (traceFrameRateCategory) { 12866 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 12867 } 12868 } 12869 } 12870 categoryToString(int frameRateCategory)12871 private static String categoryToString(int frameRateCategory) { 12872 String category; 12873 switch (frameRateCategory) { 12874 case FRAME_RATE_CATEGORY_NO_PREFERENCE -> category = "no preference"; 12875 case FRAME_RATE_CATEGORY_LOW -> category = "low"; 12876 case FRAME_RATE_CATEGORY_NORMAL -> category = "normal"; 12877 case FRAME_RATE_CATEGORY_HIGH_HINT -> category = "high hint"; 12878 case FRAME_RATE_CATEGORY_HIGH -> category = "high"; 12879 default -> category = "default"; 12880 } 12881 return category; 12882 } 12883 reasonToString(int reason)12884 private static String reasonToString(int reason) { 12885 String str; 12886 switch (reason) { 12887 case FRAME_RATE_CATEGORY_REASON_INTERMITTENT -> str = "intermittent"; 12888 case FRAME_RATE_CATEGORY_REASON_SMALL -> str = "small"; 12889 case FRAME_RATE_CATEGORY_REASON_LARGE -> str = "large"; 12890 case FRAME_RATE_CATEGORY_REASON_REQUESTED -> str = "requested"; 12891 case FRAME_RATE_CATEGORY_REASON_INVALID -> str = "invalid frame rate"; 12892 case FRAME_RATE_CATEGORY_REASON_VELOCITY -> str = "velocity"; 12893 case FRAME_RATE_CATEGORY_REASON_UNKNOWN -> str = "unknown"; 12894 case FRAME_RATE_CATEGORY_REASON_BOOST -> str = "boost"; 12895 case FRAME_RATE_CATEGORY_REASON_TOUCH -> str = "touch"; 12896 case FRAME_RATE_CATEGORY_REASON_CONFLICTED -> str = "conflicted"; 12897 default -> str = String.valueOf(reason); 12898 } 12899 return str; 12900 } 12901 setPreferredFrameRate(float preferredFrameRate)12902 private void setPreferredFrameRate(float preferredFrameRate) { 12903 if (!shouldSetFrameRate() || preferredFrameRate < 0) { 12904 return; 12905 } 12906 12907 boolean traceFrameRate = false; 12908 try { 12909 if (mLastPreferredFrameRate != preferredFrameRate) { 12910 traceFrameRate = Trace.isTagEnabled(Trace.TRACE_TAG_VIEW); 12911 if (traceFrameRate) { 12912 Trace.traceBegin( 12913 Trace.TRACE_TAG_VIEW, "ViewRootImpl#setFrameRate " 12914 + preferredFrameRate + " compatibility " 12915 + mFrameRateCompatibility); 12916 } 12917 if (sToolkitFrameRateFunctionEnablingReadOnlyFlagValue) { 12918 if (preferredFrameRate > 0) { 12919 mFrameRateTransaction.setFrameRate(mSurfaceControl, preferredFrameRate, 12920 mFrameRateCompatibility); 12921 } else { 12922 mFrameRateTransaction.clearFrameRate(mSurfaceControl); 12923 } 12924 mFrameRateTransaction.applyAsyncUnsafe(); 12925 } 12926 mLastPreferredFrameRate = preferredFrameRate; 12927 } 12928 } catch (Exception e) { 12929 Log.e(mTag, "Unable to set frame rate", e); 12930 } finally { 12931 if (traceFrameRate) { 12932 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 12933 } 12934 } 12935 } 12936 shouldSetFrameRateCategory()12937 private boolean shouldSetFrameRateCategory() { 12938 // use toolkitSetFrameRate flag to gate the change 12939 return shouldEnableDvrr() && mSurface.isValid() && shouldEnableDvrr(); 12940 } 12941 shouldSetFrameRate()12942 private boolean shouldSetFrameRate() { 12943 // use toolkitSetFrameRate flag to gate the change 12944 return shouldEnableDvrr() && mSurface.isValid() && mPreferredFrameRate >= 0 12945 && !mIsFrameRateConflicted; 12946 } 12947 shouldTouchBoost(int motionEventAction, int windowType)12948 private boolean shouldTouchBoost(int motionEventAction, int windowType) { 12949 // boost for almost all input 12950 boolean desiredAction = motionEventAction != MotionEvent.ACTION_OUTSIDE; 12951 boolean undesiredType = windowType == TYPE_INPUT_METHOD 12952 && sToolkitFrameRateTypingReadOnlyFlagValue; 12953 // use toolkitSetFrameRate flag to gate the change 12954 return desiredAction && !undesiredType && shouldEnableDvrr() 12955 && getFrameRateBoostOnTouchEnabled(); 12956 } 12957 12958 /** 12959 * Allow Views to vote for the preferred frame rate category 12960 * 12961 * @param frameRateCategory the preferred frame rate category of a View 12962 */ 12963 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED) votePreferredFrameRateCategory(int frameRateCategory, int reason, View view)12964 public void votePreferredFrameRateCategory(int frameRateCategory, int reason, View view) { 12965 if (frameRateCategory > mPreferredFrameRateCategory) { 12966 mPreferredFrameRateCategory = frameRateCategory; 12967 mFrameRateCategoryChangeReason = reason; 12968 // mFrameRateCategoryView = view == null ? "-" : view.getClass().getSimpleName(); 12969 } 12970 mDrawnThisFrame = true; 12971 } 12972 12973 /** 12974 * Mark a View as having an active ThreadedRenderer animation. This is used for 12975 * RenderNodeAnimators and AnimatedVectorDrawables. When the animation stops, 12976 * {@link #removeThreadedRendererView(View)} must be called. 12977 * @param view The View with the ThreadedRenderer animation that started. 12978 */ addThreadedRendererView(View view)12979 public void addThreadedRendererView(View view) { 12980 if (shouldEnableDvrr() && !mThreadedRendererViews.contains(view)) { 12981 mThreadedRendererViews.add(view); 12982 } 12983 } 12984 12985 /** 12986 * When a ThreadedRenderer animation ends, the View that is associated with it using 12987 * {@link #addThreadedRendererView(View)} must be removed with a call to this method. 12988 * @param view The View whose ThreadedRender animation has stopped. 12989 */ removeThreadedRendererView(View view)12990 public void removeThreadedRendererView(View view) { 12991 mThreadedRendererViews.remove(view); 12992 if (shouldEnableDvrr() 12993 && !mInvalidationIdleMessagePosted && sSurfaceFlingerBugfixFlagValue) { 12994 mInvalidationIdleMessagePosted = true; 12995 mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE, IDLE_TIME_MILLIS); 12996 } 12997 } 12998 12999 /** 13000 * Returns {@link #INTERMITTENT_STATE_INTERMITTENT} when the ViewRootImpl has only been 13001 * updated intermittently, {@link #INTERMITTENT_STATE_NOT_INTERMITTENT} when it is 13002 * not updated intermittently, and {@link #INTERMITTENT_STATE_IN_TRANSITION} when it 13003 * is transitioning between {@link #INTERMITTENT_STATE_NOT_INTERMITTENT} and 13004 * {@link #INTERMITTENT_STATE_INTERMITTENT}. 13005 */ intermittentUpdateState()13006 int intermittentUpdateState() { 13007 if (mMinusOneFrameIntervalMillis + mMinusTwoFrameIntervalMillis 13008 < INFREQUENT_UPDATE_INTERVAL_MILLIS) { 13009 return INTERMITTENT_STATE_NOT_INTERMITTENT; 13010 } 13011 if (mInfrequentUpdateCount == INFREQUENT_UPDATE_COUNTS) { 13012 return INTERMITTENT_STATE_INTERMITTENT; 13013 } 13014 return INTERMITTENT_STATE_IN_TRANSITION; 13015 } 13016 13017 /** 13018 * Returns whether a View should vote for frame rate category. When the category is HIGH 13019 * already, there's no need to calculate the category on the View and vote. 13020 */ shouldCheckFrameRateCategory()13021 public boolean shouldCheckFrameRateCategory() { 13022 return mPreferredFrameRateCategory < FRAME_RATE_CATEGORY_HIGH; 13023 } 13024 13025 /** 13026 * Returns whether a View should vote for frame rate. When the maximum frame rate has already 13027 * been voted for, there's no point in calculating and voting for the frame rate. When 13028 * isDirect is false, then it will return false when the velocity-calculated frame rate 13029 * can be avoided. 13030 * @param isDirect true when the frame rate has been set directly on the View or false if 13031 * the calculation is based only on velocity. 13032 */ shouldCheckFrameRate(boolean isDirect)13033 public boolean shouldCheckFrameRate(boolean isDirect) { 13034 return mPreferredFrameRate < MAX_FRAME_RATE 13035 || (!isDirect && !sToolkitFrameRateVelocityMappingReadOnlyFlagValue 13036 && mPreferredFrameRateCategory < FRAME_RATE_CATEGORY_HIGH); 13037 } 13038 13039 /** 13040 * Allow Views to vote for the preferred frame rate and compatibility. 13041 * When determining the preferred frame rate value, 13042 * we follow this logic: If no preferred frame rate has been set yet, 13043 * we assign the value of frameRate as the preferred frame rate. 13044 * IF there are multiple frame rates are voted: 13045 * 1. There is a frame rate is a multiple of all other frame rates. 13046 * We choose this frmae rate to be the one to be set. 13047 * 2. There is no frame rate can be a multiple of others 13048 * We set category to HIGH if the maximum frame rate is greater than 60. 13049 * Otherwise, we set category to NORMAL. 13050 * 13051 * Use FRAME_RATE_COMPATIBILITY_GTE for velocity and FRAME_RATE_COMPATIBILITY_FIXED_SOURCE 13052 * for TextureView video play and user requested frame rate. 13053 * 13054 * @param frameRate the preferred frame rate of a View 13055 * @param frameRateCompatibility the preferred frame rate compatibility of a View 13056 */ 13057 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED) votePreferredFrameRate(float frameRate, int frameRateCompatibility)13058 public void votePreferredFrameRate(float frameRate, int frameRateCompatibility) { 13059 if (frameRate <= 0) { 13060 return; 13061 } 13062 if (frameRateCompatibility == FRAME_RATE_COMPATIBILITY_GTE) { 13063 mIsTouchBoosting = false; 13064 mIsFrameRateBoosting = false; 13065 if (!sToolkitFrameRateVelocityMappingReadOnlyFlagValue) { 13066 mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH; 13067 mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT; 13068 mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_VELOCITY; 13069 mFrameRateCategoryView = null; 13070 mDrawnThisFrame = true; 13071 return; 13072 } 13073 } 13074 float nextFrameRate; 13075 int nextFrameRateCompatibility; 13076 if (frameRate > mPreferredFrameRate) { 13077 nextFrameRate = frameRate; 13078 nextFrameRateCompatibility = frameRateCompatibility; 13079 } else { 13080 nextFrameRate = mPreferredFrameRate; 13081 nextFrameRateCompatibility = mFrameRateCompatibility; 13082 } 13083 13084 if (mPreferredFrameRate > 0 && mPreferredFrameRate % frameRate != 0 13085 && frameRate % mPreferredFrameRate != 0) { 13086 mIsFrameRateConflicted = true; 13087 if (nextFrameRate > 60 && mFrameRateCategoryHighCount != FRAME_RATE_CATEGORY_COUNT) { 13088 mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT; 13089 mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_CONFLICTED; 13090 mFrameRateCategoryView = null; 13091 } else if (mFrameRateCategoryHighCount == 0 && mFrameRateCategoryHighHintCount == 0 13092 && mFrameRateCategoryNormalCount < FRAME_RATE_CATEGORY_COUNT) { 13093 mFrameRateCategoryNormalCount = FRAME_RATE_CATEGORY_COUNT; 13094 mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_CONFLICTED; 13095 mFrameRateCategoryView = null; 13096 } 13097 } 13098 13099 mPreferredFrameRate = nextFrameRate; 13100 mFrameRateCompatibility = nextFrameRateCompatibility; 13101 mDrawnThisFrame = true; 13102 } 13103 13104 /** 13105 * Get the value of mPreferredFrameRateCategory 13106 */ 13107 @VisibleForTesting getPreferredFrameRateCategory()13108 public int getPreferredFrameRateCategory() { 13109 return mPreferredFrameRateCategory; 13110 } 13111 13112 /** 13113 * Get the value of mLastPreferredFrameRateCategory 13114 */ 13115 @VisibleForTesting getLastPreferredFrameRateCategory()13116 public int getLastPreferredFrameRateCategory() { 13117 return mLastPreferredFrameRateCategory; 13118 } 13119 13120 /** 13121 * Get the value of mPreferredFrameRate 13122 */ 13123 @VisibleForTesting getPreferredFrameRate()13124 public float getPreferredFrameRate() { 13125 return mPreferredFrameRate >= 0 ? mPreferredFrameRate : mLastPreferredFrameRate; 13126 } 13127 13128 /** 13129 * Get the value of mLastPreferredFrameRate 13130 */ 13131 @VisibleForTesting getLastPreferredFrameRate()13132 public float getLastPreferredFrameRate() { 13133 return mLastPreferredFrameRate; 13134 } 13135 13136 /** 13137 * Returns whether touch boost is currently enabled. 13138 */ 13139 @VisibleForTesting getIsTouchBoosting()13140 public boolean getIsTouchBoosting() { 13141 return mIsTouchBoosting; 13142 } 13143 13144 /** 13145 * Get the value of mFrameRateCompatibility 13146 */ 13147 @VisibleForTesting getFrameRateCompatibility()13148 public int getFrameRateCompatibility() { 13149 return mFrameRateCompatibility; 13150 } 13151 13152 /** 13153 * Get the value of mIsFrameRateBoosting 13154 */ 13155 @VisibleForTesting getIsFrameRateBoosting()13156 public boolean getIsFrameRateBoosting() { 13157 return mIsFrameRateBoosting; 13158 } 13159 13160 /** 13161 * Get the value of mFrameRateBoostOnTouchEnabled 13162 * Can be used to checked if touch boost is enabled. The default value is true. 13163 */ 13164 @VisibleForTesting getFrameRateBoostOnTouchEnabled()13165 public boolean getFrameRateBoostOnTouchEnabled() { 13166 return mWindowAttributes.getFrameRateBoostOnTouchEnabled(); 13167 } 13168 boostFrameRate(int boostTimeOut)13169 private void boostFrameRate(int boostTimeOut) { 13170 mIsFrameRateBoosting = true; 13171 mHandler.removeMessages(MSG_TOUCH_BOOST_TIMEOUT); 13172 mHandler.sendEmptyMessageDelayed(MSG_TOUCH_BOOST_TIMEOUT, 13173 boostTimeOut); 13174 } 13175 13176 /** 13177 * Set the default back key callback for windowless window, to forward the back key event 13178 * to host app. 13179 * MUST NOT call this method for normal window. 13180 */ setBackKeyCallbackForWindowlessWindow(@onNull Predicate<KeyEvent> callback)13181 void setBackKeyCallbackForWindowlessWindow(@NonNull Predicate<KeyEvent> callback) { 13182 mWindowlessBackKeyCallback = callback; 13183 } 13184 recordViewPercentage(float percentage)13185 void recordViewPercentage(float percentage) { 13186 if (!Trace.isEnabled()) return; 13187 // Record the largest view of percentage to the display size. 13188 mLargestChildPercentage = Math.max(percentage, mLargestChildPercentage); 13189 } 13190 13191 /** 13192 * Get the value of mIsFrameRatePowerSavingsBalanced 13193 * Can be used to checked if toolkit dVRR feature is enabled. The default value is true. 13194 */ 13195 @VisibleForTesting isFrameRatePowerSavingsBalanced()13196 public boolean isFrameRatePowerSavingsBalanced() { 13197 if (sToolkitSetFrameRateReadOnlyFlagValue) { 13198 return mWindowAttributes.isFrameRatePowerSavingsBalanced(); 13199 } 13200 return true; 13201 } 13202 13203 /** 13204 * Get the value of mIsFrameRateConflicted 13205 * Can be used to checked if there is a conflict of frame rate votes. 13206 */ 13207 @VisibleForTesting isFrameRateConflicted()13208 public boolean isFrameRateConflicted() { 13209 return mIsFrameRateConflicted; 13210 } 13211 shouldEnableDvrr()13212 private boolean shouldEnableDvrr() { 13213 // uncomment this when we are ready for enabling dVRR 13214 if (sEnableVrr && sToolkitFrameRateViewEnablingReadOnlyFlagValue) { 13215 return sToolkitSetFrameRateReadOnlyFlagValue && isFrameRatePowerSavingsBalanced(); 13216 } 13217 return false; 13218 } 13219 removeVrrMessages()13220 private void removeVrrMessages() { 13221 mHandler.removeMessages(MSG_TOUCH_BOOST_TIMEOUT); 13222 mHandler.removeMessages(MSG_FRAME_RATE_SETTING); 13223 if (mInvalidationIdleMessagePosted && sSurfaceFlingerBugfixFlagValue) { 13224 mInvalidationIdleMessagePosted = false; 13225 mHandler.removeMessages(MSG_CHECK_INVALIDATION_IDLE); 13226 } 13227 } 13228 13229 /** 13230 * This function is mainly used for migrating infrequent layer logic 13231 * from SurfaceFlinger to Toolkit. 13232 * The infrequent layer logic includes: 13233 * - NORMAL for infrequent update: FT2-FT1 > 100 && FT3-FT2 > 100. 13234 * - HIGH/NORMAL based on size for frequent update: (FT3-FT2) + (FT2 - FT1) < 100. 13235 * - otherwise, use the previous category value. 13236 */ updateInfrequentCount()13237 private void updateInfrequentCount() { 13238 long currentTimeMillis = mAttachInfo.mDrawingTime; 13239 int timeIntervalMillis = 13240 (int) Math.min(Integer.MAX_VALUE, currentTimeMillis - mLastUpdateTimeMillis); 13241 mMinusTwoFrameIntervalMillis = mMinusOneFrameIntervalMillis; 13242 mMinusOneFrameIntervalMillis = timeIntervalMillis; 13243 13244 mLastUpdateTimeMillis = currentTimeMillis; 13245 if (mThreadedRendererViews.isEmpty() && timeIntervalMillis + mMinusTwoFrameIntervalMillis 13246 >= INFREQUENT_UPDATE_INTERVAL_MILLIS) { 13247 int infrequentUpdateCount = mInfrequentUpdateCount; 13248 mInfrequentUpdateCount = infrequentUpdateCount == INFREQUENT_UPDATE_COUNTS 13249 ? infrequentUpdateCount : infrequentUpdateCount + 1; 13250 } else { 13251 mInfrequentUpdateCount = 0; 13252 } 13253 } 13254 } 13255