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