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