• 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 android.Manifest;
20 import android.animation.LayoutTransition;
21 import android.app.ActivityManagerNative;
22 import android.content.ClipDescription;
23 import android.content.ComponentCallbacks;
24 import android.content.ComponentCallbacks2;
25 import android.content.Context;
26 import android.content.pm.ApplicationInfo;
27 import android.content.pm.PackageManager;
28 import android.content.res.CompatibilityInfo;
29 import android.content.res.Configuration;
30 import android.content.res.Resources;
31 import android.graphics.Canvas;
32 import android.graphics.Paint;
33 import android.graphics.PixelFormat;
34 import android.graphics.Point;
35 import android.graphics.PointF;
36 import android.graphics.PorterDuff;
37 import android.graphics.Rect;
38 import android.graphics.Region;
39 import android.graphics.drawable.Drawable;
40 import android.media.AudioManager;
41 import android.os.Binder;
42 import android.os.Bundle;
43 import android.os.Debug;
44 import android.os.Handler;
45 import android.os.LatencyTimer;
46 import android.os.Looper;
47 import android.os.Message;
48 import android.os.ParcelFileDescriptor;
49 import android.os.PowerManager;
50 import android.os.Process;
51 import android.os.RemoteException;
52 import android.os.SystemClock;
53 import android.os.SystemProperties;
54 import android.os.Trace;
55 import android.util.AndroidRuntimeException;
56 import android.util.DisplayMetrics;
57 import android.util.Log;
58 import android.util.Slog;
59 import android.util.TypedValue;
60 import android.view.View.AttachInfo;
61 import android.view.View.MeasureSpec;
62 import android.view.accessibility.AccessibilityEvent;
63 import android.view.accessibility.AccessibilityManager;
64 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
65 import android.view.accessibility.AccessibilityNodeInfo;
66 import android.view.accessibility.AccessibilityNodeProvider;
67 import android.view.accessibility.IAccessibilityInteractionConnection;
68 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
69 import android.view.animation.AccelerateDecelerateInterpolator;
70 import android.view.animation.Interpolator;
71 import android.view.inputmethod.InputConnection;
72 import android.view.inputmethod.InputMethodManager;
73 import android.widget.Scroller;
74 
75 import com.android.internal.R;
76 import com.android.internal.os.SomeArgs;
77 import com.android.internal.policy.PolicyManager;
78 import com.android.internal.view.BaseSurfaceHolder;
79 import com.android.internal.view.RootViewSurfaceTaker;
80 
81 import java.io.IOException;
82 import java.io.OutputStream;
83 import java.lang.ref.WeakReference;
84 import java.util.ArrayList;
85 import java.util.HashSet;
86 
87 /**
88  * The top of a view hierarchy, implementing the needed protocol between View
89  * and the WindowManager.  This is for the most part an internal implementation
90  * detail of {@link WindowManagerGlobal}.
91  *
92  * {@hide}
93  */
94 @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
95 public final class ViewRootImpl implements ViewParent,
96         View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
97     private static final String TAG = "ViewRootImpl";
98     private static final boolean DBG = false;
99     private static final boolean LOCAL_LOGV = false;
100     /** @noinspection PointlessBooleanExpression*/
101     private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
102     private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
103     private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
104     private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
105     private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
106     private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
107     private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
108     private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
109     private static final boolean DEBUG_FPS = false;
110 
111     private static final boolean USE_RENDER_THREAD = false;
112 
113     /**
114      * Set this system property to true to force the view hierarchy to render
115      * at 60 Hz. This can be used to measure the potential framerate.
116      */
117     private static final String PROPERTY_PROFILE_RENDERING = "viewancestor.profile_rendering";
118 
119     private static final boolean MEASURE_LATENCY = false;
120     private static LatencyTimer lt;
121 
122     /**
123      * Maximum time we allow the user to roll the trackball enough to generate
124      * a key event, before resetting the counters.
125      */
126     static final int MAX_TRACKBALL_DELAY = 250;
127 
128     static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>();
129 
130     static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
131     static boolean sFirstDrawComplete = false;
132 
133     static final ArrayList<ComponentCallbacks> sConfigCallbacks
134             = new ArrayList<ComponentCallbacks>();
135 
136     private static boolean sUseRenderThread = false;
137     private static boolean sRenderThreadQueried = false;
138     private static final Object[] sRenderThreadQueryLock = new Object[0];
139 
140     final IWindowSession mWindowSession;
141     final Display mDisplay;
142 
143     long mLastTrackballTime = 0;
144     final TrackballAxis mTrackballAxisX = new TrackballAxis();
145     final TrackballAxis mTrackballAxisY = new TrackballAxis();
146 
147     int mLastJoystickXDirection;
148     int mLastJoystickYDirection;
149     int mLastJoystickXKeyCode;
150     int mLastJoystickYKeyCode;
151 
152     final int[] mTmpLocation = new int[2];
153 
154     final TypedValue mTmpValue = new TypedValue();
155 
156     final InputMethodCallback mInputMethodCallback;
157     final Thread mThread;
158 
159     final WindowLeaked mLocation;
160 
161     final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
162 
163     final W mWindow;
164 
165     final int mTargetSdkVersion;
166 
167     int mSeq;
168 
169     View mView;
170     View mFocusedView;
171     View mRealFocusedView;  // this is not set to null in touch mode
172     View mOldFocusedView;
173 
174     View mAccessibilityFocusedHost;
175     AccessibilityNodeInfo mAccessibilityFocusedVirtualView;
176 
177     int mViewVisibility;
178     boolean mAppVisible = true;
179     int mOrigWindowType = -1;
180 
181     // Set to true if the owner of this window is in the stopped state,
182     // so the window should no longer be active.
183     boolean mStopped = false;
184 
185     boolean mLastInCompatMode = false;
186 
187     SurfaceHolder.Callback2 mSurfaceHolderCallback;
188     BaseSurfaceHolder mSurfaceHolder;
189     boolean mIsCreating;
190     boolean mDrawingAllowed;
191 
192     final Region mTransparentRegion;
193     final Region mPreviousTransparentRegion;
194 
195     int mWidth;
196     int mHeight;
197     Rect mDirty;
198     final Rect mCurrentDirty = new Rect();
199     final Rect mPreviousDirty = new Rect();
200     boolean mIsAnimating;
201 
202     CompatibilityInfo.Translator mTranslator;
203 
204     final View.AttachInfo mAttachInfo;
205     InputChannel mInputChannel;
206     InputQueue.Callback mInputQueueCallback;
207     InputQueue mInputQueue;
208     FallbackEventHandler mFallbackEventHandler;
209     Choreographer mChoreographer;
210 
211     final Rect mTempRect; // used in the transaction to not thrash the heap.
212     final Rect mVisRect; // used to retrieve visible rect of focused view.
213 
214     boolean mTraversalScheduled;
215     int mTraversalBarrier;
216     boolean mWillDrawSoon;
217     /** Set to true while in performTraversals for detecting when die(true) is called from internal
218      * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */
219     boolean mIsInTraversal;
220     boolean mFitSystemWindowsRequested;
221     boolean mLayoutRequested;
222     boolean mFirst;
223     boolean mReportNextDraw;
224     boolean mFullRedrawNeeded;
225     boolean mNewSurfaceNeeded;
226     boolean mHasHadWindowFocus;
227     boolean mLastWasImTarget;
228     boolean mWindowsAnimating;
229     boolean mIsDrawing;
230     int mLastSystemUiVisibility;
231     int mClientWindowLayoutFlags;
232 
233     // Pool of queued input events.
234     private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
235     private QueuedInputEvent mQueuedInputEventPool;
236     private int mQueuedInputEventPoolSize;
237 
238     // Input event queue.
239     QueuedInputEvent mFirstPendingInputEvent;
240     QueuedInputEvent mCurrentInputEvent;
241     boolean mProcessInputEventsScheduled;
242 
243     boolean mWindowAttributesChanged = false;
244     int mWindowAttributesChangesFlag = 0;
245 
246     // These can be accessed by any thread, must be protected with a lock.
247     // Surface can never be reassigned or cleared (use Surface.clear()).
248     private final Surface mSurface = new Surface();
249 
250     boolean mAdded;
251     boolean mAddedTouchMode;
252 
253     final CompatibilityInfoHolder mCompatibilityInfo;
254 
255     // These are accessed by multiple threads.
256     final Rect mWinFrame; // frame given by window manager.
257 
258     final Rect mPendingVisibleInsets = new Rect();
259     final Rect mPendingContentInsets = new Rect();
260     final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
261             = new ViewTreeObserver.InternalInsetsInfo();
262 
263     final Rect mFitSystemWindowsInsets = new Rect();
264 
265     final Configuration mLastConfiguration = new Configuration();
266     final Configuration mPendingConfiguration = new Configuration();
267 
268     boolean mScrollMayChange;
269     int mSoftInputMode;
270     View mLastScrolledFocus;
271     int mScrollY;
272     int mCurScrollY;
273     Scroller mScroller;
274     HardwareLayer mResizeBuffer;
275     long mResizeBufferStartTime;
276     int mResizeBufferDuration;
277     static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
278     private ArrayList<LayoutTransition> mPendingTransitions;
279 
280     final ViewConfiguration mViewConfiguration;
281 
282     /* Drag/drop */
283     ClipDescription mDragDescription;
284     View mCurrentDragView;
285     volatile Object mLocalDragState;
286     final PointF mDragPoint = new PointF();
287     final PointF mLastTouchPoint = new PointF();
288 
289     private boolean mProfileRendering;
290     private Thread mRenderProfiler;
291     private volatile boolean mRenderProfilingEnabled;
292 
293     // Variables to track frames per second, enabled via DEBUG_FPS flag
294     private long mFpsStartTime = -1;
295     private long mFpsPrevTime = -1;
296     private int mFpsNumFrames;
297 
298     private final ArrayList<DisplayList> mDisplayLists = new ArrayList<DisplayList>(24);
299 
300     /**
301      * see {@link #playSoundEffect(int)}
302      */
303     AudioManager mAudioManager;
304 
305     final AccessibilityManager mAccessibilityManager;
306 
307     AccessibilityInteractionController mAccessibilityInteractionController;
308 
309     AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager;
310 
311     SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
312 
313     HashSet<View> mTempHashSet;
314 
315     private final int mDensity;
316     private final int mNoncompatDensity;
317 
318     private int mViewLayoutDirectionInitial;
319 
320     /**
321      * Consistency verifier for debugging purposes.
322      */
323     protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
324             InputEventConsistencyVerifier.isInstrumentationEnabled() ?
325                     new InputEventConsistencyVerifier(this, 0) : null;
326 
327     static final class SystemUiVisibilityInfo {
328         int seq;
329         int globalVisibility;
330         int localValue;
331         int localChanges;
332     }
333 
ViewRootImpl(Context context, Display display)334     public ViewRootImpl(Context context, Display display) {
335         super();
336 
337         if (MEASURE_LATENCY) {
338             if (lt == null) {
339                 lt = new LatencyTimer(100, 1000);
340             }
341         }
342 
343         // Initialize the statics when this class is first instantiated. This is
344         // done here instead of in the static block because Zygote does not
345         // allow the spawning of threads.
346         mWindowSession = WindowManagerGlobal.getWindowSession(context.getMainLooper());
347         mDisplay = display;
348 
349         CompatibilityInfoHolder cih = display.getCompatibilityInfo();
350         mCompatibilityInfo = cih != null ? cih : new CompatibilityInfoHolder();
351 
352         mThread = Thread.currentThread();
353         mLocation = new WindowLeaked(null);
354         mLocation.fillInStackTrace();
355         mWidth = -1;
356         mHeight = -1;
357         mDirty = new Rect();
358         mTempRect = new Rect();
359         mVisRect = new Rect();
360         mWinFrame = new Rect();
361         mWindow = new W(this);
362         mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
363         mInputMethodCallback = new InputMethodCallback(this);
364         mViewVisibility = View.GONE;
365         mTransparentRegion = new Region();
366         mPreviousTransparentRegion = new Region();
367         mFirst = true; // true for the first time the view is added
368         mAdded = false;
369         mAccessibilityManager = AccessibilityManager.getInstance(context);
370         mAccessibilityInteractionConnectionManager =
371             new AccessibilityInteractionConnectionManager();
372         mAccessibilityManager.addAccessibilityStateChangeListener(
373                 mAccessibilityInteractionConnectionManager);
374         mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
375         mViewConfiguration = ViewConfiguration.get(context);
376         mDensity = context.getResources().getDisplayMetrics().densityDpi;
377         mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
378         mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
379         mProfileRendering = Boolean.parseBoolean(
380                 SystemProperties.get(PROPERTY_PROFILE_RENDERING, "false"));
381         mChoreographer = Choreographer.getInstance();
382 
383         PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
384         mAttachInfo.mScreenOn = powerManager.isScreenOn();
385         loadSystemProperties();
386     }
387 
388     /**
389      * @return True if the application requests the use of a separate render thread,
390      *         false otherwise
391      */
isRenderThreadRequested(Context context)392     private static boolean isRenderThreadRequested(Context context) {
393         if (USE_RENDER_THREAD) {
394             synchronized (sRenderThreadQueryLock) {
395                 if (!sRenderThreadQueried) {
396                     final PackageManager packageManager = context.getPackageManager();
397                     final String packageName = context.getApplicationInfo().packageName;
398                     try {
399                         ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName,
400                                 PackageManager.GET_META_DATA);
401                         if (applicationInfo.metaData != null) {
402                             sUseRenderThread = applicationInfo.metaData.getBoolean(
403                                     "android.graphics.renderThread", false);
404                         }
405                     } catch (PackageManager.NameNotFoundException e) {
406                     } finally {
407                         sRenderThreadQueried = true;
408                     }
409                 }
410                 return sUseRenderThread;
411             }
412         } else {
413             return false;
414         }
415     }
416 
addFirstDrawHandler(Runnable callback)417     public static void addFirstDrawHandler(Runnable callback) {
418         synchronized (sFirstDrawHandlers) {
419             if (!sFirstDrawComplete) {
420                 sFirstDrawHandlers.add(callback);
421             }
422         }
423     }
424 
addConfigCallback(ComponentCallbacks callback)425     public static void addConfigCallback(ComponentCallbacks callback) {
426         synchronized (sConfigCallbacks) {
427             sConfigCallbacks.add(callback);
428         }
429     }
430 
431     // FIXME for perf testing only
432     private boolean mProfile = false;
433 
434     /**
435      * Call this to profile the next traversal call.
436      * FIXME for perf testing only. Remove eventually
437      */
profile()438     public void profile() {
439         mProfile = true;
440     }
441 
442     /**
443      * Indicates whether we are in touch mode. Calling this method triggers an IPC
444      * call and should be avoided whenever possible.
445      *
446      * @return True, if the device is in touch mode, false otherwise.
447      *
448      * @hide
449      */
isInTouchMode()450     static boolean isInTouchMode() {
451         IWindowSession windowSession = WindowManagerGlobal.peekWindowSession();
452         if (windowSession != null) {
453             try {
454                 return windowSession.getInTouchMode();
455             } catch (RemoteException e) {
456             }
457         }
458         return false;
459     }
460 
461     /**
462      * We have one child
463      */
setView(View view, WindowManager.LayoutParams attrs, View panelParentView)464     public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
465         synchronized (this) {
466             if (mView == null) {
467                 mView = view;
468                 mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
469                 mFallbackEventHandler.setView(view);
470                 mWindowAttributes.copyFrom(attrs);
471                 attrs = mWindowAttributes;
472                 // Keep track of the actual window flags supplied by the client.
473                 mClientWindowLayoutFlags = attrs.flags;
474 
475                 setAccessibilityFocus(null, null);
476 
477                 if (view instanceof RootViewSurfaceTaker) {
478                     mSurfaceHolderCallback =
479                             ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
480                     if (mSurfaceHolderCallback != null) {
481                         mSurfaceHolder = new TakenSurfaceHolder();
482                         mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
483                     }
484                 }
485 
486                 CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
487                 mTranslator = compatibilityInfo.getTranslator();
488 
489                 // If the application owns the surface, don't enable hardware acceleration
490                 if (mSurfaceHolder == null) {
491                     enableHardwareAcceleration(mView.getContext(), attrs);
492                 }
493 
494                 boolean restore = false;
495                 if (mTranslator != null) {
496                     mSurface.setCompatibilityTranslator(mTranslator);
497                     restore = true;
498                     attrs.backup();
499                     mTranslator.translateWindowLayout(attrs);
500                 }
501                 if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
502 
503                 if (!compatibilityInfo.supportsScreen()) {
504                     attrs.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
505                     mLastInCompatMode = true;
506                 }
507 
508                 mSoftInputMode = attrs.softInputMode;
509                 mWindowAttributesChanged = true;
510                 mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
511                 mAttachInfo.mRootView = view;
512                 mAttachInfo.mScalingRequired = mTranslator != null;
513                 mAttachInfo.mApplicationScale =
514                         mTranslator == null ? 1.0f : mTranslator.applicationScale;
515                 if (panelParentView != null) {
516                     mAttachInfo.mPanelParentWindowToken
517                             = panelParentView.getApplicationWindowToken();
518                 }
519                 mAdded = true;
520                 int res; /* = WindowManagerImpl.ADD_OKAY; */
521 
522                 // Schedule the first layout -before- adding to the window
523                 // manager, to make sure we do the relayout before receiving
524                 // any other events from the system.
525                 requestLayout();
526                 if ((mWindowAttributes.inputFeatures
527                         & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
528                     mInputChannel = new InputChannel();
529                 }
530                 try {
531                     mOrigWindowType = mWindowAttributes.type;
532                     mAttachInfo.mRecomputeGlobalAttributes = true;
533                     collectViewAttributes();
534                     res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
535                             getHostVisibility(), mDisplay.getDisplayId(),
536                             mAttachInfo.mContentInsets, mInputChannel);
537                 } catch (RemoteException e) {
538                     mAdded = false;
539                     mView = null;
540                     mAttachInfo.mRootView = null;
541                     mInputChannel = null;
542                     mFallbackEventHandler.setView(null);
543                     unscheduleTraversals();
544                     setAccessibilityFocus(null, null);
545                     throw new RuntimeException("Adding window failed", e);
546                 } finally {
547                     if (restore) {
548                         attrs.restore();
549                     }
550                 }
551 
552                 if (mTranslator != null) {
553                     mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
554                 }
555                 mPendingContentInsets.set(mAttachInfo.mContentInsets);
556                 mPendingVisibleInsets.set(0, 0, 0, 0);
557                 if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
558                 if (res < WindowManagerGlobal.ADD_OKAY) {
559                     mAttachInfo.mRootView = null;
560                     mAdded = false;
561                     mFallbackEventHandler.setView(null);
562                     unscheduleTraversals();
563                     setAccessibilityFocus(null, null);
564                     switch (res) {
565                         case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
566                         case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
567                             throw new WindowManager.BadTokenException(
568                                 "Unable to add window -- token " + attrs.token
569                                 + " is not valid; is your activity running?");
570                         case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
571                             throw new WindowManager.BadTokenException(
572                                 "Unable to add window -- token " + attrs.token
573                                 + " is not for an application");
574                         case WindowManagerGlobal.ADD_APP_EXITING:
575                             throw new WindowManager.BadTokenException(
576                                 "Unable to add window -- app for token " + attrs.token
577                                 + " is exiting");
578                         case WindowManagerGlobal.ADD_DUPLICATE_ADD:
579                             throw new WindowManager.BadTokenException(
580                                 "Unable to add window -- window " + mWindow
581                                 + " has already been added");
582                         case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
583                             // Silently ignore -- we would have just removed it
584                             // right away, anyway.
585                             return;
586                         case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
587                             throw new WindowManager.BadTokenException(
588                                 "Unable to add window " + mWindow +
589                                 " -- another window of this type already exists");
590                         case WindowManagerGlobal.ADD_PERMISSION_DENIED:
591                             throw new WindowManager.BadTokenException(
592                                 "Unable to add window " + mWindow +
593                                 " -- permission denied for this window type");
594                         case WindowManagerGlobal.ADD_INVALID_DISPLAY:
595                             throw new WindowManager.InvalidDisplayException(
596                                 "Unable to add window " + mWindow +
597                                 " -- the specified display can not be found");
598                     }
599                     throw new RuntimeException(
600                         "Unable to add window -- unknown error code " + res);
601                 }
602 
603                 if (view instanceof RootViewSurfaceTaker) {
604                     mInputQueueCallback =
605                         ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
606                 }
607                 if (mInputChannel != null) {
608                     if (mInputQueueCallback != null) {
609                         mInputQueue = new InputQueue(mInputChannel);
610                         mInputQueueCallback.onInputQueueCreated(mInputQueue);
611                     } else {
612                         mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
613                                 Looper.myLooper());
614                     }
615                 }
616 
617                 view.assignParent(this);
618                 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
619                 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
620 
621                 if (mAccessibilityManager.isEnabled()) {
622                     mAccessibilityInteractionConnectionManager.ensureConnection();
623                 }
624 
625                 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
626                     view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
627                 }
628             }
629         }
630     }
631 
destroyHardwareResources()632     void destroyHardwareResources() {
633         if (mAttachInfo.mHardwareRenderer != null) {
634             if (mAttachInfo.mHardwareRenderer.isEnabled()) {
635                 mAttachInfo.mHardwareRenderer.destroyLayers(mView);
636             }
637             mAttachInfo.mHardwareRenderer.destroy(false);
638         }
639     }
640 
terminateHardwareResources()641     void terminateHardwareResources() {
642         if (mAttachInfo.mHardwareRenderer != null) {
643             mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
644             mAttachInfo.mHardwareRenderer.destroy(false);
645         }
646     }
647 
destroyHardwareLayers()648     void destroyHardwareLayers() {
649         if (mThread != Thread.currentThread()) {
650             if (mAttachInfo.mHardwareRenderer != null &&
651                     mAttachInfo.mHardwareRenderer.isEnabled()) {
652                 HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
653             }
654         } else {
655             if (mAttachInfo.mHardwareRenderer != null &&
656                     mAttachInfo.mHardwareRenderer.isEnabled()) {
657                 mAttachInfo.mHardwareRenderer.destroyLayers(mView);
658             }
659         }
660     }
661 
pushHardwareLayerUpdate(HardwareLayer layer)662     void pushHardwareLayerUpdate(HardwareLayer layer) {
663         if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
664             mAttachInfo.mHardwareRenderer.pushLayerUpdate(layer);
665         }
666     }
667 
attachFunctor(int functor)668     public boolean attachFunctor(int functor) {
669         //noinspection SimplifiableIfStatement
670         if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
671             return mAttachInfo.mHardwareRenderer.attachFunctor(mAttachInfo, functor);
672         }
673         return false;
674     }
675 
detachFunctor(int functor)676     public void detachFunctor(int functor) {
677         if (mAttachInfo.mHardwareRenderer != null) {
678             mAttachInfo.mHardwareRenderer.detachFunctor(functor);
679         }
680     }
681 
enableHardwareAcceleration(Context context, WindowManager.LayoutParams attrs)682     private void enableHardwareAcceleration(Context context, WindowManager.LayoutParams attrs) {
683         mAttachInfo.mHardwareAccelerated = false;
684         mAttachInfo.mHardwareAccelerationRequested = false;
685 
686         // Don't enable hardware acceleration when the application is in compatibility mode
687         if (mTranslator != null) return;
688 
689         // Try to enable hardware acceleration if requested
690         final boolean hardwareAccelerated =
691                 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
692 
693         if (hardwareAccelerated) {
694             if (!HardwareRenderer.isAvailable()) {
695                 return;
696             }
697 
698             // Persistent processes (including the system) should not do
699             // accelerated rendering on low-end devices.  In that case,
700             // sRendererDisabled will be set.  In addition, the system process
701             // itself should never do accelerated rendering.  In that case, both
702             // sRendererDisabled and sSystemRendererDisabled are set.  When
703             // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
704             // can be used by code on the system process to escape that and enable
705             // HW accelerated drawing.  (This is basically for the lock screen.)
706 
707             final boolean fakeHwAccelerated = (attrs.privateFlags &
708                     WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
709             final boolean forceHwAccelerated = (attrs.privateFlags &
710                     WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
711 
712             if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled
713                     && forceHwAccelerated)) {
714                 // Don't enable hardware acceleration when we're not on the main thread
715                 if (!HardwareRenderer.sSystemRendererDisabled &&
716                         Looper.getMainLooper() != Looper.myLooper()) {
717                     Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
718                             + "acceleration outside of the main thread, aborting");
719                     return;
720                 }
721 
722                 final boolean renderThread = isRenderThreadRequested(context);
723                 if (renderThread) {
724                     Log.i(HardwareRenderer.LOG_TAG, "Render threat initiated");
725                 }
726 
727                 if (mAttachInfo.mHardwareRenderer != null) {
728                     mAttachInfo.mHardwareRenderer.destroy(true);
729                 }
730 
731                 final boolean translucent = attrs.format != PixelFormat.OPAQUE;
732                 mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
733                 mAttachInfo.mHardwareAccelerated = mAttachInfo.mHardwareAccelerationRequested
734                         = mAttachInfo.mHardwareRenderer != null;
735 
736             } else if (fakeHwAccelerated) {
737                 // The window had wanted to use hardware acceleration, but this
738                 // is not allowed in its process.  By setting this flag, it can
739                 // still render as if it was accelerated.  This is basically for
740                 // the preview windows the window manager shows for launching
741                 // applications, so they will look more like the app being launched.
742                 mAttachInfo.mHardwareAccelerationRequested = true;
743             }
744         }
745     }
746 
getView()747     public View getView() {
748         return mView;
749     }
750 
getLocation()751     final WindowLeaked getLocation() {
752         return mLocation;
753     }
754 
setLayoutParams(WindowManager.LayoutParams attrs, boolean newView)755     void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
756         synchronized (this) {
757             int oldSoftInputMode = mWindowAttributes.softInputMode;
758             // Keep track of the actual window flags supplied by the client.
759             mClientWindowLayoutFlags = attrs.flags;
760             // preserve compatible window flag if exists.
761             int compatibleWindowFlag =
762                 mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
763             // transfer over system UI visibility values as they carry current state.
764             attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
765             attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
766             mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
767             mWindowAttributes.flags |= compatibleWindowFlag;
768 
769             applyKeepScreenOnFlag(mWindowAttributes);
770 
771             if (newView) {
772                 mSoftInputMode = attrs.softInputMode;
773                 requestLayout();
774             }
775             // Don't lose the mode we last auto-computed.
776             if ((attrs.softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
777                     == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
778                 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
779                         & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
780                         | (oldSoftInputMode
781                                 & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
782             }
783             mWindowAttributesChanged = true;
784             scheduleTraversals();
785         }
786     }
787 
handleAppVisibility(boolean visible)788     void handleAppVisibility(boolean visible) {
789         if (mAppVisible != visible) {
790             mAppVisible = visible;
791             scheduleTraversals();
792         }
793     }
794 
handleGetNewSurface()795     void handleGetNewSurface() {
796         mNewSurfaceNeeded = true;
797         mFullRedrawNeeded = true;
798         scheduleTraversals();
799     }
800 
handleScreenStateChange(boolean on)801     void handleScreenStateChange(boolean on) {
802         if (on != mAttachInfo.mScreenOn) {
803             mAttachInfo.mScreenOn = on;
804             if (mView != null) {
805                 mView.dispatchScreenStateChanged(on ? View.SCREEN_STATE_ON : View.SCREEN_STATE_OFF);
806             }
807             if (on) {
808                 mFullRedrawNeeded = true;
809                 scheduleTraversals();
810             }
811         }
812     }
813 
814     @Override
requestFitSystemWindows()815     public void requestFitSystemWindows() {
816         checkThread();
817         mFitSystemWindowsRequested = true;
818         scheduleTraversals();
819     }
820 
821     @Override
requestLayout()822     public void requestLayout() {
823         checkThread();
824         mLayoutRequested = true;
825         scheduleTraversals();
826     }
827 
828     @Override
isLayoutRequested()829     public boolean isLayoutRequested() {
830         return mLayoutRequested;
831     }
832 
invalidate()833     void invalidate() {
834         mDirty.set(0, 0, mWidth, mHeight);
835         scheduleTraversals();
836     }
837 
invalidateWorld(View view)838     void invalidateWorld(View view) {
839         view.invalidate();
840         if (view instanceof ViewGroup) {
841             ViewGroup parent = (ViewGroup) view;
842             for (int i = 0; i < parent.getChildCount(); i++) {
843                 invalidateWorld(parent.getChildAt(i));
844             }
845         }
846     }
847 
848     @Override
invalidateChild(View child, Rect dirty)849     public void invalidateChild(View child, Rect dirty) {
850         invalidateChildInParent(null, dirty);
851     }
852 
invalidateChildInParent(int[] location, Rect dirty)853     public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
854         checkThread();
855         if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
856 
857         if (dirty == null) {
858             invalidate();
859             return null;
860         } else if (dirty.isEmpty() && !mIsAnimating) {
861             return null;
862         }
863 
864         if (mCurScrollY != 0 || mTranslator != null) {
865             mTempRect.set(dirty);
866             dirty = mTempRect;
867             if (mCurScrollY != 0) {
868                 dirty.offset(0, -mCurScrollY);
869             }
870             if (mTranslator != null) {
871                 mTranslator.translateRectInAppWindowToScreen(dirty);
872             }
873             if (mAttachInfo.mScalingRequired) {
874                 dirty.inset(-1, -1);
875             }
876         }
877 
878         final Rect localDirty = mDirty;
879         if (!localDirty.isEmpty() && !localDirty.contains(dirty)) {
880             mAttachInfo.mSetIgnoreDirtyState = true;
881             mAttachInfo.mIgnoreDirtyState = true;
882         }
883 
884         // Add the new dirty rect to the current one
885         localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
886         // Intersect with the bounds of the window to skip
887         // updates that lie outside of the visible region
888         final float appScale = mAttachInfo.mApplicationScale;
889         final boolean intersected = localDirty.intersect(0, 0,
890                 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
891         if (!intersected) {
892             localDirty.setEmpty();
893         }
894         if (!mWillDrawSoon && (intersected || mIsAnimating)) {
895             scheduleTraversals();
896         }
897 
898         return null;
899     }
900 
setStopped(boolean stopped)901     void setStopped(boolean stopped) {
902         if (mStopped != stopped) {
903             mStopped = stopped;
904             if (!stopped) {
905                 scheduleTraversals();
906             }
907         }
908     }
909 
getParent()910     public ViewParent getParent() {
911         return null;
912     }
913 
getChildVisibleRect(View child, Rect r, android.graphics.Point offset)914     public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
915         if (child != mView) {
916             throw new RuntimeException("child is not mine, honest!");
917         }
918         // Note: don't apply scroll offset, because we want to know its
919         // visibility in the virtual canvas being given to the view hierarchy.
920         return r.intersect(0, 0, mWidth, mHeight);
921     }
922 
bringChildToFront(View child)923     public void bringChildToFront(View child) {
924     }
925 
getHostVisibility()926     int getHostVisibility() {
927         return mAppVisible ? mView.getVisibility() : View.GONE;
928     }
929 
disposeResizeBuffer()930     void disposeResizeBuffer() {
931         if (mResizeBuffer != null) {
932             mResizeBuffer.destroy();
933             mResizeBuffer = null;
934         }
935     }
936 
937     /**
938      * Add LayoutTransition to the list of transitions to be started in the next traversal.
939      * This list will be cleared after the transitions on the list are start()'ed. These
940      * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
941      * happens during the layout phase of traversal, which we want to complete before any of the
942      * animations are started (because those animations may side-effect properties that layout
943      * depends upon, like the bounding rectangles of the affected views). So we add the transition
944      * to the list and it is started just prior to starting the drawing phase of traversal.
945      *
946      * @param transition The LayoutTransition to be started on the next traversal.
947      *
948      * @hide
949      */
requestTransitionStart(LayoutTransition transition)950     public void requestTransitionStart(LayoutTransition transition) {
951         if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
952             if (mPendingTransitions == null) {
953                  mPendingTransitions = new ArrayList<LayoutTransition>();
954             }
955             mPendingTransitions.add(transition);
956         }
957     }
958 
scheduleTraversals()959     void scheduleTraversals() {
960         if (!mTraversalScheduled) {
961             mTraversalScheduled = true;
962             mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
963             mChoreographer.postCallback(
964                     Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
965             scheduleConsumeBatchedInput();
966         }
967     }
968 
unscheduleTraversals()969     void unscheduleTraversals() {
970         if (mTraversalScheduled) {
971             mTraversalScheduled = false;
972             mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
973             mChoreographer.removeCallbacks(
974                     Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
975         }
976     }
977 
doTraversal()978     void doTraversal() {
979         if (mTraversalScheduled) {
980             mTraversalScheduled = false;
981             mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
982 
983             if (mProfile) {
984                 Debug.startMethodTracing("ViewAncestor");
985             }
986 
987             Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
988             try {
989                 performTraversals();
990             } finally {
991                 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
992             }
993 
994             if (mProfile) {
995                 Debug.stopMethodTracing();
996                 mProfile = false;
997             }
998         }
999     }
1000 
applyKeepScreenOnFlag(WindowManager.LayoutParams params)1001     private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) {
1002         // Update window's global keep screen on flag: if a view has requested
1003         // that the screen be kept on, then it is always set; otherwise, it is
1004         // set to whatever the client last requested for the global state.
1005         if (mAttachInfo.mKeepScreenOn) {
1006             params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
1007         } else {
1008             params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
1009                     | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1010         }
1011     }
1012 
collectViewAttributes()1013     private boolean collectViewAttributes() {
1014         final View.AttachInfo attachInfo = mAttachInfo;
1015         if (attachInfo.mRecomputeGlobalAttributes) {
1016             //Log.i(TAG, "Computing view hierarchy attributes!");
1017             attachInfo.mRecomputeGlobalAttributes = false;
1018             boolean oldScreenOn = attachInfo.mKeepScreenOn;
1019             attachInfo.mKeepScreenOn = false;
1020             attachInfo.mSystemUiVisibility = 0;
1021             attachInfo.mHasSystemUiListeners = false;
1022             mView.dispatchCollectViewAttributes(attachInfo, 0);
1023             attachInfo.mSystemUiVisibility &= ~attachInfo.mDisabledSystemUiVisibility;
1024             WindowManager.LayoutParams params = mWindowAttributes;
1025             if (attachInfo.mKeepScreenOn != oldScreenOn
1026                     || attachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
1027                     || attachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
1028                 applyKeepScreenOnFlag(params);
1029                 params.subtreeSystemUiVisibility = attachInfo.mSystemUiVisibility;
1030                 params.hasSystemUiListeners = attachInfo.mHasSystemUiListeners;
1031                 mView.dispatchWindowSystemUiVisiblityChanged(attachInfo.mSystemUiVisibility);
1032                 return true;
1033             }
1034         }
1035         return false;
1036     }
1037 
measureHierarchy(final View host, final WindowManager.LayoutParams lp, final Resources res, final int desiredWindowWidth, final int desiredWindowHeight)1038     private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
1039             final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
1040         int childWidthMeasureSpec;
1041         int childHeightMeasureSpec;
1042         boolean windowSizeMayChange = false;
1043 
1044         if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
1045                 "Measuring " + host + " in display " + desiredWindowWidth
1046                 + "x" + desiredWindowHeight + "...");
1047 
1048         boolean goodMeasure = false;
1049         if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
1050             // On large screens, we don't want to allow dialogs to just
1051             // stretch to fill the entire width of the screen to display
1052             // one line of text.  First try doing the layout at a smaller
1053             // size to see if it will fit.
1054             final DisplayMetrics packageMetrics = res.getDisplayMetrics();
1055             res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
1056             int baseSize = 0;
1057             if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
1058                 baseSize = (int)mTmpValue.getDimension(packageMetrics);
1059             }
1060             if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize);
1061             if (baseSize != 0 && desiredWindowWidth > baseSize) {
1062                 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
1063                 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
1064                 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
1065                 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
1066                         + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1067                 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1068                     goodMeasure = true;
1069                 } else {
1070                     // Didn't fit in that size... try expanding a bit.
1071                     baseSize = (baseSize+desiredWindowWidth)/2;
1072                     if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
1073                             + baseSize);
1074                     childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
1075                     performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
1076                     if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
1077                             + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1078                     if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1079                         if (DEBUG_DIALOG) Log.v(TAG, "Good!");
1080                         goodMeasure = true;
1081                     }
1082                 }
1083             }
1084         }
1085 
1086         if (!goodMeasure) {
1087             childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
1088             childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
1089             performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
1090             if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
1091                 windowSizeMayChange = true;
1092             }
1093         }
1094 
1095         if (DBG) {
1096             System.out.println("======================================");
1097             System.out.println("performTraversals -- after measure");
1098             host.debug();
1099         }
1100 
1101         return windowSizeMayChange;
1102     }
1103 
performTraversals()1104     private void performTraversals() {
1105         // cache mView since it is used so much below...
1106         final View host = mView;
1107 
1108         if (DBG) {
1109             System.out.println("======================================");
1110             System.out.println("performTraversals");
1111             host.debug();
1112         }
1113 
1114         if (host == null || !mAdded)
1115             return;
1116 
1117         mIsInTraversal = true;
1118         mWillDrawSoon = true;
1119         boolean windowSizeMayChange = false;
1120         boolean newSurface = false;
1121         boolean surfaceChanged = false;
1122         WindowManager.LayoutParams lp = mWindowAttributes;
1123 
1124         int desiredWindowWidth;
1125         int desiredWindowHeight;
1126 
1127         final View.AttachInfo attachInfo = mAttachInfo;
1128 
1129         final int viewVisibility = getHostVisibility();
1130         boolean viewVisibilityChanged = mViewVisibility != viewVisibility
1131                 || mNewSurfaceNeeded;
1132 
1133         WindowManager.LayoutParams params = null;
1134         if (mWindowAttributesChanged) {
1135             mWindowAttributesChanged = false;
1136             surfaceChanged = true;
1137             params = lp;
1138         }
1139         CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
1140         if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
1141             params = lp;
1142             mFullRedrawNeeded = true;
1143             mLayoutRequested = true;
1144             if (mLastInCompatMode) {
1145                 params.flags &= ~WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
1146                 mLastInCompatMode = false;
1147             } else {
1148                 params.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
1149                 mLastInCompatMode = true;
1150             }
1151         }
1152 
1153         mWindowAttributesChangesFlag = 0;
1154 
1155         Rect frame = mWinFrame;
1156         if (mFirst) {
1157             mFullRedrawNeeded = true;
1158             mLayoutRequested = true;
1159 
1160             if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
1161                 // NOTE -- system code, won't try to do compat mode.
1162                 Point size = new Point();
1163                 mDisplay.getRealSize(size);
1164                 desiredWindowWidth = size.x;
1165                 desiredWindowHeight = size.y;
1166             } else {
1167                 DisplayMetrics packageMetrics =
1168                     mView.getContext().getResources().getDisplayMetrics();
1169                 desiredWindowWidth = packageMetrics.widthPixels;
1170                 desiredWindowHeight = packageMetrics.heightPixels;
1171             }
1172 
1173             // For the very first time, tell the view hierarchy that it
1174             // is attached to the window.  Note that at this point the surface
1175             // object is not initialized to its backing store, but soon it
1176             // will be (assuming the window is visible).
1177             attachInfo.mSurface = mSurface;
1178             // We used to use the following condition to choose 32 bits drawing caches:
1179             // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
1180             // However, windows are now always 32 bits by default, so choose 32 bits
1181             attachInfo.mUse32BitDrawingCache = true;
1182             attachInfo.mHasWindowFocus = false;
1183             attachInfo.mWindowVisibility = viewVisibility;
1184             attachInfo.mRecomputeGlobalAttributes = false;
1185             viewVisibilityChanged = false;
1186             mLastConfiguration.setTo(host.getResources().getConfiguration());
1187             mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
1188             // Set the layout direction if it has not been set before (inherit is the default)
1189             if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
1190                 host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
1191             }
1192             host.dispatchAttachedToWindow(attachInfo, 0);
1193             mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
1194             host.fitSystemWindows(mFitSystemWindowsInsets);
1195             //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
1196 
1197         } else {
1198             desiredWindowWidth = frame.width();
1199             desiredWindowHeight = frame.height();
1200             if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
1201                 if (DEBUG_ORIENTATION) Log.v(TAG,
1202                         "View " + host + " resized to: " + frame);
1203                 mFullRedrawNeeded = true;
1204                 mLayoutRequested = true;
1205                 windowSizeMayChange = true;
1206             }
1207         }
1208 
1209         if (viewVisibilityChanged) {
1210             attachInfo.mWindowVisibility = viewVisibility;
1211             host.dispatchWindowVisibilityChanged(viewVisibility);
1212             if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
1213                 destroyHardwareResources();
1214             }
1215             if (viewVisibility == View.GONE) {
1216                 // After making a window gone, we will count it as being
1217                 // shown for the first time the next time it gets focus.
1218                 mHasHadWindowFocus = false;
1219             }
1220         }
1221 
1222         // Execute enqueued actions on every traversal in case a detached view enqueued an action
1223         getRunQueue().executeActions(attachInfo.mHandler);
1224 
1225         boolean insetsChanged = false;
1226 
1227         boolean layoutRequested = mLayoutRequested && !mStopped;
1228         if (layoutRequested) {
1229 
1230             final Resources res = mView.getContext().getResources();
1231 
1232             if (mFirst) {
1233                 // make sure touch mode code executes by setting cached value
1234                 // to opposite of the added touch mode.
1235                 mAttachInfo.mInTouchMode = !mAddedTouchMode;
1236                 ensureTouchModeLocally(mAddedTouchMode);
1237             } else {
1238                 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
1239                     insetsChanged = true;
1240                 }
1241                 if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
1242                     mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1243                     if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1244                             + mAttachInfo.mVisibleInsets);
1245                 }
1246                 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
1247                         || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
1248                     windowSizeMayChange = true;
1249 
1250                     if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
1251                         // NOTE -- system code, won't try to do compat mode.
1252                         Point size = new Point();
1253                         mDisplay.getRealSize(size);
1254                         desiredWindowWidth = size.x;
1255                         desiredWindowHeight = size.y;
1256                     } else {
1257                         DisplayMetrics packageMetrics = res.getDisplayMetrics();
1258                         desiredWindowWidth = packageMetrics.widthPixels;
1259                         desiredWindowHeight = packageMetrics.heightPixels;
1260                     }
1261                 }
1262             }
1263 
1264             // Ask host how big it wants to be
1265             windowSizeMayChange |= measureHierarchy(host, lp, res,
1266                     desiredWindowWidth, desiredWindowHeight);
1267         }
1268 
1269         if (collectViewAttributes()) {
1270             params = lp;
1271         }
1272         if (attachInfo.mForceReportNewAttributes) {
1273             attachInfo.mForceReportNewAttributes = false;
1274             params = lp;
1275         }
1276 
1277         if (mFirst || attachInfo.mViewVisibilityChanged) {
1278             attachInfo.mViewVisibilityChanged = false;
1279             int resizeMode = mSoftInputMode &
1280                     WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
1281             // If we are in auto resize mode, then we need to determine
1282             // what mode to use now.
1283             if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
1284                 final int N = attachInfo.mScrollContainers.size();
1285                 for (int i=0; i<N; i++) {
1286                     if (attachInfo.mScrollContainers.get(i).isShown()) {
1287                         resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
1288                     }
1289                 }
1290                 if (resizeMode == 0) {
1291                     resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
1292                 }
1293                 if ((lp.softInputMode &
1294                         WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
1295                     lp.softInputMode = (lp.softInputMode &
1296                             ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
1297                             resizeMode;
1298                     params = lp;
1299                 }
1300             }
1301         }
1302 
1303         if (params != null && (host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
1304             if (!PixelFormat.formatHasAlpha(params.format)) {
1305                 params.format = PixelFormat.TRANSLUCENT;
1306             }
1307         }
1308 
1309         if (mFitSystemWindowsRequested) {
1310             mFitSystemWindowsRequested = false;
1311             mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
1312             host.fitSystemWindows(mFitSystemWindowsInsets);
1313             if (mLayoutRequested) {
1314                 // Short-circuit catching a new layout request here, so
1315                 // we don't need to go through two layout passes when things
1316                 // change due to fitting system windows, which can happen a lot.
1317                 windowSizeMayChange |= measureHierarchy(host, lp,
1318                         mView.getContext().getResources(),
1319                         desiredWindowWidth, desiredWindowHeight);
1320             }
1321         }
1322 
1323         if (layoutRequested) {
1324             // Clear this now, so that if anything requests a layout in the
1325             // rest of this function we will catch it and re-run a full
1326             // layout pass.
1327             mLayoutRequested = false;
1328         }
1329 
1330         boolean windowShouldResize = layoutRequested && windowSizeMayChange
1331             && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
1332                 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
1333                         frame.width() < desiredWindowWidth && frame.width() != mWidth)
1334                 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
1335                         frame.height() < desiredWindowHeight && frame.height() != mHeight));
1336 
1337         final boolean computesInternalInsets =
1338                 attachInfo.mTreeObserver.hasComputeInternalInsetsListeners();
1339 
1340         boolean insetsPending = false;
1341         int relayoutResult = 0;
1342 
1343         if (mFirst || windowShouldResize || insetsChanged ||
1344                 viewVisibilityChanged || params != null) {
1345 
1346             if (viewVisibility == View.VISIBLE) {
1347                 // If this window is giving internal insets to the window
1348                 // manager, and it is being added or changing its visibility,
1349                 // then we want to first give the window manager "fake"
1350                 // insets to cause it to effectively ignore the content of
1351                 // the window during layout.  This avoids it briefly causing
1352                 // other windows to resize/move based on the raw frame of the
1353                 // window, waiting until we can finish laying out this window
1354                 // and get back to the window manager with the ultimately
1355                 // computed insets.
1356                 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
1357             }
1358 
1359             if (mSurfaceHolder != null) {
1360                 mSurfaceHolder.mSurfaceLock.lock();
1361                 mDrawingAllowed = true;
1362             }
1363 
1364             boolean hwInitialized = false;
1365             boolean contentInsetsChanged = false;
1366             boolean visibleInsetsChanged;
1367             boolean hadSurface = mSurface.isValid();
1368 
1369             try {
1370                 if (DEBUG_LAYOUT) {
1371                     Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" +
1372                             host.getMeasuredHeight() + ", params=" + params);
1373                 }
1374 
1375                 final int surfaceGenerationId = mSurface.getGenerationId();
1376                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
1377 
1378                 if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
1379                         + " content=" + mPendingContentInsets.toShortString()
1380                         + " visible=" + mPendingVisibleInsets.toShortString()
1381                         + " surface=" + mSurface);
1382 
1383                 if (mPendingConfiguration.seq != 0) {
1384                     if (DEBUG_CONFIGURATION) Log.v(TAG, "Visible with new config: "
1385                             + mPendingConfiguration);
1386                     updateConfiguration(mPendingConfiguration, !mFirst);
1387                     mPendingConfiguration.seq = 0;
1388                 }
1389 
1390                 contentInsetsChanged = !mPendingContentInsets.equals(
1391                         mAttachInfo.mContentInsets);
1392                 visibleInsetsChanged = !mPendingVisibleInsets.equals(
1393                         mAttachInfo.mVisibleInsets);
1394                 if (contentInsetsChanged) {
1395                     if (mWidth > 0 && mHeight > 0 && lp != null &&
1396                             ((lp.systemUiVisibility|lp.subtreeSystemUiVisibility)
1397                                     & View.SYSTEM_UI_LAYOUT_FLAGS) == 0 &&
1398                             mSurface != null && mSurface.isValid() &&
1399                             !mAttachInfo.mTurnOffWindowResizeAnim &&
1400                             mAttachInfo.mHardwareRenderer != null &&
1401                             mAttachInfo.mHardwareRenderer.isEnabled() &&
1402                             mAttachInfo.mHardwareRenderer.validate() &&
1403                             lp != null && !PixelFormat.formatHasAlpha(lp.format)) {
1404 
1405                         disposeResizeBuffer();
1406 
1407                         boolean completed = false;
1408                         HardwareCanvas hwRendererCanvas = mAttachInfo.mHardwareRenderer.getCanvas();
1409                         HardwareCanvas layerCanvas = null;
1410                         try {
1411                             if (mResizeBuffer == null) {
1412                                 mResizeBuffer = mAttachInfo.mHardwareRenderer.createHardwareLayer(
1413                                         mWidth, mHeight, false);
1414                             } else if (mResizeBuffer.getWidth() != mWidth ||
1415                                     mResizeBuffer.getHeight() != mHeight) {
1416                                 mResizeBuffer.resize(mWidth, mHeight);
1417                             }
1418                             // TODO: should handle create/resize failure
1419                             layerCanvas = mResizeBuffer.start(hwRendererCanvas);
1420                             layerCanvas.setViewport(mWidth, mHeight);
1421                             layerCanvas.onPreDraw(null);
1422                             final int restoreCount = layerCanvas.save();
1423 
1424                             int yoff;
1425                             final boolean scrolling = mScroller != null
1426                                     && mScroller.computeScrollOffset();
1427                             if (scrolling) {
1428                                 yoff = mScroller.getCurrY();
1429                                 mScroller.abortAnimation();
1430                             } else {
1431                                 yoff = mScrollY;
1432                             }
1433 
1434                             layerCanvas.translate(0, -yoff);
1435                             if (mTranslator != null) {
1436                                 mTranslator.translateCanvas(layerCanvas);
1437                             }
1438 
1439                             DisplayList displayList = mView.mDisplayList;
1440                             if (displayList != null) {
1441                                 layerCanvas.drawDisplayList(displayList, null,
1442                                         DisplayList.FLAG_CLIP_CHILDREN);
1443                             } else {
1444                                 mView.draw(layerCanvas);
1445                             }
1446 
1447                             drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
1448 
1449                             mResizeBufferStartTime = SystemClock.uptimeMillis();
1450                             mResizeBufferDuration = mView.getResources().getInteger(
1451                                     com.android.internal.R.integer.config_mediumAnimTime);
1452                             completed = true;
1453 
1454                             layerCanvas.restoreToCount(restoreCount);
1455                         } catch (OutOfMemoryError e) {
1456                             Log.w(TAG, "Not enough memory for content change anim buffer", e);
1457                         } finally {
1458                             if (layerCanvas != null) {
1459                                 layerCanvas.onPostDraw();
1460                             }
1461                             if (mResizeBuffer != null) {
1462                                 mResizeBuffer.end(hwRendererCanvas);
1463                                 if (!completed) {
1464                                     mResizeBuffer.destroy();
1465                                     mResizeBuffer = null;
1466                                 }
1467                             }
1468                         }
1469                     }
1470                     mAttachInfo.mContentInsets.set(mPendingContentInsets);
1471                     if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
1472                             + mAttachInfo.mContentInsets);
1473                 }
1474                 if (contentInsetsChanged || mLastSystemUiVisibility !=
1475                         mAttachInfo.mSystemUiVisibility || mFitSystemWindowsRequested) {
1476                     mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
1477                     mFitSystemWindowsRequested = false;
1478                     mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
1479                     host.fitSystemWindows(mFitSystemWindowsInsets);
1480                 }
1481                 if (visibleInsetsChanged) {
1482                     mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1483                     if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1484                             + mAttachInfo.mVisibleInsets);
1485                 }
1486 
1487                 if (!hadSurface) {
1488                     if (mSurface.isValid()) {
1489                         // If we are creating a new surface, then we need to
1490                         // completely redraw it.  Also, when we get to the
1491                         // point of drawing it we will hold off and schedule
1492                         // a new traversal instead.  This is so we can tell the
1493                         // window manager about all of the windows being displayed
1494                         // before actually drawing them, so it can display then
1495                         // all at once.
1496                         newSurface = true;
1497                         mFullRedrawNeeded = true;
1498                         mPreviousTransparentRegion.setEmpty();
1499 
1500                         if (mAttachInfo.mHardwareRenderer != null) {
1501                             try {
1502                                 hwInitialized = mAttachInfo.mHardwareRenderer.initialize(
1503                                         mHolder.getSurface());
1504                             } catch (Surface.OutOfResourcesException e) {
1505                                 Log.e(TAG, "OutOfResourcesException initializing HW surface", e);
1506                                 try {
1507                                     if (!mWindowSession.outOfMemory(mWindow) &&
1508                                             Process.myUid() != Process.SYSTEM_UID) {
1509                                         Slog.w(TAG, "No processes killed for memory; killing self");
1510                                         Process.killProcess(Process.myPid());
1511                                     }
1512                                 } catch (RemoteException ex) {
1513                                 }
1514                                 mLayoutRequested = true;    // ask wm for a new surface next time.
1515                                 return;
1516                             }
1517                         }
1518                     }
1519                 } else if (!mSurface.isValid()) {
1520                     // If the surface has been removed, then reset the scroll
1521                     // positions.
1522                     mLastScrolledFocus = null;
1523                     mScrollY = mCurScrollY = 0;
1524                     if (mScroller != null) {
1525                         mScroller.abortAnimation();
1526                     }
1527                     disposeResizeBuffer();
1528                     // Our surface is gone
1529                     if (mAttachInfo.mHardwareRenderer != null &&
1530                             mAttachInfo.mHardwareRenderer.isEnabled()) {
1531                         mAttachInfo.mHardwareRenderer.destroy(true);
1532                     }
1533                 } else if (surfaceGenerationId != mSurface.getGenerationId() &&
1534                         mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
1535                     mFullRedrawNeeded = true;
1536                     try {
1537                         mAttachInfo.mHardwareRenderer.updateSurface(mHolder.getSurface());
1538                     } catch (Surface.OutOfResourcesException e) {
1539                         Log.e(TAG, "OutOfResourcesException updating HW surface", e);
1540                         try {
1541                             if (!mWindowSession.outOfMemory(mWindow)) {
1542                                 Slog.w(TAG, "No processes killed for memory; killing self");
1543                                 Process.killProcess(Process.myPid());
1544                             }
1545                         } catch (RemoteException ex) {
1546                         }
1547                         mLayoutRequested = true;    // ask wm for a new surface next time.
1548                         return;
1549                     }
1550                 }
1551             } catch (RemoteException e) {
1552             }
1553 
1554             if (DEBUG_ORIENTATION) Log.v(
1555                     TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
1556 
1557             attachInfo.mWindowLeft = frame.left;
1558             attachInfo.mWindowTop = frame.top;
1559 
1560             // !!FIXME!! This next section handles the case where we did not get the
1561             // window size we asked for. We should avoid this by getting a maximum size from
1562             // the window session beforehand.
1563             if (mWidth != frame.width() || mHeight != frame.height()) {
1564                 mWidth = frame.width();
1565                 mHeight = frame.height();
1566             }
1567 
1568             if (mSurfaceHolder != null) {
1569                 // The app owns the surface; tell it about what is going on.
1570                 if (mSurface.isValid()) {
1571                     // XXX .copyFrom() doesn't work!
1572                     //mSurfaceHolder.mSurface.copyFrom(mSurface);
1573                     mSurfaceHolder.mSurface = mSurface;
1574                 }
1575                 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
1576                 mSurfaceHolder.mSurfaceLock.unlock();
1577                 if (mSurface.isValid()) {
1578                     if (!hadSurface) {
1579                         mSurfaceHolder.ungetCallbacks();
1580 
1581                         mIsCreating = true;
1582                         mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder);
1583                         SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1584                         if (callbacks != null) {
1585                             for (SurfaceHolder.Callback c : callbacks) {
1586                                 c.surfaceCreated(mSurfaceHolder);
1587                             }
1588                         }
1589                         surfaceChanged = true;
1590                     }
1591                     if (surfaceChanged) {
1592                         mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
1593                                 lp.format, mWidth, mHeight);
1594                         SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1595                         if (callbacks != null) {
1596                             for (SurfaceHolder.Callback c : callbacks) {
1597                                 c.surfaceChanged(mSurfaceHolder, lp.format,
1598                                         mWidth, mHeight);
1599                             }
1600                         }
1601                     }
1602                     mIsCreating = false;
1603                 } else if (hadSurface) {
1604                     mSurfaceHolder.ungetCallbacks();
1605                     SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1606                     mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
1607                     if (callbacks != null) {
1608                         for (SurfaceHolder.Callback c : callbacks) {
1609                             c.surfaceDestroyed(mSurfaceHolder);
1610                         }
1611                     }
1612                     mSurfaceHolder.mSurfaceLock.lock();
1613                     try {
1614                         mSurfaceHolder.mSurface = new Surface();
1615                     } finally {
1616                         mSurfaceHolder.mSurfaceLock.unlock();
1617                     }
1618                 }
1619             }
1620 
1621             if (mAttachInfo.mHardwareRenderer != null &&
1622                     mAttachInfo.mHardwareRenderer.isEnabled()) {
1623                 if (hwInitialized || windowShouldResize ||
1624                         mWidth != mAttachInfo.mHardwareRenderer.getWidth() ||
1625                         mHeight != mAttachInfo.mHardwareRenderer.getHeight()) {
1626                     mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight);
1627                     if (!hwInitialized) {
1628                         mAttachInfo.mHardwareRenderer.invalidate(mHolder.getSurface());
1629                         mFullRedrawNeeded = true;
1630                     }
1631                 }
1632             }
1633 
1634             if (!mStopped) {
1635                 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
1636                         (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
1637                 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
1638                         || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
1639                     int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
1640                     int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
1641 
1642                     if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed!  mWidth="
1643                             + mWidth + " measuredWidth=" + host.getMeasuredWidth()
1644                             + " mHeight=" + mHeight
1645                             + " measuredHeight=" + host.getMeasuredHeight()
1646                             + " coveredInsetsChanged=" + contentInsetsChanged);
1647 
1648                      // Ask host how big it wants to be
1649                     performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
1650 
1651                     // Implementation of weights from WindowManager.LayoutParams
1652                     // We just grow the dimensions as needed and re-measure if
1653                     // needs be
1654                     int width = host.getMeasuredWidth();
1655                     int height = host.getMeasuredHeight();
1656                     boolean measureAgain = false;
1657 
1658                     if (lp.horizontalWeight > 0.0f) {
1659                         width += (int) ((mWidth - width) * lp.horizontalWeight);
1660                         childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
1661                                 MeasureSpec.EXACTLY);
1662                         measureAgain = true;
1663                     }
1664                     if (lp.verticalWeight > 0.0f) {
1665                         height += (int) ((mHeight - height) * lp.verticalWeight);
1666                         childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
1667                                 MeasureSpec.EXACTLY);
1668                         measureAgain = true;
1669                     }
1670 
1671                     if (measureAgain) {
1672                         if (DEBUG_LAYOUT) Log.v(TAG,
1673                                 "And hey let's measure once more: width=" + width
1674                                 + " height=" + height);
1675                         performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
1676                     }
1677 
1678                     layoutRequested = true;
1679                 }
1680             }
1681         } else {
1682             // Not the first pass and no window/insets/visibility change but the window
1683             // may have moved and we need check that and if so to update the left and right
1684             // in the attach info. We translate only the window frame since on window move
1685             // the window manager tells us only for the new frame but the insets are the
1686             // same and we do not want to translate them more than once.
1687 
1688             // TODO: Well, we are checking whether the frame has changed similarly
1689             // to how this is done for the insets. This is however incorrect since
1690             // the insets and the frame are translated. For example, the old frame
1691             // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new
1692             // reported frame is (2, 2 - 2, 2) which implies no change but this is not
1693             // true since we are comparing a not translated value to a translated one.
1694             // This scenario is rare but we may want to fix that.
1695 
1696             final boolean windowMoved = (attachInfo.mWindowLeft != frame.left
1697                     || attachInfo.mWindowTop != frame.top);
1698             if (windowMoved) {
1699                 if (mTranslator != null) {
1700                     mTranslator.translateRectInScreenToAppWinFrame(frame);
1701                 }
1702                 attachInfo.mWindowLeft = frame.left;
1703                 attachInfo.mWindowTop = frame.top;
1704             }
1705         }
1706 
1707         final boolean didLayout = layoutRequested && !mStopped;
1708         boolean triggerGlobalLayoutListener = didLayout
1709                 || attachInfo.mRecomputeGlobalAttributes;
1710         if (didLayout) {
1711             performLayout();
1712 
1713             // By this point all views have been sized and positionned
1714             // We can compute the transparent area
1715 
1716             if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
1717                 // start out transparent
1718                 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
1719                 host.getLocationInWindow(mTmpLocation);
1720                 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
1721                         mTmpLocation[0] + host.mRight - host.mLeft,
1722                         mTmpLocation[1] + host.mBottom - host.mTop);
1723 
1724                 host.gatherTransparentRegion(mTransparentRegion);
1725                 if (mTranslator != null) {
1726                     mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
1727                 }
1728 
1729                 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
1730                     mPreviousTransparentRegion.set(mTransparentRegion);
1731                     // reconfigure window manager
1732                     try {
1733                         mWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
1734                     } catch (RemoteException e) {
1735                     }
1736                 }
1737             }
1738 
1739             if (DBG) {
1740                 System.out.println("======================================");
1741                 System.out.println("performTraversals -- after setFrame");
1742                 host.debug();
1743             }
1744         }
1745 
1746         if (triggerGlobalLayoutListener) {
1747             attachInfo.mRecomputeGlobalAttributes = false;
1748             attachInfo.mTreeObserver.dispatchOnGlobalLayout();
1749 
1750             if (AccessibilityManager.getInstance(host.mContext).isEnabled()) {
1751                 postSendWindowContentChangedCallback(mView);
1752             }
1753         }
1754 
1755         if (computesInternalInsets) {
1756             // Clear the original insets.
1757             final ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets;
1758             insets.reset();
1759 
1760             // Compute new insets in place.
1761             attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
1762 
1763             // Tell the window manager.
1764             if (insetsPending || !mLastGivenInsets.equals(insets)) {
1765                 mLastGivenInsets.set(insets);
1766 
1767                 // Translate insets to screen coordinates if needed.
1768                 final Rect contentInsets;
1769                 final Rect visibleInsets;
1770                 final Region touchableRegion;
1771                 if (mTranslator != null) {
1772                     contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
1773                     visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
1774                     touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
1775                 } else {
1776                     contentInsets = insets.contentInsets;
1777                     visibleInsets = insets.visibleInsets;
1778                     touchableRegion = insets.touchableRegion;
1779                 }
1780 
1781                 try {
1782                     mWindowSession.setInsets(mWindow, insets.mTouchableInsets,
1783                             contentInsets, visibleInsets, touchableRegion);
1784                 } catch (RemoteException e) {
1785                 }
1786             }
1787         }
1788 
1789         boolean skipDraw = false;
1790 
1791         if (mFirst) {
1792             // handle first focus request
1793             if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()="
1794                     + mView.hasFocus());
1795             if (mView != null) {
1796                 if (!mView.hasFocus()) {
1797                     mView.requestFocus(View.FOCUS_FORWARD);
1798                     mFocusedView = mRealFocusedView = mView.findFocus();
1799                     if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view="
1800                             + mFocusedView);
1801                 } else {
1802                     mRealFocusedView = mView.findFocus();
1803                     if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view="
1804                             + mRealFocusedView);
1805                 }
1806             }
1807             if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_ANIMATING) != 0) {
1808                 // The first time we relayout the window, if the system is
1809                 // doing window animations, we want to hold of on any future
1810                 // draws until the animation is done.
1811                 mWindowsAnimating = true;
1812             }
1813         } else if (mWindowsAnimating) {
1814             skipDraw = true;
1815         }
1816 
1817         mFirst = false;
1818         mWillDrawSoon = false;
1819         mNewSurfaceNeeded = false;
1820         mViewVisibility = viewVisibility;
1821 
1822         if (mAttachInfo.mHasWindowFocus) {
1823             final boolean imTarget = WindowManager.LayoutParams
1824                     .mayUseInputMethod(mWindowAttributes.flags);
1825             if (imTarget != mLastWasImTarget) {
1826                 mLastWasImTarget = imTarget;
1827                 InputMethodManager imm = InputMethodManager.peekInstance();
1828                 if (imm != null && imTarget) {
1829                     imm.startGettingWindowFocus(mView);
1830                     imm.onWindowFocus(mView, mView.findFocus(),
1831                             mWindowAttributes.softInputMode,
1832                             !mHasHadWindowFocus, mWindowAttributes.flags);
1833                 }
1834             }
1835         }
1836 
1837         // Remember if we must report the next draw.
1838         if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
1839             mReportNextDraw = true;
1840         }
1841 
1842         boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw() ||
1843                 viewVisibility != View.VISIBLE;
1844 
1845         if (!cancelDraw && !newSurface) {
1846             if (!skipDraw || mReportNextDraw) {
1847                 if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
1848                     for (int i = 0; i < mPendingTransitions.size(); ++i) {
1849                         mPendingTransitions.get(i).startChangingAnimations();
1850                     }
1851                     mPendingTransitions.clear();
1852                 }
1853 
1854                 performDraw();
1855             }
1856         } else {
1857             if (viewVisibility == View.VISIBLE) {
1858                 // Try again
1859                 scheduleTraversals();
1860             } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
1861                 for (int i = 0; i < mPendingTransitions.size(); ++i) {
1862                     mPendingTransitions.get(i).endChangingAnimations();
1863                 }
1864                 mPendingTransitions.clear();
1865             }
1866         }
1867 
1868         mIsInTraversal = false;
1869     }
1870 
performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec)1871     private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
1872         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
1873         try {
1874             mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
1875         } finally {
1876             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1877         }
1878     }
1879 
performLayout()1880     private void performLayout() {
1881         mLayoutRequested = false;
1882         mScrollMayChange = true;
1883 
1884         final View host = mView;
1885         if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
1886             Log.v(TAG, "Laying out " + host + " to (" +
1887                     host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
1888         }
1889 
1890         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
1891         try {
1892             host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
1893         } finally {
1894             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1895         }
1896     }
1897 
requestTransparentRegion(View child)1898     public void requestTransparentRegion(View child) {
1899         // the test below should not fail unless someone is messing with us
1900         checkThread();
1901         if (mView == child) {
1902             mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
1903             // Need to make sure we re-evaluate the window attributes next
1904             // time around, to ensure the window has the correct format.
1905             mWindowAttributesChanged = true;
1906             mWindowAttributesChangesFlag = 0;
1907             requestLayout();
1908         }
1909     }
1910 
1911     /**
1912      * Figures out the measure spec for the root view in a window based on it's
1913      * layout params.
1914      *
1915      * @param windowSize
1916      *            The available width or height of the window
1917      *
1918      * @param rootDimension
1919      *            The layout params for one dimension (width or height) of the
1920      *            window.
1921      *
1922      * @return The measure spec to use to measure the root view.
1923      */
getRootMeasureSpec(int windowSize, int rootDimension)1924     private static int getRootMeasureSpec(int windowSize, int rootDimension) {
1925         int measureSpec;
1926         switch (rootDimension) {
1927 
1928         case ViewGroup.LayoutParams.MATCH_PARENT:
1929             // Window can't resize. Force root view to be windowSize.
1930             measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
1931             break;
1932         case ViewGroup.LayoutParams.WRAP_CONTENT:
1933             // Window can resize. Set max size for root view.
1934             measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
1935             break;
1936         default:
1937             // Window wants to be an exact size. Force root view to be that size.
1938             measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
1939             break;
1940         }
1941         return measureSpec;
1942     }
1943 
1944     int mHardwareYOffset;
1945     int mResizeAlpha;
1946     final Paint mResizePaint = new Paint();
1947 
onHardwarePreDraw(HardwareCanvas canvas)1948     public void onHardwarePreDraw(HardwareCanvas canvas) {
1949         canvas.translate(0, -mHardwareYOffset);
1950     }
1951 
onHardwarePostDraw(HardwareCanvas canvas)1952     public void onHardwarePostDraw(HardwareCanvas canvas) {
1953         if (mResizeBuffer != null) {
1954             mResizePaint.setAlpha(mResizeAlpha);
1955             canvas.drawHardwareLayer(mResizeBuffer, 0.0f, mHardwareYOffset, mResizePaint);
1956         }
1957         drawAccessibilityFocusedDrawableIfNeeded(canvas);
1958     }
1959 
1960     /**
1961      * @hide
1962      */
outputDisplayList(View view)1963     void outputDisplayList(View view) {
1964         if (mAttachInfo != null && mAttachInfo.mHardwareCanvas != null) {
1965             DisplayList displayList = view.getDisplayList();
1966             if (displayList != null) {
1967                 mAttachInfo.mHardwareCanvas.outputDisplayList(displayList);
1968             }
1969         }
1970     }
1971 
1972     /**
1973      * @see #PROPERTY_PROFILE_RENDERING
1974      */
profileRendering(boolean enabled)1975     private void profileRendering(boolean enabled) {
1976         if (mProfileRendering) {
1977             mRenderProfilingEnabled = enabled;
1978             if (mRenderProfiler == null) {
1979                 mRenderProfiler = new Thread(new Runnable() {
1980                     @Override
1981                     public void run() {
1982                         Log.d(TAG, "Starting profiling thread");
1983                         while (mRenderProfilingEnabled) {
1984                             mAttachInfo.mHandler.post(new Runnable() {
1985                                 @Override
1986                                 public void run() {
1987                                     mDirty.set(0, 0, mWidth, mHeight);
1988                                     scheduleTraversals();
1989                                 }
1990                             });
1991                             try {
1992                                 // TODO: This should use vsync when we get an API
1993                                 Thread.sleep(15);
1994                             } catch (InterruptedException e) {
1995                                 Log.d(TAG, "Exiting profiling thread");
1996                             }
1997                         }
1998                     }
1999                 }, "Rendering Profiler");
2000                 mRenderProfiler.start();
2001             } else {
2002                 mRenderProfiler.interrupt();
2003                 mRenderProfiler = null;
2004             }
2005         }
2006     }
2007 
2008     /**
2009      * Called from draw() when DEBUG_FPS is enabled
2010      */
trackFPS()2011     private void trackFPS() {
2012         // Tracks frames per second drawn. First value in a series of draws may be bogus
2013         // because it down not account for the intervening idle time
2014         long nowTime = System.currentTimeMillis();
2015         if (mFpsStartTime < 0) {
2016             mFpsStartTime = mFpsPrevTime = nowTime;
2017             mFpsNumFrames = 0;
2018         } else {
2019             ++mFpsNumFrames;
2020             String thisHash = Integer.toHexString(System.identityHashCode(this));
2021             long frameTime = nowTime - mFpsPrevTime;
2022             long totalTime = nowTime - mFpsStartTime;
2023             Log.v(TAG, "0x" + thisHash + "\tFrame time:\t" + frameTime);
2024             mFpsPrevTime = nowTime;
2025             if (totalTime > 1000) {
2026                 float fps = (float) mFpsNumFrames * 1000 / totalTime;
2027                 Log.v(TAG, "0x" + thisHash + "\tFPS:\t" + fps);
2028                 mFpsStartTime = nowTime;
2029                 mFpsNumFrames = 0;
2030             }
2031         }
2032     }
2033 
performDraw()2034     private void performDraw() {
2035         if (!mAttachInfo.mScreenOn && !mReportNextDraw) {
2036             return;
2037         }
2038 
2039         final boolean fullRedrawNeeded = mFullRedrawNeeded;
2040         mFullRedrawNeeded = false;
2041 
2042         mIsDrawing = true;
2043         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
2044         try {
2045             draw(fullRedrawNeeded);
2046         } finally {
2047             mIsDrawing = false;
2048             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2049         }
2050 
2051         if (mReportNextDraw) {
2052             mReportNextDraw = false;
2053 
2054             if (LOCAL_LOGV) {
2055                 Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
2056             }
2057             if (mSurfaceHolder != null && mSurface.isValid()) {
2058                 mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
2059                 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
2060                 if (callbacks != null) {
2061                     for (SurfaceHolder.Callback c : callbacks) {
2062                         if (c instanceof SurfaceHolder.Callback2) {
2063                             ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
2064                                     mSurfaceHolder);
2065                         }
2066                     }
2067                 }
2068             }
2069             try {
2070                 mWindowSession.finishDrawing(mWindow);
2071             } catch (RemoteException e) {
2072             }
2073         }
2074     }
2075 
draw(boolean fullRedrawNeeded)2076     private void draw(boolean fullRedrawNeeded) {
2077         Surface surface = mSurface;
2078         if (surface == null || !surface.isValid()) {
2079             return;
2080         }
2081 
2082         if (DEBUG_FPS) {
2083             trackFPS();
2084         }
2085 
2086         if (!sFirstDrawComplete) {
2087             synchronized (sFirstDrawHandlers) {
2088                 sFirstDrawComplete = true;
2089                 final int count = sFirstDrawHandlers.size();
2090                 for (int i = 0; i< count; i++) {
2091                     mHandler.post(sFirstDrawHandlers.get(i));
2092                 }
2093             }
2094         }
2095 
2096         scrollToRectOrFocus(null, false);
2097 
2098         final AttachInfo attachInfo = mAttachInfo;
2099         if (attachInfo.mViewScrollChanged) {
2100             attachInfo.mViewScrollChanged = false;
2101             attachInfo.mTreeObserver.dispatchOnScrollChanged();
2102         }
2103 
2104         int yoff;
2105         boolean animating = mScroller != null && mScroller.computeScrollOffset();
2106         if (animating) {
2107             yoff = mScroller.getCurrY();
2108         } else {
2109             yoff = mScrollY;
2110         }
2111         if (mCurScrollY != yoff) {
2112             mCurScrollY = yoff;
2113             fullRedrawNeeded = true;
2114         }
2115 
2116         final float appScale = attachInfo.mApplicationScale;
2117         final boolean scalingRequired = attachInfo.mScalingRequired;
2118 
2119         int resizeAlpha = 0;
2120         if (mResizeBuffer != null) {
2121             long deltaTime = SystemClock.uptimeMillis() - mResizeBufferStartTime;
2122             if (deltaTime < mResizeBufferDuration) {
2123                 float amt = deltaTime/(float) mResizeBufferDuration;
2124                 amt = mResizeInterpolator.getInterpolation(amt);
2125                 animating = true;
2126                 resizeAlpha = 255 - (int)(amt*255);
2127             } else {
2128                 disposeResizeBuffer();
2129             }
2130         }
2131 
2132         final Rect dirty = mDirty;
2133         if (mSurfaceHolder != null) {
2134             // The app owns the surface, we won't draw.
2135             dirty.setEmpty();
2136             if (animating) {
2137                 if (mScroller != null) {
2138                     mScroller.abortAnimation();
2139                 }
2140                 disposeResizeBuffer();
2141             }
2142             return;
2143         }
2144 
2145         if (fullRedrawNeeded) {
2146             attachInfo.mIgnoreDirtyState = true;
2147             dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
2148         }
2149 
2150         if (DEBUG_ORIENTATION || DEBUG_DRAW) {
2151             Log.v(TAG, "Draw " + mView + "/"
2152                     + mWindowAttributes.getTitle()
2153                     + ": dirty={" + dirty.left + "," + dirty.top
2154                     + "," + dirty.right + "," + dirty.bottom + "} surface="
2155                     + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
2156                     appScale + ", width=" + mWidth + ", height=" + mHeight);
2157         }
2158 
2159         attachInfo.mTreeObserver.dispatchOnDraw();
2160 
2161         if (!dirty.isEmpty() || mIsAnimating) {
2162             if (attachInfo.mHardwareRenderer != null && attachInfo.mHardwareRenderer.isEnabled()) {
2163                 // Draw with hardware renderer.
2164                 mIsAnimating = false;
2165                 mHardwareYOffset = yoff;
2166                 mResizeAlpha = resizeAlpha;
2167 
2168                 mCurrentDirty.set(dirty);
2169                 mCurrentDirty.union(mPreviousDirty);
2170                 mPreviousDirty.set(dirty);
2171                 dirty.setEmpty();
2172 
2173                 if (attachInfo.mHardwareRenderer.draw(mView, attachInfo, this,
2174                         animating ? null : mCurrentDirty)) {
2175                     mPreviousDirty.set(0, 0, mWidth, mHeight);
2176                 }
2177             } else if (!drawSoftware(surface, attachInfo, yoff, scalingRequired, dirty)) {
2178                 return;
2179             }
2180         }
2181 
2182         if (animating) {
2183             mFullRedrawNeeded = true;
2184             scheduleTraversals();
2185         }
2186     }
2187 
2188     /**
2189      * @return true if drawing was succesfull, false if an error occurred
2190      */
drawSoftware(Surface surface, AttachInfo attachInfo, int yoff, boolean scalingRequired, Rect dirty)2191     private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int yoff,
2192             boolean scalingRequired, Rect dirty) {
2193 
2194         // If we get here with a disabled & requested hardware renderer, something went
2195         // wrong (an invalidate posted right before we destroyed the hardware surface
2196         // for instance) so we should just bail out. Locking the surface with software
2197         // rendering at this point would lock it forever and prevent hardware renderer
2198         // from doing its job when it comes back.
2199         if (attachInfo.mHardwareRenderer != null && !attachInfo.mHardwareRenderer.isEnabled() &&
2200                 attachInfo.mHardwareRenderer.isRequested()) {
2201             mFullRedrawNeeded = true;
2202             scheduleTraversals();
2203             return false;
2204         }
2205 
2206         // Draw with software renderer.
2207         Canvas canvas;
2208         try {
2209             int left = dirty.left;
2210             int top = dirty.top;
2211             int right = dirty.right;
2212             int bottom = dirty.bottom;
2213 
2214             canvas = mSurface.lockCanvas(dirty);
2215 
2216             if (left != dirty.left || top != dirty.top || right != dirty.right ||
2217                     bottom != dirty.bottom) {
2218                 attachInfo.mIgnoreDirtyState = true;
2219             }
2220 
2221             // TODO: Do this in native
2222             canvas.setDensity(mDensity);
2223         } catch (Surface.OutOfResourcesException e) {
2224             Log.e(TAG, "OutOfResourcesException locking surface", e);
2225             try {
2226                 if (!mWindowSession.outOfMemory(mWindow)) {
2227                     Slog.w(TAG, "No processes killed for memory; killing self");
2228                     Process.killProcess(Process.myPid());
2229                 }
2230             } catch (RemoteException ex) {
2231             }
2232             mLayoutRequested = true;    // ask wm for a new surface next time.
2233             return false;
2234         } catch (IllegalArgumentException e) {
2235             Log.e(TAG, "Could not lock surface", e);
2236             // Don't assume this is due to out of memory, it could be
2237             // something else, and if it is something else then we could
2238             // kill stuff (or ourself) for no reason.
2239             mLayoutRequested = true;    // ask wm for a new surface next time.
2240             return false;
2241         }
2242 
2243         try {
2244             if (DEBUG_ORIENTATION || DEBUG_DRAW) {
2245                 Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
2246                         + canvas.getWidth() + ", h=" + canvas.getHeight());
2247                 //canvas.drawARGB(255, 255, 0, 0);
2248             }
2249 
2250             // If this bitmap's format includes an alpha channel, we
2251             // need to clear it before drawing so that the child will
2252             // properly re-composite its drawing on a transparent
2253             // background. This automatically respects the clip/dirty region
2254             // or
2255             // If we are applying an offset, we need to clear the area
2256             // where the offset doesn't appear to avoid having garbage
2257             // left in the blank areas.
2258             if (!canvas.isOpaque() || yoff != 0) {
2259                 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
2260             }
2261 
2262             dirty.setEmpty();
2263             mIsAnimating = false;
2264             attachInfo.mDrawingTime = SystemClock.uptimeMillis();
2265             mView.mPrivateFlags |= View.PFLAG_DRAWN;
2266 
2267             if (DEBUG_DRAW) {
2268                 Context cxt = mView.getContext();
2269                 Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
2270                         ", metrics=" + cxt.getResources().getDisplayMetrics() +
2271                         ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
2272             }
2273             try {
2274                 canvas.translate(0, -yoff);
2275                 if (mTranslator != null) {
2276                     mTranslator.translateCanvas(canvas);
2277                 }
2278                 canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
2279                 attachInfo.mSetIgnoreDirtyState = false;
2280 
2281                 mView.draw(canvas);
2282 
2283                 drawAccessibilityFocusedDrawableIfNeeded(canvas);
2284             } finally {
2285                 if (!attachInfo.mSetIgnoreDirtyState) {
2286                     // Only clear the flag if it was not set during the mView.draw() call
2287                     attachInfo.mIgnoreDirtyState = false;
2288                 }
2289             }
2290         } finally {
2291             try {
2292                 surface.unlockCanvasAndPost(canvas);
2293             } catch (IllegalArgumentException e) {
2294                 Log.e(TAG, "Could not unlock surface", e);
2295                 mLayoutRequested = true;    // ask wm for a new surface next time.
2296                 //noinspection ReturnInsideFinallyBlock
2297                 return false;
2298             }
2299 
2300             if (LOCAL_LOGV) {
2301                 Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
2302             }
2303         }
2304         return true;
2305     }
2306 
2307     /**
2308      * We want to draw a highlight around the current accessibility focused.
2309      * Since adding a style for all possible view is not a viable option we
2310      * have this specialized drawing method.
2311      *
2312      * Note: We are doing this here to be able to draw the highlight for
2313      *       virtual views in addition to real ones.
2314      *
2315      * @param canvas The canvas on which to draw.
2316      */
drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas)2317     private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
2318         AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
2319         if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
2320             return;
2321         }
2322         if (mAccessibilityFocusedHost == null || mAccessibilityFocusedHost.mAttachInfo == null) {
2323             return;
2324         }
2325         Drawable drawable = getAccessibilityFocusedDrawable();
2326         if (drawable == null) {
2327             return;
2328         }
2329         AccessibilityNodeProvider provider =
2330             mAccessibilityFocusedHost.getAccessibilityNodeProvider();
2331         Rect bounds = mView.mAttachInfo.mTmpInvalRect;
2332         if (provider == null) {
2333             mAccessibilityFocusedHost.getBoundsOnScreen(bounds);
2334         } else {
2335             if (mAccessibilityFocusedVirtualView == null) {
2336                 return;
2337             }
2338             mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
2339         }
2340         bounds.offset(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
2341         bounds.intersect(0, 0, mAttachInfo.mViewRootImpl.mWidth, mAttachInfo.mViewRootImpl.mHeight);
2342         drawable.setBounds(bounds);
2343         drawable.draw(canvas);
2344     }
2345 
getAccessibilityFocusedDrawable()2346     private Drawable getAccessibilityFocusedDrawable() {
2347         if (mAttachInfo != null) {
2348             // Lazily load the accessibility focus drawable.
2349             if (mAttachInfo.mAccessibilityFocusDrawable == null) {
2350                 TypedValue value = new TypedValue();
2351                 final boolean resolved = mView.mContext.getTheme().resolveAttribute(
2352                         R.attr.accessibilityFocusedDrawable, value, true);
2353                 if (resolved) {
2354                     mAttachInfo.mAccessibilityFocusDrawable =
2355                         mView.mContext.getResources().getDrawable(value.resourceId);
2356                 }
2357             }
2358             return mAttachInfo.mAccessibilityFocusDrawable;
2359         }
2360         return null;
2361     }
2362 
invalidateDisplayLists()2363     void invalidateDisplayLists() {
2364         final ArrayList<DisplayList> displayLists = mDisplayLists;
2365         final int count = displayLists.size();
2366 
2367         for (int i = 0; i < count; i++) {
2368             final DisplayList displayList = displayLists.get(i);
2369             displayList.invalidate();
2370             displayList.clear();
2371         }
2372 
2373         displayLists.clear();
2374     }
2375 
scrollToRectOrFocus(Rect rectangle, boolean immediate)2376     boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
2377         final View.AttachInfo attachInfo = mAttachInfo;
2378         final Rect ci = attachInfo.mContentInsets;
2379         final Rect vi = attachInfo.mVisibleInsets;
2380         int scrollY = 0;
2381         boolean handled = false;
2382 
2383         if (vi.left > ci.left || vi.top > ci.top
2384                 || vi.right > ci.right || vi.bottom > ci.bottom) {
2385             // We'll assume that we aren't going to change the scroll
2386             // offset, since we want to avoid that unless it is actually
2387             // going to make the focus visible...  otherwise we scroll
2388             // all over the place.
2389             scrollY = mScrollY;
2390             // We can be called for two different situations: during a draw,
2391             // to update the scroll position if the focus has changed (in which
2392             // case 'rectangle' is null), or in response to a
2393             // requestChildRectangleOnScreen() call (in which case 'rectangle'
2394             // is non-null and we just want to scroll to whatever that
2395             // rectangle is).
2396             View focus = mRealFocusedView;
2397 
2398             // When in touch mode, focus points to the previously focused view,
2399             // which may have been removed from the view hierarchy. The following
2400             // line checks whether the view is still in our hierarchy.
2401             if (focus == null || focus.mAttachInfo != mAttachInfo) {
2402                 mRealFocusedView = null;
2403                 return false;
2404             }
2405 
2406             if (focus != mLastScrolledFocus) {
2407                 // If the focus has changed, then ignore any requests to scroll
2408                 // to a rectangle; first we want to make sure the entire focus
2409                 // view is visible.
2410                 rectangle = null;
2411             }
2412             if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus
2413                     + " rectangle=" + rectangle + " ci=" + ci
2414                     + " vi=" + vi);
2415             if (focus == mLastScrolledFocus && !mScrollMayChange
2416                     && rectangle == null) {
2417                 // Optimization: if the focus hasn't changed since last
2418                 // time, and no layout has happened, then just leave things
2419                 // as they are.
2420                 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y="
2421                         + mScrollY + " vi=" + vi.toShortString());
2422             } else if (focus != null) {
2423                 // We need to determine if the currently focused view is
2424                 // within the visible part of the window and, if not, apply
2425                 // a pan so it can be seen.
2426                 mLastScrolledFocus = focus;
2427                 mScrollMayChange = false;
2428                 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?");
2429                 // Try to find the rectangle from the focus view.
2430                 if (focus.getGlobalVisibleRect(mVisRect, null)) {
2431                     if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w="
2432                             + mView.getWidth() + " h=" + mView.getHeight()
2433                             + " ci=" + ci.toShortString()
2434                             + " vi=" + vi.toShortString());
2435                     if (rectangle == null) {
2436                         focus.getFocusedRect(mTempRect);
2437                         if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus
2438                                 + ": focusRect=" + mTempRect.toShortString());
2439                         if (mView instanceof ViewGroup) {
2440                             ((ViewGroup) mView).offsetDescendantRectToMyCoords(
2441                                     focus, mTempRect);
2442                         }
2443                         if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2444                                 "Focus in window: focusRect="
2445                                 + mTempRect.toShortString()
2446                                 + " visRect=" + mVisRect.toShortString());
2447                     } else {
2448                         mTempRect.set(rectangle);
2449                         if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2450                                 "Request scroll to rect: "
2451                                 + mTempRect.toShortString()
2452                                 + " visRect=" + mVisRect.toShortString());
2453                     }
2454                     if (mTempRect.intersect(mVisRect)) {
2455                         if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2456                                 "Focus window visible rect: "
2457                                 + mTempRect.toShortString());
2458                         if (mTempRect.height() >
2459                                 (mView.getHeight()-vi.top-vi.bottom)) {
2460                             // If the focus simply is not going to fit, then
2461                             // best is probably just to leave things as-is.
2462                             if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2463                                     "Too tall; leaving scrollY=" + scrollY);
2464                         } else if ((mTempRect.top-scrollY) < vi.top) {
2465                             scrollY -= vi.top - (mTempRect.top-scrollY);
2466                             if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2467                                     "Top covered; scrollY=" + scrollY);
2468                         } else if ((mTempRect.bottom-scrollY)
2469                                 > (mView.getHeight()-vi.bottom)) {
2470                             scrollY += (mTempRect.bottom-scrollY)
2471                                     - (mView.getHeight()-vi.bottom);
2472                             if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2473                                     "Bottom covered; scrollY=" + scrollY);
2474                         }
2475                         handled = true;
2476                     }
2477                 }
2478             }
2479         }
2480 
2481         if (scrollY != mScrollY) {
2482             if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
2483                     + mScrollY + " , new=" + scrollY);
2484             if (!immediate && mResizeBuffer == null) {
2485                 if (mScroller == null) {
2486                     mScroller = new Scroller(mView.getContext());
2487                 }
2488                 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
2489             } else if (mScroller != null) {
2490                 mScroller.abortAnimation();
2491             }
2492             mScrollY = scrollY;
2493         }
2494 
2495         return handled;
2496     }
2497 
2498     /**
2499      * @hide
2500      */
getAccessibilityFocusedHost()2501     public View getAccessibilityFocusedHost() {
2502         return mAccessibilityFocusedHost;
2503     }
2504 
2505     /**
2506      * @hide
2507      */
getAccessibilityFocusedVirtualView()2508     public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
2509         return mAccessibilityFocusedVirtualView;
2510     }
2511 
setAccessibilityFocus(View view, AccessibilityNodeInfo node)2512     void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
2513         // If we have a virtual view with accessibility focus we need
2514         // to clear the focus and invalidate the virtual view bounds.
2515         if (mAccessibilityFocusedVirtualView != null) {
2516 
2517             AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
2518             View focusHost = mAccessibilityFocusedHost;
2519             focusHost.clearAccessibilityFocusNoCallbacks();
2520 
2521             // Wipe the state of the current accessibility focus since
2522             // the call into the provider to clear accessibility focus
2523             // will fire an accessibility event which will end up calling
2524             // this method and we want to have clean state when this
2525             // invocation happens.
2526             mAccessibilityFocusedHost = null;
2527             mAccessibilityFocusedVirtualView = null;
2528 
2529             AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
2530             if (provider != null) {
2531                 // Invalidate the area of the cleared accessibility focus.
2532                 focusNode.getBoundsInParent(mTempRect);
2533                 focusHost.invalidate(mTempRect);
2534                 // Clear accessibility focus in the virtual node.
2535                 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
2536                         focusNode.getSourceNodeId());
2537                 provider.performAction(virtualNodeId,
2538                         AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
2539             }
2540             focusNode.recycle();
2541         }
2542         if (mAccessibilityFocusedHost != null) {
2543             // Clear accessibility focus in the view.
2544             mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks();
2545         }
2546 
2547         // Set the new focus host and node.
2548         mAccessibilityFocusedHost = view;
2549         mAccessibilityFocusedVirtualView = node;
2550     }
2551 
requestChildFocus(View child, View focused)2552     public void requestChildFocus(View child, View focused) {
2553         checkThread();
2554 
2555         if (DEBUG_INPUT_RESIZE) {
2556             Log.v(TAG, "Request child focus: focus now " + focused);
2557         }
2558 
2559         mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mOldFocusedView, focused);
2560         scheduleTraversals();
2561 
2562         mFocusedView = mRealFocusedView = focused;
2563     }
2564 
clearChildFocus(View child)2565     public void clearChildFocus(View child) {
2566         checkThread();
2567 
2568         if (DEBUG_INPUT_RESIZE) {
2569             Log.v(TAG, "Clearing child focus");
2570         }
2571 
2572         mOldFocusedView = mFocusedView;
2573 
2574         // Invoke the listener only if there is no view to take focus
2575         if (focusSearch(null, View.FOCUS_FORWARD) == null) {
2576             mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mOldFocusedView, null);
2577         }
2578 
2579         mFocusedView = mRealFocusedView = null;
2580     }
2581 
2582     @Override
getParentForAccessibility()2583     public ViewParent getParentForAccessibility() {
2584         return null;
2585     }
2586 
focusableViewAvailable(View v)2587     public void focusableViewAvailable(View v) {
2588         checkThread();
2589         if (mView != null) {
2590             if (!mView.hasFocus()) {
2591                 v.requestFocus();
2592             } else {
2593                 // the one case where will transfer focus away from the current one
2594                 // is if the current view is a view group that prefers to give focus
2595                 // to its children first AND the view is a descendant of it.
2596                 mFocusedView = mView.findFocus();
2597                 boolean descendantsHaveDibsOnFocus =
2598                         (mFocusedView instanceof ViewGroup) &&
2599                             (((ViewGroup) mFocusedView).getDescendantFocusability() ==
2600                                     ViewGroup.FOCUS_AFTER_DESCENDANTS);
2601                 if (descendantsHaveDibsOnFocus && isViewDescendantOf(v, mFocusedView)) {
2602                     // If a view gets the focus, the listener will be invoked from requestChildFocus()
2603                     v.requestFocus();
2604                 }
2605             }
2606         }
2607     }
2608 
recomputeViewAttributes(View child)2609     public void recomputeViewAttributes(View child) {
2610         checkThread();
2611         if (mView == child) {
2612             mAttachInfo.mRecomputeGlobalAttributes = true;
2613             if (!mWillDrawSoon) {
2614                 scheduleTraversals();
2615             }
2616         }
2617     }
2618 
dispatchDetachedFromWindow()2619     void dispatchDetachedFromWindow() {
2620         if (mView != null && mView.mAttachInfo != null) {
2621             if (mAttachInfo.mHardwareRenderer != null &&
2622                     mAttachInfo.mHardwareRenderer.isEnabled()) {
2623                 mAttachInfo.mHardwareRenderer.validate();
2624             }
2625             mView.dispatchDetachedFromWindow();
2626         }
2627 
2628         mAccessibilityInteractionConnectionManager.ensureNoConnection();
2629         mAccessibilityManager.removeAccessibilityStateChangeListener(
2630                 mAccessibilityInteractionConnectionManager);
2631         removeSendWindowContentChangedCallback();
2632 
2633         destroyHardwareRenderer();
2634 
2635         setAccessibilityFocus(null, null);
2636 
2637         mView = null;
2638         mAttachInfo.mRootView = null;
2639         mAttachInfo.mSurface = null;
2640 
2641         mSurface.release();
2642 
2643         if (mInputQueueCallback != null && mInputQueue != null) {
2644             mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
2645             mInputQueueCallback = null;
2646             mInputQueue = null;
2647         } else if (mInputEventReceiver != null) {
2648             mInputEventReceiver.dispose();
2649             mInputEventReceiver = null;
2650         }
2651         try {
2652             mWindowSession.remove(mWindow);
2653         } catch (RemoteException e) {
2654         }
2655 
2656         // Dispose the input channel after removing the window so the Window Manager
2657         // doesn't interpret the input channel being closed as an abnormal termination.
2658         if (mInputChannel != null) {
2659             mInputChannel.dispose();
2660             mInputChannel = null;
2661         }
2662 
2663         unscheduleTraversals();
2664     }
2665 
updateConfiguration(Configuration config, boolean force)2666     void updateConfiguration(Configuration config, boolean force) {
2667         if (DEBUG_CONFIGURATION) Log.v(TAG,
2668                 "Applying new config to window "
2669                 + mWindowAttributes.getTitle()
2670                 + ": " + config);
2671 
2672         CompatibilityInfo ci = mCompatibilityInfo.getIfNeeded();
2673         if (ci != null) {
2674             config = new Configuration(config);
2675             ci.applyToConfiguration(mNoncompatDensity, config);
2676         }
2677 
2678         synchronized (sConfigCallbacks) {
2679             for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
2680                 sConfigCallbacks.get(i).onConfigurationChanged(config);
2681             }
2682         }
2683         if (mView != null) {
2684             // At this point the resources have been updated to
2685             // have the most recent config, whatever that is.  Use
2686             // the one in them which may be newer.
2687             config = mView.getResources().getConfiguration();
2688             if (force || mLastConfiguration.diff(config) != 0) {
2689                 final int lastLayoutDirection = mLastConfiguration.getLayoutDirection();
2690                 final int currentLayoutDirection = config.getLayoutDirection();
2691                 mLastConfiguration.setTo(config);
2692                 if (lastLayoutDirection != currentLayoutDirection &&
2693                         mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
2694                     mView.setLayoutDirection(currentLayoutDirection);
2695                 }
2696                 mView.dispatchConfigurationChanged(config);
2697             }
2698         }
2699     }
2700 
2701     /**
2702      * Return true if child is an ancestor of parent, (or equal to the parent).
2703      */
isViewDescendantOf(View child, View parent)2704     public static boolean isViewDescendantOf(View child, View parent) {
2705         if (child == parent) {
2706             return true;
2707         }
2708 
2709         final ViewParent theParent = child.getParent();
2710         return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
2711     }
2712 
forceLayout(View view)2713     private static void forceLayout(View view) {
2714         view.forceLayout();
2715         if (view instanceof ViewGroup) {
2716             ViewGroup group = (ViewGroup) view;
2717             final int count = group.getChildCount();
2718             for (int i = 0; i < count; i++) {
2719                 forceLayout(group.getChildAt(i));
2720             }
2721         }
2722     }
2723 
2724     private final static int MSG_INVALIDATE = 1;
2725     private final static int MSG_INVALIDATE_RECT = 2;
2726     private final static int MSG_DIE = 3;
2727     private final static int MSG_RESIZED = 4;
2728     private final static int MSG_RESIZED_REPORT = 5;
2729     private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
2730     private final static int MSG_DISPATCH_KEY = 7;
2731     private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
2732     private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
2733     private final static int MSG_IME_FINISHED_EVENT = 10;
2734     private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
2735     private final static int MSG_FINISH_INPUT_CONNECTION = 12;
2736     private final static int MSG_CHECK_FOCUS = 13;
2737     private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
2738     private final static int MSG_DISPATCH_DRAG_EVENT = 15;
2739     private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
2740     private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
2741     private final static int MSG_UPDATE_CONFIGURATION = 18;
2742     private final static int MSG_PROCESS_INPUT_EVENTS = 19;
2743     private final static int MSG_DISPATCH_SCREEN_STATE = 20;
2744     private final static int MSG_INVALIDATE_DISPLAY_LIST = 21;
2745     private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 22;
2746     private final static int MSG_DISPATCH_DONE_ANIMATING = 23;
2747     private final static int MSG_INVALIDATE_WORLD = 24;
2748     private final static int MSG_WINDOW_MOVED = 25;
2749 
2750     final class ViewRootHandler extends Handler {
2751         @Override
getMessageName(Message message)2752         public String getMessageName(Message message) {
2753             switch (message.what) {
2754                 case MSG_INVALIDATE:
2755                     return "MSG_INVALIDATE";
2756                 case MSG_INVALIDATE_RECT:
2757                     return "MSG_INVALIDATE_RECT";
2758                 case MSG_DIE:
2759                     return "MSG_DIE";
2760                 case MSG_RESIZED:
2761                     return "MSG_RESIZED";
2762                 case MSG_RESIZED_REPORT:
2763                     return "MSG_RESIZED_REPORT";
2764                 case MSG_WINDOW_FOCUS_CHANGED:
2765                     return "MSG_WINDOW_FOCUS_CHANGED";
2766                 case MSG_DISPATCH_KEY:
2767                     return "MSG_DISPATCH_KEY";
2768                 case MSG_DISPATCH_APP_VISIBILITY:
2769                     return "MSG_DISPATCH_APP_VISIBILITY";
2770                 case MSG_DISPATCH_GET_NEW_SURFACE:
2771                     return "MSG_DISPATCH_GET_NEW_SURFACE";
2772                 case MSG_IME_FINISHED_EVENT:
2773                     return "MSG_IME_FINISHED_EVENT";
2774                 case MSG_DISPATCH_KEY_FROM_IME:
2775                     return "MSG_DISPATCH_KEY_FROM_IME";
2776                 case MSG_FINISH_INPUT_CONNECTION:
2777                     return "MSG_FINISH_INPUT_CONNECTION";
2778                 case MSG_CHECK_FOCUS:
2779                     return "MSG_CHECK_FOCUS";
2780                 case MSG_CLOSE_SYSTEM_DIALOGS:
2781                     return "MSG_CLOSE_SYSTEM_DIALOGS";
2782                 case MSG_DISPATCH_DRAG_EVENT:
2783                     return "MSG_DISPATCH_DRAG_EVENT";
2784                 case MSG_DISPATCH_DRAG_LOCATION_EVENT:
2785                     return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
2786                 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
2787                     return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
2788                 case MSG_UPDATE_CONFIGURATION:
2789                     return "MSG_UPDATE_CONFIGURATION";
2790                 case MSG_PROCESS_INPUT_EVENTS:
2791                     return "MSG_PROCESS_INPUT_EVENTS";
2792                 case MSG_DISPATCH_SCREEN_STATE:
2793                     return "MSG_DISPATCH_SCREEN_STATE";
2794                 case MSG_INVALIDATE_DISPLAY_LIST:
2795                     return "MSG_INVALIDATE_DISPLAY_LIST";
2796                 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
2797                     return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
2798                 case MSG_DISPATCH_DONE_ANIMATING:
2799                     return "MSG_DISPATCH_DONE_ANIMATING";
2800                 case MSG_WINDOW_MOVED:
2801                     return "MSG_WINDOW_MOVED";
2802             }
2803             return super.getMessageName(message);
2804         }
2805 
2806         @Override
handleMessage(Message msg)2807         public void handleMessage(Message msg) {
2808             switch (msg.what) {
2809             case MSG_INVALIDATE:
2810                 ((View) msg.obj).invalidate();
2811                 break;
2812             case MSG_INVALIDATE_RECT:
2813                 final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
2814                 info.target.invalidate(info.left, info.top, info.right, info.bottom);
2815                 info.release();
2816                 break;
2817             case MSG_IME_FINISHED_EVENT:
2818                 handleImeFinishedEvent(msg.arg1, msg.arg2 != 0);
2819                 break;
2820             case MSG_PROCESS_INPUT_EVENTS:
2821                 mProcessInputEventsScheduled = false;
2822                 doProcessInputEvents();
2823                 break;
2824             case MSG_DISPATCH_APP_VISIBILITY:
2825                 handleAppVisibility(msg.arg1 != 0);
2826                 break;
2827             case MSG_DISPATCH_GET_NEW_SURFACE:
2828                 handleGetNewSurface();
2829                 break;
2830             case MSG_RESIZED: {
2831                 // Recycled in the fall through...
2832                 SomeArgs args = (SomeArgs) msg.obj;
2833                 if (mWinFrame.equals(args.arg1)
2834                         && mPendingContentInsets.equals(args.arg2)
2835                         && mPendingVisibleInsets.equals(args.arg3)
2836                         && args.arg4 == null) {
2837                     break;
2838                 }
2839                 } // fall through...
2840             case MSG_RESIZED_REPORT:
2841                 if (mAdded) {
2842                     SomeArgs args = (SomeArgs) msg.obj;
2843 
2844                     Configuration config = (Configuration) args.arg4;
2845                     if (config != null) {
2846                         updateConfiguration(config, false);
2847                     }
2848 
2849                     mWinFrame.set((Rect) args.arg1);
2850                     mPendingContentInsets.set((Rect) args.arg2);
2851                     mPendingVisibleInsets.set((Rect) args.arg3);
2852 
2853                     args.recycle();
2854 
2855                     if (msg.what == MSG_RESIZED_REPORT) {
2856                         mReportNextDraw = true;
2857                     }
2858 
2859                     if (mView != null) {
2860                         forceLayout(mView);
2861                     }
2862 
2863                     requestLayout();
2864                 }
2865                 break;
2866             case MSG_WINDOW_MOVED:
2867                 if (mAdded) {
2868                     final int w = mWinFrame.width();
2869                     final int h = mWinFrame.height();
2870                     final int l = msg.arg1;
2871                     final int t = msg.arg2;
2872                     mWinFrame.left = l;
2873                     mWinFrame.right = l + w;
2874                     mWinFrame.top = t;
2875                     mWinFrame.bottom = t + h;
2876 
2877                     if (mView != null) {
2878                         forceLayout(mView);
2879                     }
2880                     requestLayout();
2881                 }
2882                 break;
2883             case MSG_WINDOW_FOCUS_CHANGED: {
2884                 if (mAdded) {
2885                     boolean hasWindowFocus = msg.arg1 != 0;
2886                     mAttachInfo.mHasWindowFocus = hasWindowFocus;
2887 
2888                     profileRendering(hasWindowFocus);
2889 
2890                     if (hasWindowFocus) {
2891                         boolean inTouchMode = msg.arg2 != 0;
2892                         ensureTouchModeLocally(inTouchMode);
2893 
2894                         if (mAttachInfo.mHardwareRenderer != null &&
2895                                 mSurface != null && mSurface.isValid()) {
2896                             mFullRedrawNeeded = true;
2897                             try {
2898                                 if (mAttachInfo.mHardwareRenderer.initializeIfNeeded(
2899                                         mWidth, mHeight, mHolder.getSurface())) {
2900                                     mFullRedrawNeeded = true;
2901                                 }
2902                             } catch (Surface.OutOfResourcesException e) {
2903                                 Log.e(TAG, "OutOfResourcesException locking surface", e);
2904                                 try {
2905                                     if (!mWindowSession.outOfMemory(mWindow)) {
2906                                         Slog.w(TAG, "No processes killed for memory; killing self");
2907                                         Process.killProcess(Process.myPid());
2908                                     }
2909                                 } catch (RemoteException ex) {
2910                                 }
2911                                 // Retry in a bit.
2912                                 sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
2913                                 return;
2914                             }
2915                         }
2916                     }
2917 
2918                     mLastWasImTarget = WindowManager.LayoutParams
2919                             .mayUseInputMethod(mWindowAttributes.flags);
2920 
2921                     InputMethodManager imm = InputMethodManager.peekInstance();
2922                     if (mView != null) {
2923                         if (hasWindowFocus && imm != null && mLastWasImTarget) {
2924                             imm.startGettingWindowFocus(mView);
2925                         }
2926                         mAttachInfo.mKeyDispatchState.reset();
2927                         mView.dispatchWindowFocusChanged(hasWindowFocus);
2928                     }
2929 
2930                     // Note: must be done after the focus change callbacks,
2931                     // so all of the view state is set up correctly.
2932                     if (hasWindowFocus) {
2933                         if (imm != null && mLastWasImTarget) {
2934                             imm.onWindowFocus(mView, mView.findFocus(),
2935                                     mWindowAttributes.softInputMode,
2936                                     !mHasHadWindowFocus, mWindowAttributes.flags);
2937                         }
2938                         // Clear the forward bit.  We can just do this directly, since
2939                         // the window manager doesn't care about it.
2940                         mWindowAttributes.softInputMode &=
2941                                 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
2942                         ((WindowManager.LayoutParams)mView.getLayoutParams())
2943                                 .softInputMode &=
2944                                     ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
2945                         mHasHadWindowFocus = true;
2946                     }
2947 
2948                     setAccessibilityFocus(null, null);
2949 
2950                     if (mView != null && mAccessibilityManager.isEnabled()) {
2951                         if (hasWindowFocus) {
2952                             mView.sendAccessibilityEvent(
2953                                     AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
2954                         }
2955                     }
2956                 }
2957             } break;
2958             case MSG_DIE:
2959                 doDie();
2960                 break;
2961             case MSG_DISPATCH_KEY: {
2962                 KeyEvent event = (KeyEvent)msg.obj;
2963                 enqueueInputEvent(event, null, 0, true);
2964             } break;
2965             case MSG_DISPATCH_KEY_FROM_IME: {
2966                 if (LOCAL_LOGV) Log.v(
2967                     TAG, "Dispatching key "
2968                     + msg.obj + " from IME to " + mView);
2969                 KeyEvent event = (KeyEvent)msg.obj;
2970                 if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
2971                     // The IME is trying to say this event is from the
2972                     // system!  Bad bad bad!
2973                     //noinspection UnusedAssignment
2974                     event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
2975                 }
2976                 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
2977             } break;
2978             case MSG_FINISH_INPUT_CONNECTION: {
2979                 InputMethodManager imm = InputMethodManager.peekInstance();
2980                 if (imm != null) {
2981                     imm.reportFinishInputConnection((InputConnection)msg.obj);
2982                 }
2983             } break;
2984             case MSG_CHECK_FOCUS: {
2985                 InputMethodManager imm = InputMethodManager.peekInstance();
2986                 if (imm != null) {
2987                     imm.checkFocus();
2988                 }
2989             } break;
2990             case MSG_CLOSE_SYSTEM_DIALOGS: {
2991                 if (mView != null) {
2992                     mView.onCloseSystemDialogs((String)msg.obj);
2993                 }
2994             } break;
2995             case MSG_DISPATCH_DRAG_EVENT:
2996             case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
2997                 DragEvent event = (DragEvent)msg.obj;
2998                 event.mLocalState = mLocalDragState;    // only present when this app called startDrag()
2999                 handleDragEvent(event);
3000             } break;
3001             case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
3002                 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo)msg.obj);
3003             } break;
3004             case MSG_UPDATE_CONFIGURATION: {
3005                 Configuration config = (Configuration)msg.obj;
3006                 if (config.isOtherSeqNewer(mLastConfiguration)) {
3007                     config = mLastConfiguration;
3008                 }
3009                 updateConfiguration(config, false);
3010             } break;
3011             case MSG_DISPATCH_SCREEN_STATE: {
3012                 if (mView != null) {
3013                     handleScreenStateChange(msg.arg1 == 1);
3014                 }
3015             } break;
3016             case MSG_INVALIDATE_DISPLAY_LIST: {
3017                 invalidateDisplayLists();
3018             } break;
3019             case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
3020                 setAccessibilityFocus(null, null);
3021             } break;
3022             case MSG_DISPATCH_DONE_ANIMATING: {
3023                 handleDispatchDoneAnimating();
3024             } break;
3025             case MSG_INVALIDATE_WORLD: {
3026                 if (mView != null) {
3027                     invalidateWorld(mView);
3028                 }
3029             } break;
3030             }
3031         }
3032     }
3033 
3034     final ViewRootHandler mHandler = new ViewRootHandler();
3035 
3036     /**
3037      * Something in the current window tells us we need to change the touch mode.  For
3038      * example, we are not in touch mode, and the user touches the screen.
3039      *
3040      * If the touch mode has changed, tell the window manager, and handle it locally.
3041      *
3042      * @param inTouchMode Whether we want to be in touch mode.
3043      * @return True if the touch mode changed and focus changed was changed as a result
3044      */
ensureTouchMode(boolean inTouchMode)3045     boolean ensureTouchMode(boolean inTouchMode) {
3046         if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
3047                 + "touch mode is " + mAttachInfo.mInTouchMode);
3048         if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3049 
3050         // tell the window manager
3051         try {
3052             mWindowSession.setInTouchMode(inTouchMode);
3053         } catch (RemoteException e) {
3054             throw new RuntimeException(e);
3055         }
3056 
3057         // handle the change
3058         return ensureTouchModeLocally(inTouchMode);
3059     }
3060 
3061     /**
3062      * Ensure that the touch mode for this window is set, and if it is changing,
3063      * take the appropriate action.
3064      * @param inTouchMode Whether we want to be in touch mode.
3065      * @return True if the touch mode changed and focus changed was changed as a result
3066      */
ensureTouchModeLocally(boolean inTouchMode)3067     private boolean ensureTouchModeLocally(boolean inTouchMode) {
3068         if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
3069                 + "touch mode is " + mAttachInfo.mInTouchMode);
3070 
3071         if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3072 
3073         mAttachInfo.mInTouchMode = inTouchMode;
3074         mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
3075 
3076         return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
3077     }
3078 
enterTouchMode()3079     private boolean enterTouchMode() {
3080         if (mView != null) {
3081             if (mView.hasFocus()) {
3082                 // note: not relying on mFocusedView here because this could
3083                 // be when the window is first being added, and mFocused isn't
3084                 // set yet.
3085                 final View focused = mView.findFocus();
3086                 if (focused != null && !focused.isFocusableInTouchMode()) {
3087 
3088                     final ViewGroup ancestorToTakeFocus =
3089                             findAncestorToTakeFocusInTouchMode(focused);
3090                     if (ancestorToTakeFocus != null) {
3091                         // there is an ancestor that wants focus after its descendants that
3092                         // is focusable in touch mode.. give it focus
3093                         return ancestorToTakeFocus.requestFocus();
3094                     } else {
3095                         // nothing appropriate to have focus in touch mode, clear it out
3096                         mView.unFocus();
3097                         mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(focused, null);
3098                         mFocusedView = null;
3099                         mOldFocusedView = null;
3100                         return true;
3101                     }
3102                 }
3103             }
3104         }
3105         return false;
3106     }
3107 
3108     /**
3109      * Find an ancestor of focused that wants focus after its descendants and is
3110      * focusable in touch mode.
3111      * @param focused The currently focused view.
3112      * @return An appropriate view, or null if no such view exists.
3113      */
findAncestorToTakeFocusInTouchMode(View focused)3114     private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
3115         ViewParent parent = focused.getParent();
3116         while (parent instanceof ViewGroup) {
3117             final ViewGroup vgParent = (ViewGroup) parent;
3118             if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
3119                     && vgParent.isFocusableInTouchMode()) {
3120                 return vgParent;
3121             }
3122             if (vgParent.isRootNamespace()) {
3123                 return null;
3124             } else {
3125                 parent = vgParent.getParent();
3126             }
3127         }
3128         return null;
3129     }
3130 
leaveTouchMode()3131     private boolean leaveTouchMode() {
3132         if (mView != null) {
3133             if (mView.hasFocus()) {
3134                 // i learned the hard way to not trust mFocusedView :)
3135                 mFocusedView = mView.findFocus();
3136                 if (!(mFocusedView instanceof ViewGroup)) {
3137                     // some view has focus, let it keep it
3138                     return false;
3139                 } else if (((ViewGroup)mFocusedView).getDescendantFocusability() !=
3140                         ViewGroup.FOCUS_AFTER_DESCENDANTS) {
3141                     // some view group has focus, and doesn't prefer its children
3142                     // over itself for focus, so let them keep it.
3143                     return false;
3144                 }
3145             }
3146 
3147             // find the best view to give focus to in this brave new non-touch-mode
3148             // world
3149             final View focused = focusSearch(null, View.FOCUS_DOWN);
3150             if (focused != null) {
3151                 return focused.requestFocus(View.FOCUS_DOWN);
3152             }
3153         }
3154         return false;
3155     }
3156 
deliverInputEvent(QueuedInputEvent q)3157     private void deliverInputEvent(QueuedInputEvent q) {
3158         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent");
3159         try {
3160             if (q.mEvent instanceof KeyEvent) {
3161                 deliverKeyEvent(q);
3162             } else {
3163                 final int source = q.mEvent.getSource();
3164                 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
3165                     deliverPointerEvent(q);
3166                 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
3167                     deliverTrackballEvent(q);
3168                 } else {
3169                     deliverGenericMotionEvent(q);
3170                 }
3171             }
3172         } finally {
3173             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
3174         }
3175     }
3176 
deliverPointerEvent(QueuedInputEvent q)3177     private void deliverPointerEvent(QueuedInputEvent q) {
3178         final MotionEvent event = (MotionEvent)q.mEvent;
3179         final boolean isTouchEvent = event.isTouchEvent();
3180         if (mInputEventConsistencyVerifier != null) {
3181             if (isTouchEvent) {
3182                 mInputEventConsistencyVerifier.onTouchEvent(event, 0);
3183             } else {
3184                 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0);
3185             }
3186         }
3187 
3188         // If there is no view, then the event will not be handled.
3189         if (mView == null || !mAdded) {
3190             finishInputEvent(q, false);
3191             return;
3192         }
3193 
3194         // Translate the pointer event for compatibility, if needed.
3195         if (mTranslator != null) {
3196             mTranslator.translateEventInScreenToAppWindow(event);
3197         }
3198 
3199         // Enter touch mode on down or scroll.
3200         final int action = event.getAction();
3201         if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
3202             ensureTouchMode(true);
3203         }
3204 
3205         // Offset the scroll position.
3206         if (mCurScrollY != 0) {
3207             event.offsetLocation(0, mCurScrollY);
3208         }
3209         if (MEASURE_LATENCY) {
3210             lt.sample("A Dispatching PointerEvents", System.nanoTime() - event.getEventTimeNano());
3211         }
3212 
3213         // Remember the touch position for possible drag-initiation.
3214         if (isTouchEvent) {
3215             mLastTouchPoint.x = event.getRawX();
3216             mLastTouchPoint.y = event.getRawY();
3217         }
3218 
3219         // Dispatch touch to view hierarchy.
3220         boolean handled = mView.dispatchPointerEvent(event);
3221         if (MEASURE_LATENCY) {
3222             lt.sample("B Dispatched PointerEvents ", System.nanoTime() - event.getEventTimeNano());
3223         }
3224         if (handled) {
3225             finishInputEvent(q, true);
3226             return;
3227         }
3228 
3229         // Pointer event was unhandled.
3230         finishInputEvent(q, false);
3231     }
3232 
deliverTrackballEvent(QueuedInputEvent q)3233     private void deliverTrackballEvent(QueuedInputEvent q) {
3234         final MotionEvent event = (MotionEvent)q.mEvent;
3235         if (mInputEventConsistencyVerifier != null) {
3236             mInputEventConsistencyVerifier.onTrackballEvent(event, 0);
3237         }
3238 
3239         if (mView != null && mAdded && (q.mFlags & QueuedInputEvent.FLAG_DELIVER_POST_IME) == 0) {
3240             if (LOCAL_LOGV)
3241                 Log.v(TAG, "Dispatching trackball " + event + " to " + mView);
3242 
3243             // Dispatch to the IME before propagating down the view hierarchy.
3244             // The IME will eventually call back into handleImeFinishedEvent.
3245             if (mLastWasImTarget) {
3246                 InputMethodManager imm = InputMethodManager.peekInstance();
3247                 if (imm != null) {
3248                     final int seq = event.getSequenceNumber();
3249                     if (DEBUG_IMF)
3250                         Log.v(TAG, "Sending trackball event to IME: seq="
3251                                 + seq + " event=" + event);
3252                     imm.dispatchTrackballEvent(mView.getContext(), seq, event,
3253                             mInputMethodCallback);
3254                     return;
3255                 }
3256             }
3257         }
3258 
3259         // Not dispatching to IME, continue with post IME actions.
3260         deliverTrackballEventPostIme(q);
3261     }
3262 
deliverTrackballEventPostIme(QueuedInputEvent q)3263     private void deliverTrackballEventPostIme(QueuedInputEvent q) {
3264         final MotionEvent event = (MotionEvent) q.mEvent;
3265 
3266         // If there is no view, then the event will not be handled.
3267         if (mView == null || !mAdded) {
3268             finishInputEvent(q, false);
3269             return;
3270         }
3271 
3272         // Deliver the trackball event to the view.
3273         if (mView.dispatchTrackballEvent(event)) {
3274             // If we reach this, we delivered a trackball event to mView and
3275             // mView consumed it. Because we will not translate the trackball
3276             // event into a key event, touch mode will not exit, so we exit
3277             // touch mode here.
3278             ensureTouchMode(false);
3279 
3280             finishInputEvent(q, true);
3281             mLastTrackballTime = Integer.MIN_VALUE;
3282             return;
3283         }
3284 
3285         // Translate the trackball event into DPAD keys and try to deliver those.
3286         final TrackballAxis x = mTrackballAxisX;
3287         final TrackballAxis y = mTrackballAxisY;
3288 
3289         long curTime = SystemClock.uptimeMillis();
3290         if ((mLastTrackballTime + MAX_TRACKBALL_DELAY) < curTime) {
3291             // It has been too long since the last movement,
3292             // so restart at the beginning.
3293             x.reset(0);
3294             y.reset(0);
3295             mLastTrackballTime = curTime;
3296         }
3297 
3298         final int action = event.getAction();
3299         final int metaState = event.getMetaState();
3300         switch (action) {
3301             case MotionEvent.ACTION_DOWN:
3302                 x.reset(2);
3303                 y.reset(2);
3304                 enqueueInputEvent(new KeyEvent(curTime, curTime,
3305                         KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
3306                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
3307                         InputDevice.SOURCE_KEYBOARD));
3308                 break;
3309             case MotionEvent.ACTION_UP:
3310                 x.reset(2);
3311                 y.reset(2);
3312                 enqueueInputEvent(new KeyEvent(curTime, curTime,
3313                         KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
3314                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
3315                         InputDevice.SOURCE_KEYBOARD));
3316                 break;
3317         }
3318 
3319         if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + x.position + " step="
3320                 + x.step + " dir=" + x.dir + " acc=" + x.acceleration
3321                 + " move=" + event.getX()
3322                 + " / Y=" + y.position + " step="
3323                 + y.step + " dir=" + y.dir + " acc=" + y.acceleration
3324                 + " move=" + event.getY());
3325         final float xOff = x.collect(event.getX(), event.getEventTime(), "X");
3326         final float yOff = y.collect(event.getY(), event.getEventTime(), "Y");
3327 
3328         // Generate DPAD events based on the trackball movement.
3329         // We pick the axis that has moved the most as the direction of
3330         // the DPAD.  When we generate DPAD events for one axis, then the
3331         // other axis is reset -- we don't want to perform DPAD jumps due
3332         // to slight movements in the trackball when making major movements
3333         // along the other axis.
3334         int keycode = 0;
3335         int movement = 0;
3336         float accel = 1;
3337         if (xOff > yOff) {
3338             movement = x.generate((2/event.getXPrecision()));
3339             if (movement != 0) {
3340                 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
3341                         : KeyEvent.KEYCODE_DPAD_LEFT;
3342                 accel = x.acceleration;
3343                 y.reset(2);
3344             }
3345         } else if (yOff > 0) {
3346             movement = y.generate((2/event.getYPrecision()));
3347             if (movement != 0) {
3348                 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
3349                         : KeyEvent.KEYCODE_DPAD_UP;
3350                 accel = y.acceleration;
3351                 x.reset(2);
3352             }
3353         }
3354 
3355         if (keycode != 0) {
3356             if (movement < 0) movement = -movement;
3357             int accelMovement = (int)(movement * accel);
3358             if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
3359                     + " accelMovement=" + accelMovement
3360                     + " accel=" + accel);
3361             if (accelMovement > movement) {
3362                 if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
3363                         + keycode);
3364                 movement--;
3365                 int repeatCount = accelMovement - movement;
3366                 enqueueInputEvent(new KeyEvent(curTime, curTime,
3367                         KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
3368                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
3369                         InputDevice.SOURCE_KEYBOARD));
3370             }
3371             while (movement > 0) {
3372                 if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
3373                         + keycode);
3374                 movement--;
3375                 curTime = SystemClock.uptimeMillis();
3376                 enqueueInputEvent(new KeyEvent(curTime, curTime,
3377                         KeyEvent.ACTION_DOWN, keycode, 0, metaState,
3378                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
3379                         InputDevice.SOURCE_KEYBOARD));
3380                 enqueueInputEvent(new KeyEvent(curTime, curTime,
3381                         KeyEvent.ACTION_UP, keycode, 0, metaState,
3382                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
3383                         InputDevice.SOURCE_KEYBOARD));
3384             }
3385             mLastTrackballTime = curTime;
3386         }
3387 
3388         // Unfortunately we can't tell whether the application consumed the keys, so
3389         // we always consider the trackball event handled.
3390         finishInputEvent(q, true);
3391     }
3392 
deliverGenericMotionEvent(QueuedInputEvent q)3393     private void deliverGenericMotionEvent(QueuedInputEvent q) {
3394         final MotionEvent event = (MotionEvent)q.mEvent;
3395         if (mInputEventConsistencyVerifier != null) {
3396             mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0);
3397         }
3398 
3399         if (mView != null && mAdded && (q.mFlags & QueuedInputEvent.FLAG_DELIVER_POST_IME) == 0) {
3400             if (LOCAL_LOGV)
3401                 Log.v(TAG, "Dispatching generic motion " + event + " to " + mView);
3402 
3403             // Dispatch to the IME before propagating down the view hierarchy.
3404             // The IME will eventually call back into handleImeFinishedEvent.
3405             if (mLastWasImTarget) {
3406                 InputMethodManager imm = InputMethodManager.peekInstance();
3407                 if (imm != null) {
3408                     final int seq = event.getSequenceNumber();
3409                     if (DEBUG_IMF)
3410                         Log.v(TAG, "Sending generic motion event to IME: seq="
3411                                 + seq + " event=" + event);
3412                     imm.dispatchGenericMotionEvent(mView.getContext(), seq, event,
3413                             mInputMethodCallback);
3414                     return;
3415                 }
3416             }
3417         }
3418 
3419         // Not dispatching to IME, continue with post IME actions.
3420         deliverGenericMotionEventPostIme(q);
3421     }
3422 
deliverGenericMotionEventPostIme(QueuedInputEvent q)3423     private void deliverGenericMotionEventPostIme(QueuedInputEvent q) {
3424         final MotionEvent event = (MotionEvent) q.mEvent;
3425         final boolean isJoystick = (event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0;
3426 
3427         // If there is no view, then the event will not be handled.
3428         if (mView == null || !mAdded) {
3429             if (isJoystick) {
3430                 updateJoystickDirection(event, false);
3431             }
3432             finishInputEvent(q, false);
3433             return;
3434         }
3435 
3436         // Deliver the event to the view.
3437         if (mView.dispatchGenericMotionEvent(event)) {
3438             if (isJoystick) {
3439                 updateJoystickDirection(event, false);
3440             }
3441             finishInputEvent(q, true);
3442             return;
3443         }
3444 
3445         if (isJoystick) {
3446             // Translate the joystick event into DPAD keys and try to deliver
3447             // those.
3448             updateJoystickDirection(event, true);
3449             finishInputEvent(q, true);
3450         } else {
3451             finishInputEvent(q, false);
3452         }
3453     }
3454 
updateJoystickDirection(MotionEvent event, boolean synthesizeNewKeys)3455     private void updateJoystickDirection(MotionEvent event, boolean synthesizeNewKeys) {
3456         final long time = event.getEventTime();
3457         final int metaState = event.getMetaState();
3458         final int deviceId = event.getDeviceId();
3459         final int source = event.getSource();
3460 
3461         int xDirection = joystickAxisValueToDirection(event.getAxisValue(MotionEvent.AXIS_HAT_X));
3462         if (xDirection == 0) {
3463             xDirection = joystickAxisValueToDirection(event.getX());
3464         }
3465 
3466         int yDirection = joystickAxisValueToDirection(event.getAxisValue(MotionEvent.AXIS_HAT_Y));
3467         if (yDirection == 0) {
3468             yDirection = joystickAxisValueToDirection(event.getY());
3469         }
3470 
3471         if (xDirection != mLastJoystickXDirection) {
3472             if (mLastJoystickXKeyCode != 0) {
3473                 enqueueInputEvent(new KeyEvent(time, time,
3474                         KeyEvent.ACTION_UP, mLastJoystickXKeyCode, 0, metaState,
3475                         deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
3476                 mLastJoystickXKeyCode = 0;
3477             }
3478 
3479             mLastJoystickXDirection = xDirection;
3480 
3481             if (xDirection != 0 && synthesizeNewKeys) {
3482                 mLastJoystickXKeyCode = xDirection > 0
3483                         ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
3484                 enqueueInputEvent(new KeyEvent(time, time,
3485                         KeyEvent.ACTION_DOWN, mLastJoystickXKeyCode, 0, metaState,
3486                         deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
3487             }
3488         }
3489 
3490         if (yDirection != mLastJoystickYDirection) {
3491             if (mLastJoystickYKeyCode != 0) {
3492                 enqueueInputEvent(new KeyEvent(time, time,
3493                         KeyEvent.ACTION_UP, mLastJoystickYKeyCode, 0, metaState,
3494                         deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
3495                 mLastJoystickYKeyCode = 0;
3496             }
3497 
3498             mLastJoystickYDirection = yDirection;
3499 
3500             if (yDirection != 0 && synthesizeNewKeys) {
3501                 mLastJoystickYKeyCode = yDirection > 0
3502                         ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
3503                 enqueueInputEvent(new KeyEvent(time, time,
3504                         KeyEvent.ACTION_DOWN, mLastJoystickYKeyCode, 0, metaState,
3505                         deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
3506             }
3507         }
3508     }
3509 
joystickAxisValueToDirection(float value)3510     private static int joystickAxisValueToDirection(float value) {
3511         if (value >= 0.5f) {
3512             return 1;
3513         } else if (value <= -0.5f) {
3514             return -1;
3515         } else {
3516             return 0;
3517         }
3518     }
3519 
3520     /**
3521      * Returns true if the key is used for keyboard navigation.
3522      * @param keyEvent The key event.
3523      * @return True if the key is used for keyboard navigation.
3524      */
isNavigationKey(KeyEvent keyEvent)3525     private static boolean isNavigationKey(KeyEvent keyEvent) {
3526         switch (keyEvent.getKeyCode()) {
3527         case KeyEvent.KEYCODE_DPAD_LEFT:
3528         case KeyEvent.KEYCODE_DPAD_RIGHT:
3529         case KeyEvent.KEYCODE_DPAD_UP:
3530         case KeyEvent.KEYCODE_DPAD_DOWN:
3531         case KeyEvent.KEYCODE_DPAD_CENTER:
3532         case KeyEvent.KEYCODE_PAGE_UP:
3533         case KeyEvent.KEYCODE_PAGE_DOWN:
3534         case KeyEvent.KEYCODE_MOVE_HOME:
3535         case KeyEvent.KEYCODE_MOVE_END:
3536         case KeyEvent.KEYCODE_TAB:
3537         case KeyEvent.KEYCODE_SPACE:
3538         case KeyEvent.KEYCODE_ENTER:
3539             return true;
3540         }
3541         return false;
3542     }
3543 
3544     /**
3545      * Returns true if the key is used for typing.
3546      * @param keyEvent The key event.
3547      * @return True if the key is used for typing.
3548      */
isTypingKey(KeyEvent keyEvent)3549     private static boolean isTypingKey(KeyEvent keyEvent) {
3550         return keyEvent.getUnicodeChar() > 0;
3551     }
3552 
3553     /**
3554      * See if the key event means we should leave touch mode (and leave touch mode if so).
3555      * @param event The key event.
3556      * @return Whether this key event should be consumed (meaning the act of
3557      *   leaving touch mode alone is considered the event).
3558      */
checkForLeavingTouchModeAndConsume(KeyEvent event)3559     private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
3560         // Only relevant in touch mode.
3561         if (!mAttachInfo.mInTouchMode) {
3562             return false;
3563         }
3564 
3565         // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
3566         final int action = event.getAction();
3567         if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
3568             return false;
3569         }
3570 
3571         // Don't leave touch mode if the IME told us not to.
3572         if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
3573             return false;
3574         }
3575 
3576         // If the key can be used for keyboard navigation then leave touch mode
3577         // and select a focused view if needed (in ensureTouchMode).
3578         // When a new focused view is selected, we consume the navigation key because
3579         // navigation doesn't make much sense unless a view already has focus so
3580         // the key's purpose is to set focus.
3581         if (isNavigationKey(event)) {
3582             return ensureTouchMode(false);
3583         }
3584 
3585         // If the key can be used for typing then leave touch mode
3586         // and select a focused view if needed (in ensureTouchMode).
3587         // Always allow the view to process the typing key.
3588         if (isTypingKey(event)) {
3589             ensureTouchMode(false);
3590             return false;
3591         }
3592 
3593         return false;
3594     }
3595 
deliverKeyEvent(QueuedInputEvent q)3596     private void deliverKeyEvent(QueuedInputEvent q) {
3597         final KeyEvent event = (KeyEvent)q.mEvent;
3598         if (mInputEventConsistencyVerifier != null) {
3599             mInputEventConsistencyVerifier.onKeyEvent(event, 0);
3600         }
3601 
3602         if (mView != null && mAdded && (q.mFlags & QueuedInputEvent.FLAG_DELIVER_POST_IME) == 0) {
3603             if (LOCAL_LOGV) Log.v(TAG, "Dispatching key " + event + " to " + mView);
3604 
3605             // Perform predispatching before the IME.
3606             if (mView.dispatchKeyEventPreIme(event)) {
3607                 finishInputEvent(q, true);
3608                 return;
3609             }
3610 
3611             // Dispatch to the IME before propagating down the view hierarchy.
3612             // The IME will eventually call back into handleImeFinishedEvent.
3613             if (mLastWasImTarget) {
3614                 InputMethodManager imm = InputMethodManager.peekInstance();
3615                 if (imm != null) {
3616                     final int seq = event.getSequenceNumber();
3617                     if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq="
3618                             + seq + " event=" + event);
3619                     imm.dispatchKeyEvent(mView.getContext(), seq, event, mInputMethodCallback);
3620                     return;
3621                 }
3622             }
3623         }
3624 
3625         // Not dispatching to IME, continue with post IME actions.
3626         deliverKeyEventPostIme(q);
3627     }
3628 
handleImeFinishedEvent(int seq, boolean handled)3629     void handleImeFinishedEvent(int seq, boolean handled) {
3630         final QueuedInputEvent q = mCurrentInputEvent;
3631         if (q != null && q.mEvent.getSequenceNumber() == seq) {
3632             if (DEBUG_IMF) {
3633                 Log.v(TAG, "IME finished event: seq=" + seq
3634                         + " handled=" + handled + " event=" + q);
3635             }
3636             if (handled) {
3637                 finishInputEvent(q, true);
3638             } else {
3639                 if (q.mEvent instanceof KeyEvent) {
3640                     KeyEvent event = (KeyEvent)q.mEvent;
3641                     if (event.getAction() != KeyEvent.ACTION_UP) {
3642                         // If the window doesn't currently have input focus, then drop
3643                         // this event.  This could be an event that came back from the
3644                         // IME dispatch but the window has lost focus in the meantime.
3645                         if (!mAttachInfo.mHasWindowFocus) {
3646                             Slog.w(TAG, "Dropping event due to no window focus: " + event);
3647                             finishInputEvent(q, true);
3648                             return;
3649                         }
3650                     }
3651                     deliverKeyEventPostIme(q);
3652                 } else {
3653                     MotionEvent event = (MotionEvent)q.mEvent;
3654                     if (event.getAction() != MotionEvent.ACTION_CANCEL
3655                             && event.getAction() != MotionEvent.ACTION_UP) {
3656                         // If the window doesn't currently have input focus, then drop
3657                         // this event.  This could be an event that came back from the
3658                         // IME dispatch but the window has lost focus in the meantime.
3659                         if (!mAttachInfo.mHasWindowFocus) {
3660                             Slog.w(TAG, "Dropping event due to no window focus: " + event);
3661                             finishInputEvent(q, true);
3662                             return;
3663                         }
3664                     }
3665                     final int source = q.mEvent.getSource();
3666                     if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
3667                         deliverTrackballEventPostIme(q);
3668                     } else {
3669                         deliverGenericMotionEventPostIme(q);
3670                     }
3671                 }
3672             }
3673         } else {
3674             if (DEBUG_IMF) {
3675                 Log.v(TAG, "IME finished event: seq=" + seq
3676                         + " handled=" + handled + ", event not found!");
3677             }
3678         }
3679     }
3680 
deliverKeyEventPostIme(QueuedInputEvent q)3681     private void deliverKeyEventPostIme(QueuedInputEvent q) {
3682         final KeyEvent event = (KeyEvent)q.mEvent;
3683 
3684         // If the view went away, then the event will not be handled.
3685         if (mView == null || !mAdded) {
3686             finishInputEvent(q, false);
3687             return;
3688         }
3689 
3690         // If the key's purpose is to exit touch mode then we consume it and consider it handled.
3691         if (checkForLeavingTouchModeAndConsume(event)) {
3692             finishInputEvent(q, true);
3693             return;
3694         }
3695 
3696         // Make sure the fallback event policy sees all keys that will be delivered to the
3697         // view hierarchy.
3698         mFallbackEventHandler.preDispatchKeyEvent(event);
3699 
3700         // Deliver the key to the view hierarchy.
3701         if (mView.dispatchKeyEvent(event)) {
3702             finishInputEvent(q, true);
3703             return;
3704         }
3705 
3706         // If the Control modifier is held, try to interpret the key as a shortcut.
3707         if (event.getAction() == KeyEvent.ACTION_DOWN
3708                 && event.isCtrlPressed()
3709                 && event.getRepeatCount() == 0
3710                 && !KeyEvent.isModifierKey(event.getKeyCode())) {
3711             if (mView.dispatchKeyShortcutEvent(event)) {
3712                 finishInputEvent(q, true);
3713                 return;
3714             }
3715         }
3716 
3717         // Apply the fallback event policy.
3718         if (mFallbackEventHandler.dispatchKeyEvent(event)) {
3719             finishInputEvent(q, true);
3720             return;
3721         }
3722 
3723         // Handle automatic focus changes.
3724         if (event.getAction() == KeyEvent.ACTION_DOWN) {
3725             int direction = 0;
3726             switch (event.getKeyCode()) {
3727                 case KeyEvent.KEYCODE_DPAD_LEFT:
3728                     if (event.hasNoModifiers()) {
3729                         direction = View.FOCUS_LEFT;
3730                     }
3731                     break;
3732                 case KeyEvent.KEYCODE_DPAD_RIGHT:
3733                     if (event.hasNoModifiers()) {
3734                         direction = View.FOCUS_RIGHT;
3735                     }
3736                     break;
3737                 case KeyEvent.KEYCODE_DPAD_UP:
3738                     if (event.hasNoModifiers()) {
3739                         direction = View.FOCUS_UP;
3740                     }
3741                     break;
3742                 case KeyEvent.KEYCODE_DPAD_DOWN:
3743                     if (event.hasNoModifiers()) {
3744                         direction = View.FOCUS_DOWN;
3745                     }
3746                     break;
3747                 case KeyEvent.KEYCODE_TAB:
3748                     if (event.hasNoModifiers()) {
3749                         direction = View.FOCUS_FORWARD;
3750                     } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
3751                         direction = View.FOCUS_BACKWARD;
3752                     }
3753                     break;
3754             }
3755             if (direction != 0) {
3756                 View focused = mView.findFocus();
3757                 if (focused != null) {
3758                     View v = focused.focusSearch(direction);
3759                     if (v != null && v != focused) {
3760                         // do the math the get the interesting rect
3761                         // of previous focused into the coord system of
3762                         // newly focused view
3763                         focused.getFocusedRect(mTempRect);
3764                         if (mView instanceof ViewGroup) {
3765                             ((ViewGroup) mView).offsetDescendantRectToMyCoords(
3766                                     focused, mTempRect);
3767                             ((ViewGroup) mView).offsetRectIntoDescendantCoords(
3768                                     v, mTempRect);
3769                         }
3770                         if (v.requestFocus(direction, mTempRect)) {
3771                             playSoundEffect(SoundEffectConstants
3772                                     .getContantForFocusDirection(direction));
3773                             finishInputEvent(q, true);
3774                             return;
3775                         }
3776                     }
3777 
3778                     // Give the focused view a last chance to handle the dpad key.
3779                     if (mView.dispatchUnhandledMove(focused, direction)) {
3780                         finishInputEvent(q, true);
3781                         return;
3782                     }
3783                 }
3784             }
3785         }
3786 
3787         // Key was unhandled.
3788         finishInputEvent(q, false);
3789     }
3790 
3791     /* drag/drop */
setLocalDragState(Object obj)3792     void setLocalDragState(Object obj) {
3793         mLocalDragState = obj;
3794     }
3795 
handleDragEvent(DragEvent event)3796     private void handleDragEvent(DragEvent event) {
3797         // From the root, only drag start/end/location are dispatched.  entered/exited
3798         // are determined and dispatched by the viewgroup hierarchy, who then report
3799         // that back here for ultimate reporting back to the framework.
3800         if (mView != null && mAdded) {
3801             final int what = event.mAction;
3802 
3803             if (what == DragEvent.ACTION_DRAG_EXITED) {
3804                 // A direct EXITED event means that the window manager knows we've just crossed
3805                 // a window boundary, so the current drag target within this one must have
3806                 // just been exited.  Send it the usual notifications and then we're done
3807                 // for now.
3808                 mView.dispatchDragEvent(event);
3809             } else {
3810                 // Cache the drag description when the operation starts, then fill it in
3811                 // on subsequent calls as a convenience
3812                 if (what == DragEvent.ACTION_DRAG_STARTED) {
3813                     mCurrentDragView = null;    // Start the current-recipient tracking
3814                     mDragDescription = event.mClipDescription;
3815                 } else {
3816                     event.mClipDescription = mDragDescription;
3817                 }
3818 
3819                 // For events with a [screen] location, translate into window coordinates
3820                 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
3821                     mDragPoint.set(event.mX, event.mY);
3822                     if (mTranslator != null) {
3823                         mTranslator.translatePointInScreenToAppWindow(mDragPoint);
3824                     }
3825 
3826                     if (mCurScrollY != 0) {
3827                         mDragPoint.offset(0, mCurScrollY);
3828                     }
3829 
3830                     event.mX = mDragPoint.x;
3831                     event.mY = mDragPoint.y;
3832                 }
3833 
3834                 // Remember who the current drag target is pre-dispatch
3835                 final View prevDragView = mCurrentDragView;
3836 
3837                 // Now dispatch the drag/drop event
3838                 boolean result = mView.dispatchDragEvent(event);
3839 
3840                 // If we changed apparent drag target, tell the OS about it
3841                 if (prevDragView != mCurrentDragView) {
3842                     try {
3843                         if (prevDragView != null) {
3844                             mWindowSession.dragRecipientExited(mWindow);
3845                         }
3846                         if (mCurrentDragView != null) {
3847                             mWindowSession.dragRecipientEntered(mWindow);
3848                         }
3849                     } catch (RemoteException e) {
3850                         Slog.e(TAG, "Unable to note drag target change");
3851                     }
3852                 }
3853 
3854                 // Report the drop result when we're done
3855                 if (what == DragEvent.ACTION_DROP) {
3856                     mDragDescription = null;
3857                     try {
3858                         Log.i(TAG, "Reporting drop result: " + result);
3859                         mWindowSession.reportDropResult(mWindow, result);
3860                     } catch (RemoteException e) {
3861                         Log.e(TAG, "Unable to report drop result");
3862                     }
3863                 }
3864 
3865                 // When the drag operation ends, release any local state object
3866                 // that may have been in use
3867                 if (what == DragEvent.ACTION_DRAG_ENDED) {
3868                     setLocalDragState(null);
3869                 }
3870             }
3871         }
3872         event.recycle();
3873     }
3874 
handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args)3875     public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
3876         if (mSeq != args.seq) {
3877             // The sequence has changed, so we need to update our value and make
3878             // sure to do a traversal afterward so the window manager is given our
3879             // most recent data.
3880             mSeq = args.seq;
3881             mAttachInfo.mForceReportNewAttributes = true;
3882             scheduleTraversals();
3883         }
3884         if (mView == null) return;
3885         if (args.localChanges != 0) {
3886             mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
3887         }
3888         if (mAttachInfo != null) {
3889             int visibility = args.globalVisibility&View.SYSTEM_UI_CLEARABLE_FLAGS;
3890             if (visibility != mAttachInfo.mGlobalSystemUiVisibility) {
3891                 mAttachInfo.mGlobalSystemUiVisibility = visibility;
3892                 mView.dispatchSystemUiVisibilityChanged(visibility);
3893             }
3894         }
3895     }
3896 
handleDispatchDoneAnimating()3897     public void handleDispatchDoneAnimating() {
3898         if (mWindowsAnimating) {
3899             mWindowsAnimating = false;
3900             if (!mDirty.isEmpty() || mIsAnimating)  {
3901                 scheduleTraversals();
3902             }
3903         }
3904     }
3905 
getLastTouchPoint(Point outLocation)3906     public void getLastTouchPoint(Point outLocation) {
3907         outLocation.x = (int) mLastTouchPoint.x;
3908         outLocation.y = (int) mLastTouchPoint.y;
3909     }
3910 
setDragFocus(View newDragTarget)3911     public void setDragFocus(View newDragTarget) {
3912         if (mCurrentDragView != newDragTarget) {
3913             mCurrentDragView = newDragTarget;
3914         }
3915     }
3916 
getAudioManager()3917     private AudioManager getAudioManager() {
3918         if (mView == null) {
3919             throw new IllegalStateException("getAudioManager called when there is no mView");
3920         }
3921         if (mAudioManager == null) {
3922             mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
3923         }
3924         return mAudioManager;
3925     }
3926 
getAccessibilityInteractionController()3927     public AccessibilityInteractionController getAccessibilityInteractionController() {
3928         if (mView == null) {
3929             throw new IllegalStateException("getAccessibilityInteractionController"
3930                     + " called when there is no mView");
3931         }
3932         if (mAccessibilityInteractionController == null) {
3933             mAccessibilityInteractionController = new AccessibilityInteractionController(this);
3934         }
3935         return mAccessibilityInteractionController;
3936     }
3937 
relayoutWindow(WindowManager.LayoutParams params, int viewVisibility, boolean insetsPending)3938     private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
3939             boolean insetsPending) throws RemoteException {
3940 
3941         float appScale = mAttachInfo.mApplicationScale;
3942         boolean restore = false;
3943         if (params != null && mTranslator != null) {
3944             restore = true;
3945             params.backup();
3946             mTranslator.translateWindowLayout(params);
3947         }
3948         if (params != null) {
3949             if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params);
3950         }
3951         mPendingConfiguration.seq = 0;
3952         //Log.d(TAG, ">>>>>> CALLING relayout");
3953         if (params != null && mOrigWindowType != params.type) {
3954             // For compatibility with old apps, don't crash here.
3955             if (mTargetSdkVersion < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
3956                 Slog.w(TAG, "Window type can not be changed after "
3957                         + "the window is added; ignoring change of " + mView);
3958                 params.type = mOrigWindowType;
3959             }
3960         }
3961         int relayoutResult = mWindowSession.relayout(
3962                 mWindow, mSeq, params,
3963                 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
3964                 (int) (mView.getMeasuredHeight() * appScale + 0.5f),
3965                 viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
3966                 mWinFrame, mPendingContentInsets, mPendingVisibleInsets,
3967                 mPendingConfiguration, mSurface);
3968         //Log.d(TAG, "<<<<<< BACK FROM relayout");
3969         if (restore) {
3970             params.restore();
3971         }
3972 
3973         if (mTranslator != null) {
3974             mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
3975             mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
3976             mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
3977         }
3978         return relayoutResult;
3979     }
3980 
3981     /**
3982      * {@inheritDoc}
3983      */
playSoundEffect(int effectId)3984     public void playSoundEffect(int effectId) {
3985         checkThread();
3986 
3987         try {
3988             final AudioManager audioManager = getAudioManager();
3989 
3990             switch (effectId) {
3991                 case SoundEffectConstants.CLICK:
3992                     audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
3993                     return;
3994                 case SoundEffectConstants.NAVIGATION_DOWN:
3995                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
3996                     return;
3997                 case SoundEffectConstants.NAVIGATION_LEFT:
3998                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
3999                     return;
4000                 case SoundEffectConstants.NAVIGATION_RIGHT:
4001                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
4002                     return;
4003                 case SoundEffectConstants.NAVIGATION_UP:
4004                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
4005                     return;
4006                 default:
4007                     throw new IllegalArgumentException("unknown effect id " + effectId +
4008                             " not defined in " + SoundEffectConstants.class.getCanonicalName());
4009             }
4010         } catch (IllegalStateException e) {
4011             // Exception thrown by getAudioManager() when mView is null
4012             Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e);
4013             e.printStackTrace();
4014         }
4015     }
4016 
4017     /**
4018      * {@inheritDoc}
4019      */
performHapticFeedback(int effectId, boolean always)4020     public boolean performHapticFeedback(int effectId, boolean always) {
4021         try {
4022             return mWindowSession.performHapticFeedback(mWindow, effectId, always);
4023         } catch (RemoteException e) {
4024             return false;
4025         }
4026     }
4027 
4028     /**
4029      * {@inheritDoc}
4030      */
focusSearch(View focused, int direction)4031     public View focusSearch(View focused, int direction) {
4032         checkThread();
4033         if (!(mView instanceof ViewGroup)) {
4034             return null;
4035         }
4036         return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
4037     }
4038 
debug()4039     public void debug() {
4040         mView.debug();
4041     }
4042 
dumpGfxInfo(int[] info)4043     public void dumpGfxInfo(int[] info) {
4044         info[0] = info[1] = 0;
4045         if (mView != null) {
4046             getGfxInfo(mView, info);
4047         }
4048     }
4049 
getGfxInfo(View view, int[] info)4050     private static void getGfxInfo(View view, int[] info) {
4051         DisplayList displayList = view.mDisplayList;
4052         info[0]++;
4053         if (displayList != null) {
4054             info[1] += displayList.getSize();
4055         }
4056 
4057         if (view instanceof ViewGroup) {
4058             ViewGroup group = (ViewGroup) view;
4059 
4060             int count = group.getChildCount();
4061             for (int i = 0; i < count; i++) {
4062                 getGfxInfo(group.getChildAt(i), info);
4063             }
4064         }
4065     }
4066 
die(boolean immediate)4067     public void die(boolean immediate) {
4068         // Make sure we do execute immediately if we are in the middle of a traversal or the damage
4069         // done by dispatchDetachedFromWindow will cause havoc on return.
4070         if (immediate && !mIsInTraversal) {
4071             doDie();
4072         } else {
4073             if (!mIsDrawing) {
4074                 destroyHardwareRenderer();
4075             } else {
4076                 Log.e(TAG, "Attempting to destroy the window while drawing!\n" +
4077                         "  window=" + this + ", title=" + mWindowAttributes.getTitle());
4078             }
4079             mHandler.sendEmptyMessage(MSG_DIE);
4080         }
4081     }
4082 
doDie()4083     void doDie() {
4084         checkThread();
4085         if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
4086         synchronized (this) {
4087             if (mAdded) {
4088                 dispatchDetachedFromWindow();
4089             }
4090 
4091             if (mAdded && !mFirst) {
4092                 destroyHardwareRenderer();
4093 
4094                 if (mView != null) {
4095                     int viewVisibility = mView.getVisibility();
4096                     boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
4097                     if (mWindowAttributesChanged || viewVisibilityChanged) {
4098                         // If layout params have been changed, first give them
4099                         // to the window manager to make sure it has the correct
4100                         // animation info.
4101                         try {
4102                             if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
4103                                     & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
4104                                 mWindowSession.finishDrawing(mWindow);
4105                             }
4106                         } catch (RemoteException e) {
4107                         }
4108                     }
4109 
4110                     mSurface.release();
4111                 }
4112             }
4113 
4114             mAdded = false;
4115         }
4116     }
4117 
requestUpdateConfiguration(Configuration config)4118     public void requestUpdateConfiguration(Configuration config) {
4119         Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
4120         mHandler.sendMessage(msg);
4121     }
4122 
loadSystemProperties()4123     public void loadSystemProperties() {
4124         boolean layout = SystemProperties.getBoolean(
4125                 View.DEBUG_LAYOUT_PROPERTY, false);
4126         if (layout != mAttachInfo.mDebugLayout) {
4127             mAttachInfo.mDebugLayout = layout;
4128             if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
4129                 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
4130             }
4131         }
4132     }
4133 
destroyHardwareRenderer()4134     private void destroyHardwareRenderer() {
4135         AttachInfo attachInfo = mAttachInfo;
4136         HardwareRenderer hardwareRenderer = attachInfo.mHardwareRenderer;
4137 
4138         if (hardwareRenderer != null) {
4139             if (mView != null) {
4140                 hardwareRenderer.destroyHardwareResources(mView);
4141             }
4142             hardwareRenderer.destroy(true);
4143             hardwareRenderer.setRequested(false);
4144 
4145             attachInfo.mHardwareRenderer = null;
4146             attachInfo.mHardwareAccelerated = false;
4147         }
4148     }
4149 
dispatchImeFinishedEvent(int seq, boolean handled)4150     void dispatchImeFinishedEvent(int seq, boolean handled) {
4151         Message msg = mHandler.obtainMessage(MSG_IME_FINISHED_EVENT);
4152         msg.arg1 = seq;
4153         msg.arg2 = handled ? 1 : 0;
4154         msg.setAsynchronous(true);
4155         mHandler.sendMessage(msg);
4156     }
4157 
dispatchFinishInputConnection(InputConnection connection)4158     public void dispatchFinishInputConnection(InputConnection connection) {
4159         Message msg = mHandler.obtainMessage(MSG_FINISH_INPUT_CONNECTION, connection);
4160         mHandler.sendMessage(msg);
4161     }
4162 
dispatchResized(Rect frame, Rect contentInsets, Rect visibleInsets, boolean reportDraw, Configuration newConfig)4163     public void dispatchResized(Rect frame, Rect contentInsets,
4164             Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
4165         if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": frame=" + frame.toShortString()
4166                 + " contentInsets=" + contentInsets.toShortString()
4167                 + " visibleInsets=" + visibleInsets.toShortString()
4168                 + " reportDraw=" + reportDraw);
4169         Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
4170         if (mTranslator != null) {
4171             mTranslator.translateRectInScreenToAppWindow(frame);
4172             mTranslator.translateRectInScreenToAppWindow(contentInsets);
4173             mTranslator.translateRectInScreenToAppWindow(visibleInsets);
4174         }
4175         SomeArgs args = SomeArgs.obtain();
4176         final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
4177         args.arg1 = sameProcessCall ? new Rect(frame) : frame;
4178         args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets;
4179         args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
4180         args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig;
4181         msg.obj = args;
4182         mHandler.sendMessage(msg);
4183     }
4184 
dispatchMoved(int newX, int newY)4185     public void dispatchMoved(int newX, int newY) {
4186         if (DEBUG_LAYOUT) Log.v(TAG, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
4187         if (mTranslator != null) {
4188             PointF point = new PointF(newX, newY);
4189             mTranslator.translatePointInScreenToAppWindow(point);
4190             newX = (int) (point.x + 0.5);
4191             newY = (int) (point.y + 0.5);
4192         }
4193         Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY);
4194         mHandler.sendMessage(msg);
4195     }
4196 
4197     /**
4198      * Represents a pending input event that is waiting in a queue.
4199      *
4200      * Input events are processed in serial order by the timestamp specified by
4201      * {@link InputEvent#getEventTimeNano()}.  In general, the input dispatcher delivers
4202      * one input event to the application at a time and waits for the application
4203      * to finish handling it before delivering the next one.
4204      *
4205      * However, because the application or IME can synthesize and inject multiple
4206      * key events at a time without going through the input dispatcher, we end up
4207      * needing a queue on the application's side.
4208      */
4209     private static final class QueuedInputEvent {
4210         public static final int FLAG_DELIVER_POST_IME = 1;
4211 
4212         public QueuedInputEvent mNext;
4213 
4214         public InputEvent mEvent;
4215         public InputEventReceiver mReceiver;
4216         public int mFlags;
4217     }
4218 
obtainQueuedInputEvent(InputEvent event, InputEventReceiver receiver, int flags)4219     private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
4220             InputEventReceiver receiver, int flags) {
4221         QueuedInputEvent q = mQueuedInputEventPool;
4222         if (q != null) {
4223             mQueuedInputEventPoolSize -= 1;
4224             mQueuedInputEventPool = q.mNext;
4225             q.mNext = null;
4226         } else {
4227             q = new QueuedInputEvent();
4228         }
4229 
4230         q.mEvent = event;
4231         q.mReceiver = receiver;
4232         q.mFlags = flags;
4233         return q;
4234     }
4235 
recycleQueuedInputEvent(QueuedInputEvent q)4236     private void recycleQueuedInputEvent(QueuedInputEvent q) {
4237         q.mEvent = null;
4238         q.mReceiver = null;
4239 
4240         if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
4241             mQueuedInputEventPoolSize += 1;
4242             q.mNext = mQueuedInputEventPool;
4243             mQueuedInputEventPool = q;
4244         }
4245     }
4246 
enqueueInputEvent(InputEvent event)4247     void enqueueInputEvent(InputEvent event) {
4248         enqueueInputEvent(event, null, 0, false);
4249     }
4250 
enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately)4251     void enqueueInputEvent(InputEvent event,
4252             InputEventReceiver receiver, int flags, boolean processImmediately) {
4253         QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
4254 
4255         // Always enqueue the input event in order, regardless of its time stamp.
4256         // We do this because the application or the IME may inject key events
4257         // in response to touch events and we want to ensure that the injected keys
4258         // are processed in the order they were received and we cannot trust that
4259         // the time stamp of injected events are monotonic.
4260         QueuedInputEvent last = mFirstPendingInputEvent;
4261         if (last == null) {
4262             mFirstPendingInputEvent = q;
4263         } else {
4264             while (last.mNext != null) {
4265                 last = last.mNext;
4266             }
4267             last.mNext = q;
4268         }
4269 
4270         if (processImmediately) {
4271             doProcessInputEvents();
4272         } else {
4273             scheduleProcessInputEvents();
4274         }
4275     }
4276 
scheduleProcessInputEvents()4277     private void scheduleProcessInputEvents() {
4278         if (!mProcessInputEventsScheduled) {
4279             mProcessInputEventsScheduled = true;
4280             Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
4281             msg.setAsynchronous(true);
4282             mHandler.sendMessage(msg);
4283         }
4284     }
4285 
doProcessInputEvents()4286     void doProcessInputEvents() {
4287         while (mCurrentInputEvent == null && mFirstPendingInputEvent != null) {
4288             QueuedInputEvent q = mFirstPendingInputEvent;
4289             mFirstPendingInputEvent = q.mNext;
4290             q.mNext = null;
4291             mCurrentInputEvent = q;
4292             deliverInputEvent(q);
4293         }
4294 
4295         // We are done processing all input events that we can process right now
4296         // so we can clear the pending flag immediately.
4297         if (mProcessInputEventsScheduled) {
4298             mProcessInputEventsScheduled = false;
4299             mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
4300         }
4301     }
4302 
finishInputEvent(QueuedInputEvent q, boolean handled)4303     private void finishInputEvent(QueuedInputEvent q, boolean handled) {
4304         if (q != mCurrentInputEvent) {
4305             throw new IllegalStateException("finished input event out of order");
4306         }
4307 
4308         if (q.mReceiver != null) {
4309             q.mReceiver.finishInputEvent(q.mEvent, handled);
4310         } else {
4311             q.mEvent.recycleIfNeededAfterDispatch();
4312         }
4313 
4314         recycleQueuedInputEvent(q);
4315 
4316         mCurrentInputEvent = null;
4317         if (mFirstPendingInputEvent != null) {
4318             scheduleProcessInputEvents();
4319         }
4320     }
4321 
scheduleConsumeBatchedInput()4322     void scheduleConsumeBatchedInput() {
4323         if (!mConsumeBatchedInputScheduled) {
4324             mConsumeBatchedInputScheduled = true;
4325             mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
4326                     mConsumedBatchedInputRunnable, null);
4327         }
4328     }
4329 
unscheduleConsumeBatchedInput()4330     void unscheduleConsumeBatchedInput() {
4331         if (mConsumeBatchedInputScheduled) {
4332             mConsumeBatchedInputScheduled = false;
4333             mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT,
4334                     mConsumedBatchedInputRunnable, null);
4335         }
4336     }
4337 
doConsumeBatchedInput(long frameTimeNanos)4338     void doConsumeBatchedInput(long frameTimeNanos) {
4339         if (mConsumeBatchedInputScheduled) {
4340             mConsumeBatchedInputScheduled = false;
4341             if (mInputEventReceiver != null) {
4342                 mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos);
4343             }
4344             doProcessInputEvents();
4345         }
4346     }
4347 
4348     final class TraversalRunnable implements Runnable {
4349         @Override
run()4350         public void run() {
4351             doTraversal();
4352         }
4353     }
4354     final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
4355 
4356     final class WindowInputEventReceiver extends InputEventReceiver {
WindowInputEventReceiver(InputChannel inputChannel, Looper looper)4357         public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
4358             super(inputChannel, looper);
4359         }
4360 
4361         @Override
onInputEvent(InputEvent event)4362         public void onInputEvent(InputEvent event) {
4363             enqueueInputEvent(event, this, 0, true);
4364         }
4365 
4366         @Override
onBatchedInputEventPending()4367         public void onBatchedInputEventPending() {
4368             scheduleConsumeBatchedInput();
4369         }
4370 
4371         @Override
dispose()4372         public void dispose() {
4373             unscheduleConsumeBatchedInput();
4374             super.dispose();
4375         }
4376     }
4377     WindowInputEventReceiver mInputEventReceiver;
4378 
4379     final class ConsumeBatchedInputRunnable implements Runnable {
4380         @Override
run()4381         public void run() {
4382             doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
4383         }
4384     }
4385     final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =
4386             new ConsumeBatchedInputRunnable();
4387     boolean mConsumeBatchedInputScheduled;
4388 
4389     final class InvalidateOnAnimationRunnable implements Runnable {
4390         private boolean mPosted;
4391         private ArrayList<View> mViews = new ArrayList<View>();
4392         private ArrayList<AttachInfo.InvalidateInfo> mViewRects =
4393                 new ArrayList<AttachInfo.InvalidateInfo>();
4394         private View[] mTempViews;
4395         private AttachInfo.InvalidateInfo[] mTempViewRects;
4396 
addView(View view)4397         public void addView(View view) {
4398             synchronized (this) {
4399                 mViews.add(view);
4400                 postIfNeededLocked();
4401             }
4402         }
4403 
addViewRect(AttachInfo.InvalidateInfo info)4404         public void addViewRect(AttachInfo.InvalidateInfo info) {
4405             synchronized (this) {
4406                 mViewRects.add(info);
4407                 postIfNeededLocked();
4408             }
4409         }
4410 
removeView(View view)4411         public void removeView(View view) {
4412             synchronized (this) {
4413                 mViews.remove(view);
4414 
4415                 for (int i = mViewRects.size(); i-- > 0; ) {
4416                     AttachInfo.InvalidateInfo info = mViewRects.get(i);
4417                     if (info.target == view) {
4418                         mViewRects.remove(i);
4419                         info.release();
4420                     }
4421                 }
4422 
4423                 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) {
4424                     mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null);
4425                     mPosted = false;
4426                 }
4427             }
4428         }
4429 
4430         @Override
run()4431         public void run() {
4432             final int viewCount;
4433             final int viewRectCount;
4434             synchronized (this) {
4435                 mPosted = false;
4436 
4437                 viewCount = mViews.size();
4438                 if (viewCount != 0) {
4439                     mTempViews = mViews.toArray(mTempViews != null
4440                             ? mTempViews : new View[viewCount]);
4441                     mViews.clear();
4442                 }
4443 
4444                 viewRectCount = mViewRects.size();
4445                 if (viewRectCount != 0) {
4446                     mTempViewRects = mViewRects.toArray(mTempViewRects != null
4447                             ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]);
4448                     mViewRects.clear();
4449                 }
4450             }
4451 
4452             for (int i = 0; i < viewCount; i++) {
4453                 mTempViews[i].invalidate();
4454                 mTempViews[i] = null;
4455             }
4456 
4457             for (int i = 0; i < viewRectCount; i++) {
4458                 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
4459                 info.target.invalidate(info.left, info.top, info.right, info.bottom);
4460                 info.release();
4461             }
4462         }
4463 
postIfNeededLocked()4464         private void postIfNeededLocked() {
4465             if (!mPosted) {
4466                 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
4467                 mPosted = true;
4468             }
4469         }
4470     }
4471     final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
4472             new InvalidateOnAnimationRunnable();
4473 
dispatchInvalidateDelayed(View view, long delayMilliseconds)4474     public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
4475         Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
4476         mHandler.sendMessageDelayed(msg, delayMilliseconds);
4477     }
4478 
dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info, long delayMilliseconds)4479     public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
4480             long delayMilliseconds) {
4481         final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
4482         mHandler.sendMessageDelayed(msg, delayMilliseconds);
4483     }
4484 
dispatchInvalidateOnAnimation(View view)4485     public void dispatchInvalidateOnAnimation(View view) {
4486         mInvalidateOnAnimationRunnable.addView(view);
4487     }
4488 
dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info)4489     public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) {
4490         mInvalidateOnAnimationRunnable.addViewRect(info);
4491     }
4492 
enqueueDisplayList(DisplayList displayList)4493     public void enqueueDisplayList(DisplayList displayList) {
4494         mDisplayLists.add(displayList);
4495 
4496         mHandler.removeMessages(MSG_INVALIDATE_DISPLAY_LIST);
4497         Message msg = mHandler.obtainMessage(MSG_INVALIDATE_DISPLAY_LIST);
4498         mHandler.sendMessage(msg);
4499     }
4500 
dequeueDisplayList(DisplayList displayList)4501     public void dequeueDisplayList(DisplayList displayList) {
4502         if (mDisplayLists.remove(displayList)) {
4503             displayList.invalidate();
4504             if (mDisplayLists.size() == 0) {
4505                 mHandler.removeMessages(MSG_INVALIDATE_DISPLAY_LIST);
4506             }
4507         }
4508     }
4509 
cancelInvalidate(View view)4510     public void cancelInvalidate(View view) {
4511         mHandler.removeMessages(MSG_INVALIDATE, view);
4512         // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning
4513         // them to the pool
4514         mHandler.removeMessages(MSG_INVALIDATE_RECT, view);
4515         mInvalidateOnAnimationRunnable.removeView(view);
4516     }
4517 
dispatchKey(KeyEvent event)4518     public void dispatchKey(KeyEvent event) {
4519         Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY, event);
4520         msg.setAsynchronous(true);
4521         mHandler.sendMessage(msg);
4522     }
4523 
dispatchKeyFromIme(KeyEvent event)4524     public void dispatchKeyFromIme(KeyEvent event) {
4525         Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
4526         msg.setAsynchronous(true);
4527         mHandler.sendMessage(msg);
4528     }
4529 
dispatchUnhandledKey(KeyEvent event)4530     public void dispatchUnhandledKey(KeyEvent event) {
4531         if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
4532             final KeyCharacterMap kcm = event.getKeyCharacterMap();
4533             final int keyCode = event.getKeyCode();
4534             final int metaState = event.getMetaState();
4535 
4536             // Check for fallback actions specified by the key character map.
4537             KeyCharacterMap.FallbackAction fallbackAction =
4538                     kcm.getFallbackAction(keyCode, metaState);
4539             if (fallbackAction != null) {
4540                 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
4541                 KeyEvent fallbackEvent = KeyEvent.obtain(
4542                         event.getDownTime(), event.getEventTime(),
4543                         event.getAction(), fallbackAction.keyCode,
4544                         event.getRepeatCount(), fallbackAction.metaState,
4545                         event.getDeviceId(), event.getScanCode(),
4546                         flags, event.getSource(), null);
4547                 fallbackAction.recycle();
4548 
4549                 dispatchKey(fallbackEvent);
4550             }
4551         }
4552     }
4553 
dispatchAppVisibility(boolean visible)4554     public void dispatchAppVisibility(boolean visible) {
4555         Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
4556         msg.arg1 = visible ? 1 : 0;
4557         mHandler.sendMessage(msg);
4558     }
4559 
dispatchScreenStateChange(boolean on)4560     public void dispatchScreenStateChange(boolean on) {
4561         Message msg = mHandler.obtainMessage(MSG_DISPATCH_SCREEN_STATE);
4562         msg.arg1 = on ? 1 : 0;
4563         mHandler.sendMessage(msg);
4564     }
4565 
dispatchGetNewSurface()4566     public void dispatchGetNewSurface() {
4567         Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
4568         mHandler.sendMessage(msg);
4569     }
4570 
windowFocusChanged(boolean hasFocus, boolean inTouchMode)4571     public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
4572         Message msg = Message.obtain();
4573         msg.what = MSG_WINDOW_FOCUS_CHANGED;
4574         msg.arg1 = hasFocus ? 1 : 0;
4575         msg.arg2 = inTouchMode ? 1 : 0;
4576         mHandler.sendMessage(msg);
4577     }
4578 
dispatchCloseSystemDialogs(String reason)4579     public void dispatchCloseSystemDialogs(String reason) {
4580         Message msg = Message.obtain();
4581         msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
4582         msg.obj = reason;
4583         mHandler.sendMessage(msg);
4584     }
4585 
dispatchDragEvent(DragEvent event)4586     public void dispatchDragEvent(DragEvent event) {
4587         final int what;
4588         if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
4589             what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
4590             mHandler.removeMessages(what);
4591         } else {
4592             what = MSG_DISPATCH_DRAG_EVENT;
4593         }
4594         Message msg = mHandler.obtainMessage(what, event);
4595         mHandler.sendMessage(msg);
4596     }
4597 
dispatchSystemUiVisibilityChanged(int seq, int globalVisibility, int localValue, int localChanges)4598     public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
4599             int localValue, int localChanges) {
4600         SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
4601         args.seq = seq;
4602         args.globalVisibility = globalVisibility;
4603         args.localValue = localValue;
4604         args.localChanges = localChanges;
4605         mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
4606     }
4607 
dispatchDoneAnimating()4608     public void dispatchDoneAnimating() {
4609         mHandler.sendEmptyMessage(MSG_DISPATCH_DONE_ANIMATING);
4610     }
4611 
dispatchCheckFocus()4612     public void dispatchCheckFocus() {
4613         if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
4614             // This will result in a call to checkFocus() below.
4615             mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
4616         }
4617     }
4618 
4619     /**
4620      * Post a callback to send a
4621      * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
4622      * This event is send at most once every
4623      * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
4624      */
postSendWindowContentChangedCallback(View source)4625     private void postSendWindowContentChangedCallback(View source) {
4626         if (mSendWindowContentChangedAccessibilityEvent == null) {
4627             mSendWindowContentChangedAccessibilityEvent =
4628                 new SendWindowContentChangedAccessibilityEvent();
4629         }
4630         View oldSource = mSendWindowContentChangedAccessibilityEvent.mSource;
4631         if (oldSource == null) {
4632             mSendWindowContentChangedAccessibilityEvent.mSource = source;
4633             mHandler.postDelayed(mSendWindowContentChangedAccessibilityEvent,
4634                     ViewConfiguration.getSendRecurringAccessibilityEventsInterval());
4635         } else {
4636             mSendWindowContentChangedAccessibilityEvent.mSource =
4637                     getCommonPredecessor(oldSource, source);
4638         }
4639     }
4640 
4641     /**
4642      * Remove a posted callback to send a
4643      * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
4644      */
removeSendWindowContentChangedCallback()4645     private void removeSendWindowContentChangedCallback() {
4646         if (mSendWindowContentChangedAccessibilityEvent != null) {
4647             mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
4648         }
4649     }
4650 
showContextMenuForChild(View originalView)4651     public boolean showContextMenuForChild(View originalView) {
4652         return false;
4653     }
4654 
startActionModeForChild(View originalView, ActionMode.Callback callback)4655     public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
4656         return null;
4657     }
4658 
createContextMenu(ContextMenu menu)4659     public void createContextMenu(ContextMenu menu) {
4660     }
4661 
childDrawableStateChanged(View child)4662     public void childDrawableStateChanged(View child) {
4663     }
4664 
requestSendAccessibilityEvent(View child, AccessibilityEvent event)4665     public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
4666         if (mView == null) {
4667             return false;
4668         }
4669         // Intercept accessibility focus events fired by virtual nodes to keep
4670         // track of accessibility focus position in such nodes.
4671         final int eventType = event.getEventType();
4672         switch (eventType) {
4673             case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
4674                 final long sourceNodeId = event.getSourceNodeId();
4675                 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
4676                         sourceNodeId);
4677                 View source = mView.findViewByAccessibilityId(accessibilityViewId);
4678                 if (source != null) {
4679                     AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
4680                     if (provider != null) {
4681                         AccessibilityNodeInfo node = provider.createAccessibilityNodeInfo(
4682                                 AccessibilityNodeInfo.getVirtualDescendantId(sourceNodeId));
4683                         setAccessibilityFocus(source, node);
4684                     }
4685                 }
4686             } break;
4687             case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
4688                 final long sourceNodeId = event.getSourceNodeId();
4689                 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
4690                         sourceNodeId);
4691                 View source = mView.findViewByAccessibilityId(accessibilityViewId);
4692                 if (source != null) {
4693                     AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
4694                     if (provider != null) {
4695                         setAccessibilityFocus(null, null);
4696                     }
4697                 }
4698             } break;
4699         }
4700         mAccessibilityManager.sendAccessibilityEvent(event);
4701         return true;
4702     }
4703 
4704     @Override
childAccessibilityStateChanged(View child)4705     public void childAccessibilityStateChanged(View child) {
4706         postSendWindowContentChangedCallback(child);
4707     }
4708 
getCommonPredecessor(View first, View second)4709     private View getCommonPredecessor(View first, View second) {
4710         if (mAttachInfo != null) {
4711             if (mTempHashSet == null) {
4712                 mTempHashSet = new HashSet<View>();
4713             }
4714             HashSet<View> seen = mTempHashSet;
4715             seen.clear();
4716             View firstCurrent = first;
4717             while (firstCurrent != null) {
4718                 seen.add(firstCurrent);
4719                 ViewParent firstCurrentParent = firstCurrent.mParent;
4720                 if (firstCurrentParent instanceof View) {
4721                     firstCurrent = (View) firstCurrentParent;
4722                 } else {
4723                     firstCurrent = null;
4724                 }
4725             }
4726             View secondCurrent = second;
4727             while (secondCurrent != null) {
4728                 if (seen.contains(secondCurrent)) {
4729                     seen.clear();
4730                     return secondCurrent;
4731                 }
4732                 ViewParent secondCurrentParent = secondCurrent.mParent;
4733                 if (secondCurrentParent instanceof View) {
4734                     secondCurrent = (View) secondCurrentParent;
4735                 } else {
4736                     secondCurrent = null;
4737                 }
4738             }
4739             seen.clear();
4740         }
4741         return null;
4742     }
4743 
checkThread()4744     void checkThread() {
4745         if (mThread != Thread.currentThread()) {
4746             throw new CalledFromWrongThreadException(
4747                     "Only the original thread that created a view hierarchy can touch its views.");
4748         }
4749     }
4750 
requestDisallowInterceptTouchEvent(boolean disallowIntercept)4751     public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
4752         // ViewAncestor never intercepts touch event, so this can be a no-op
4753     }
4754 
requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate)4755     public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
4756         final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
4757         if (rectangle != null) {
4758             mTempRect.set(rectangle);
4759             mTempRect.offset(0, -mCurScrollY);
4760             mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
4761             try {
4762                 mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect, immediate);
4763             } catch (RemoteException re) {
4764                 /* ignore */
4765             }
4766         }
4767         return scrolled;
4768     }
4769 
childHasTransientStateChanged(View child, boolean hasTransientState)4770     public void childHasTransientStateChanged(View child, boolean hasTransientState) {
4771         // Do nothing.
4772     }
4773 
4774     class TakenSurfaceHolder extends BaseSurfaceHolder {
4775         @Override
onAllowLockCanvas()4776         public boolean onAllowLockCanvas() {
4777             return mDrawingAllowed;
4778         }
4779 
4780         @Override
onRelayoutContainer()4781         public void onRelayoutContainer() {
4782             // Not currently interesting -- from changing between fixed and layout size.
4783         }
4784 
setFormat(int format)4785         public void setFormat(int format) {
4786             ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
4787         }
4788 
setType(int type)4789         public void setType(int type) {
4790             ((RootViewSurfaceTaker)mView).setSurfaceType(type);
4791         }
4792 
4793         @Override
onUpdateSurface()4794         public void onUpdateSurface() {
4795             // We take care of format and type changes on our own.
4796             throw new IllegalStateException("Shouldn't be here");
4797         }
4798 
isCreating()4799         public boolean isCreating() {
4800             return mIsCreating;
4801         }
4802 
4803         @Override
setFixedSize(int width, int height)4804         public void setFixedSize(int width, int height) {
4805             throw new UnsupportedOperationException(
4806                     "Currently only support sizing from layout");
4807         }
4808 
setKeepScreenOn(boolean screenOn)4809         public void setKeepScreenOn(boolean screenOn) {
4810             ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
4811         }
4812     }
4813 
4814     static final class InputMethodCallback implements InputMethodManager.FinishedEventCallback {
4815         private WeakReference<ViewRootImpl> mViewAncestor;
4816 
InputMethodCallback(ViewRootImpl viewAncestor)4817         public InputMethodCallback(ViewRootImpl viewAncestor) {
4818             mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
4819         }
4820 
4821         @Override
finishedEvent(int seq, boolean handled)4822         public void finishedEvent(int seq, boolean handled) {
4823             final ViewRootImpl viewAncestor = mViewAncestor.get();
4824             if (viewAncestor != null) {
4825                 viewAncestor.dispatchImeFinishedEvent(seq, handled);
4826             }
4827         }
4828     }
4829 
4830     static class W extends IWindow.Stub {
4831         private final WeakReference<ViewRootImpl> mViewAncestor;
4832         private final IWindowSession mWindowSession;
4833 
W(ViewRootImpl viewAncestor)4834         W(ViewRootImpl viewAncestor) {
4835             mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
4836             mWindowSession = viewAncestor.mWindowSession;
4837         }
4838 
resized(Rect frame, Rect contentInsets, Rect visibleInsets, boolean reportDraw, Configuration newConfig)4839         public void resized(Rect frame, Rect contentInsets,
4840                 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
4841             final ViewRootImpl viewAncestor = mViewAncestor.get();
4842             if (viewAncestor != null) {
4843                 viewAncestor.dispatchResized(frame, contentInsets,
4844                         visibleInsets, reportDraw, newConfig);
4845             }
4846         }
4847 
4848         @Override
moved(int newX, int newY)4849         public void moved(int newX, int newY) {
4850             final ViewRootImpl viewAncestor = mViewAncestor.get();
4851             if (viewAncestor != null) {
4852                 viewAncestor.dispatchMoved(newX, newY);
4853             }
4854         }
4855 
dispatchAppVisibility(boolean visible)4856         public void dispatchAppVisibility(boolean visible) {
4857             final ViewRootImpl viewAncestor = mViewAncestor.get();
4858             if (viewAncestor != null) {
4859                 viewAncestor.dispatchAppVisibility(visible);
4860             }
4861         }
4862 
dispatchScreenState(boolean on)4863         public void dispatchScreenState(boolean on) {
4864             final ViewRootImpl viewAncestor = mViewAncestor.get();
4865             if (viewAncestor != null) {
4866                 viewAncestor.dispatchScreenStateChange(on);
4867             }
4868         }
4869 
dispatchGetNewSurface()4870         public void dispatchGetNewSurface() {
4871             final ViewRootImpl viewAncestor = mViewAncestor.get();
4872             if (viewAncestor != null) {
4873                 viewAncestor.dispatchGetNewSurface();
4874             }
4875         }
4876 
windowFocusChanged(boolean hasFocus, boolean inTouchMode)4877         public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
4878             final ViewRootImpl viewAncestor = mViewAncestor.get();
4879             if (viewAncestor != null) {
4880                 viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
4881             }
4882         }
4883 
checkCallingPermission(String permission)4884         private static int checkCallingPermission(String permission) {
4885             try {
4886                 return ActivityManagerNative.getDefault().checkPermission(
4887                         permission, Binder.getCallingPid(), Binder.getCallingUid());
4888             } catch (RemoteException e) {
4889                 return PackageManager.PERMISSION_DENIED;
4890             }
4891         }
4892 
executeCommand(String command, String parameters, ParcelFileDescriptor out)4893         public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
4894             final ViewRootImpl viewAncestor = mViewAncestor.get();
4895             if (viewAncestor != null) {
4896                 final View view = viewAncestor.mView;
4897                 if (view != null) {
4898                     if (checkCallingPermission(Manifest.permission.DUMP) !=
4899                             PackageManager.PERMISSION_GRANTED) {
4900                         throw new SecurityException("Insufficient permissions to invoke"
4901                                 + " executeCommand() from pid=" + Binder.getCallingPid()
4902                                 + ", uid=" + Binder.getCallingUid());
4903                     }
4904 
4905                     OutputStream clientStream = null;
4906                     try {
4907                         clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
4908                         ViewDebug.dispatchCommand(view, command, parameters, clientStream);
4909                     } catch (IOException e) {
4910                         e.printStackTrace();
4911                     } finally {
4912                         if (clientStream != null) {
4913                             try {
4914                                 clientStream.close();
4915                             } catch (IOException e) {
4916                                 e.printStackTrace();
4917                             }
4918                         }
4919                     }
4920                 }
4921             }
4922         }
4923 
closeSystemDialogs(String reason)4924         public void closeSystemDialogs(String reason) {
4925             final ViewRootImpl viewAncestor = mViewAncestor.get();
4926             if (viewAncestor != null) {
4927                 viewAncestor.dispatchCloseSystemDialogs(reason);
4928             }
4929         }
4930 
dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, boolean sync)4931         public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
4932                 boolean sync) {
4933             if (sync) {
4934                 try {
4935                     mWindowSession.wallpaperOffsetsComplete(asBinder());
4936                 } catch (RemoteException e) {
4937                 }
4938             }
4939         }
4940 
dispatchWallpaperCommand(String action, int x, int y, int z, Bundle extras, boolean sync)4941         public void dispatchWallpaperCommand(String action, int x, int y,
4942                 int z, Bundle extras, boolean sync) {
4943             if (sync) {
4944                 try {
4945                     mWindowSession.wallpaperCommandComplete(asBinder(), null);
4946                 } catch (RemoteException e) {
4947                 }
4948             }
4949         }
4950 
4951         /* Drag/drop */
dispatchDragEvent(DragEvent event)4952         public void dispatchDragEvent(DragEvent event) {
4953             final ViewRootImpl viewAncestor = mViewAncestor.get();
4954             if (viewAncestor != null) {
4955                 viewAncestor.dispatchDragEvent(event);
4956             }
4957         }
4958 
dispatchSystemUiVisibilityChanged(int seq, int globalVisibility, int localValue, int localChanges)4959         public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
4960                 int localValue, int localChanges) {
4961             final ViewRootImpl viewAncestor = mViewAncestor.get();
4962             if (viewAncestor != null) {
4963                 viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility,
4964                         localValue, localChanges);
4965             }
4966         }
4967 
doneAnimating()4968         public void doneAnimating() {
4969             final ViewRootImpl viewAncestor = mViewAncestor.get();
4970             if (viewAncestor != null) {
4971                 viewAncestor.dispatchDoneAnimating();
4972             }
4973         }
4974     }
4975 
4976     /**
4977      * Maintains state information for a single trackball axis, generating
4978      * discrete (DPAD) movements based on raw trackball motion.
4979      */
4980     static final class TrackballAxis {
4981         /**
4982          * The maximum amount of acceleration we will apply.
4983          */
4984         static final float MAX_ACCELERATION = 20;
4985 
4986         /**
4987          * The maximum amount of time (in milliseconds) between events in order
4988          * for us to consider the user to be doing fast trackball movements,
4989          * and thus apply an acceleration.
4990          */
4991         static final long FAST_MOVE_TIME = 150;
4992 
4993         /**
4994          * Scaling factor to the time (in milliseconds) between events to how
4995          * much to multiple/divide the current acceleration.  When movement
4996          * is < FAST_MOVE_TIME this multiplies the acceleration; when >
4997          * FAST_MOVE_TIME it divides it.
4998          */
4999         static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
5000 
5001         float position;
5002         float absPosition;
5003         float acceleration = 1;
5004         long lastMoveTime = 0;
5005         int step;
5006         int dir;
5007         int nonAccelMovement;
5008 
reset(int _step)5009         void reset(int _step) {
5010             position = 0;
5011             acceleration = 1;
5012             lastMoveTime = 0;
5013             step = _step;
5014             dir = 0;
5015         }
5016 
5017         /**
5018          * Add trackball movement into the state.  If the direction of movement
5019          * has been reversed, the state is reset before adding the
5020          * movement (so that you don't have to compensate for any previously
5021          * collected movement before see the result of the movement in the
5022          * new direction).
5023          *
5024          * @return Returns the absolute value of the amount of movement
5025          * collected so far.
5026          */
collect(float off, long time, String axis)5027         float collect(float off, long time, String axis) {
5028             long normTime;
5029             if (off > 0) {
5030                 normTime = (long)(off * FAST_MOVE_TIME);
5031                 if (dir < 0) {
5032                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
5033                     position = 0;
5034                     step = 0;
5035                     acceleration = 1;
5036                     lastMoveTime = 0;
5037                 }
5038                 dir = 1;
5039             } else if (off < 0) {
5040                 normTime = (long)((-off) * FAST_MOVE_TIME);
5041                 if (dir > 0) {
5042                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
5043                     position = 0;
5044                     step = 0;
5045                     acceleration = 1;
5046                     lastMoveTime = 0;
5047                 }
5048                 dir = -1;
5049             } else {
5050                 normTime = 0;
5051             }
5052 
5053             // The number of milliseconds between each movement that is
5054             // considered "normal" and will not result in any acceleration
5055             // or deceleration, scaled by the offset we have here.
5056             if (normTime > 0) {
5057                 long delta = time - lastMoveTime;
5058                 lastMoveTime = time;
5059                 float acc = acceleration;
5060                 if (delta < normTime) {
5061                     // The user is scrolling rapidly, so increase acceleration.
5062                     float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
5063                     if (scale > 1) acc *= scale;
5064                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
5065                             + off + " normTime=" + normTime + " delta=" + delta
5066                             + " scale=" + scale + " acc=" + acc);
5067                     acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
5068                 } else {
5069                     // The user is scrolling slowly, so decrease acceleration.
5070                     float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
5071                     if (scale > 1) acc /= scale;
5072                     if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
5073                             + off + " normTime=" + normTime + " delta=" + delta
5074                             + " scale=" + scale + " acc=" + acc);
5075                     acceleration = acc > 1 ? acc : 1;
5076                 }
5077             }
5078             position += off;
5079             return (absPosition = Math.abs(position));
5080         }
5081 
5082         /**
5083          * Generate the number of discrete movement events appropriate for
5084          * the currently collected trackball movement.
5085          *
5086          * @param precision The minimum movement required to generate the
5087          * first discrete movement.
5088          *
5089          * @return Returns the number of discrete movements, either positive
5090          * or negative, or 0 if there is not enough trackball movement yet
5091          * for a discrete movement.
5092          */
generate(float precision)5093         int generate(float precision) {
5094             int movement = 0;
5095             nonAccelMovement = 0;
5096             do {
5097                 final int dir = position >= 0 ? 1 : -1;
5098                 switch (step) {
5099                     // If we are going to execute the first step, then we want
5100                     // to do this as soon as possible instead of waiting for
5101                     // a full movement, in order to make things look responsive.
5102                     case 0:
5103                         if (absPosition < precision) {
5104                             return movement;
5105                         }
5106                         movement += dir;
5107                         nonAccelMovement += dir;
5108                         step = 1;
5109                         break;
5110                     // If we have generated the first movement, then we need
5111                     // to wait for the second complete trackball motion before
5112                     // generating the second discrete movement.
5113                     case 1:
5114                         if (absPosition < 2) {
5115                             return movement;
5116                         }
5117                         movement += dir;
5118                         nonAccelMovement += dir;
5119                         position += dir > 0 ? -2 : 2;
5120                         absPosition = Math.abs(position);
5121                         step = 2;
5122                         break;
5123                     // After the first two, we generate discrete movements
5124                     // consistently with the trackball, applying an acceleration
5125                     // if the trackball is moving quickly.  This is a simple
5126                     // acceleration on top of what we already compute based
5127                     // on how quickly the wheel is being turned, to apply
5128                     // a longer increasing acceleration to continuous movement
5129                     // in one direction.
5130                     default:
5131                         if (absPosition < 1) {
5132                             return movement;
5133                         }
5134                         movement += dir;
5135                         position += dir >= 0 ? -1 : 1;
5136                         absPosition = Math.abs(position);
5137                         float acc = acceleration;
5138                         acc *= 1.1f;
5139                         acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
5140                         break;
5141                 }
5142             } while (true);
5143         }
5144     }
5145 
5146     public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
5147         public CalledFromWrongThreadException(String msg) {
5148             super(msg);
5149         }
5150     }
5151 
5152     private SurfaceHolder mHolder = new SurfaceHolder() {
5153         // we only need a SurfaceHolder for opengl. it would be nice
5154         // to implement everything else though, especially the callback
5155         // support (opengl doesn't make use of it right now, but eventually
5156         // will).
5157         public Surface getSurface() {
5158             return mSurface;
5159         }
5160 
5161         public boolean isCreating() {
5162             return false;
5163         }
5164 
5165         public void addCallback(Callback callback) {
5166         }
5167 
5168         public void removeCallback(Callback callback) {
5169         }
5170 
5171         public void setFixedSize(int width, int height) {
5172         }
5173 
5174         public void setSizeFromLayout() {
5175         }
5176 
5177         public void setFormat(int format) {
5178         }
5179 
5180         public void setType(int type) {
5181         }
5182 
5183         public void setKeepScreenOn(boolean screenOn) {
5184         }
5185 
5186         public Canvas lockCanvas() {
5187             return null;
5188         }
5189 
5190         public Canvas lockCanvas(Rect dirty) {
5191             return null;
5192         }
5193 
5194         public void unlockCanvasAndPost(Canvas canvas) {
5195         }
5196         public Rect getSurfaceFrame() {
5197             return null;
5198         }
5199     };
5200 
5201     static RunQueue getRunQueue() {
5202         RunQueue rq = sRunQueues.get();
5203         if (rq != null) {
5204             return rq;
5205         }
5206         rq = new RunQueue();
5207         sRunQueues.set(rq);
5208         return rq;
5209     }
5210 
5211     /**
5212      * The run queue is used to enqueue pending work from Views when no Handler is
5213      * attached.  The work is executed during the next call to performTraversals on
5214      * the thread.
5215      * @hide
5216      */
5217     static final class RunQueue {
5218         private final ArrayList<HandlerAction> mActions = new ArrayList<HandlerAction>();
5219 
5220         void post(Runnable action) {
5221             postDelayed(action, 0);
5222         }
5223 
5224         void postDelayed(Runnable action, long delayMillis) {
5225             HandlerAction handlerAction = new HandlerAction();
5226             handlerAction.action = action;
5227             handlerAction.delay = delayMillis;
5228 
5229             synchronized (mActions) {
5230                 mActions.add(handlerAction);
5231             }
5232         }
5233 
5234         void removeCallbacks(Runnable action) {
5235             final HandlerAction handlerAction = new HandlerAction();
5236             handlerAction.action = action;
5237 
5238             synchronized (mActions) {
5239                 final ArrayList<HandlerAction> actions = mActions;
5240 
5241                 while (actions.remove(handlerAction)) {
5242                     // Keep going
5243                 }
5244             }
5245         }
5246 
5247         void executeActions(Handler handler) {
5248             synchronized (mActions) {
5249                 final ArrayList<HandlerAction> actions = mActions;
5250                 final int count = actions.size();
5251 
5252                 for (int i = 0; i < count; i++) {
5253                     final HandlerAction handlerAction = actions.get(i);
5254                     handler.postDelayed(handlerAction.action, handlerAction.delay);
5255                 }
5256 
5257                 actions.clear();
5258             }
5259         }
5260 
5261         private static class HandlerAction {
5262             Runnable action;
5263             long delay;
5264 
5265             @Override
5266             public boolean equals(Object o) {
5267                 if (this == o) return true;
5268                 if (o == null || getClass() != o.getClass()) return false;
5269 
5270                 HandlerAction that = (HandlerAction) o;
5271                 return !(action != null ? !action.equals(that.action) : that.action != null);
5272 
5273             }
5274 
5275             @Override
5276             public int hashCode() {
5277                 int result = action != null ? action.hashCode() : 0;
5278                 result = 31 * result + (int) (delay ^ (delay >>> 32));
5279                 return result;
5280             }
5281         }
5282     }
5283 
5284     /**
5285      * Class for managing the accessibility interaction connection
5286      * based on the global accessibility state.
5287      */
5288     final class AccessibilityInteractionConnectionManager
5289             implements AccessibilityStateChangeListener {
onAccessibilityStateChanged(boolean enabled)5290         public void onAccessibilityStateChanged(boolean enabled) {
5291             if (enabled) {
5292                 ensureConnection();
5293                 if (mAttachInfo != null && mAttachInfo.mHasWindowFocus) {
5294                     mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
5295                     View focusedView = mView.findFocus();
5296                     if (focusedView != null && focusedView != mView) {
5297                         focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
5298                     }
5299                 }
5300             } else {
5301                 ensureNoConnection();
5302                 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
5303             }
5304         }
5305 
ensureConnection()5306         public void ensureConnection() {
5307             if (mAttachInfo != null) {
5308                 final boolean registered =
5309                     mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED;
5310                 if (!registered) {
5311                     mAttachInfo.mAccessibilityWindowId =
5312                         mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
5313                                 new AccessibilityInteractionConnection(ViewRootImpl.this));
5314                 }
5315             }
5316         }
5317 
ensureNoConnection()5318         public void ensureNoConnection() {
5319             final boolean registered =
5320                 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED;
5321             if (registered) {
5322                 mAttachInfo.mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED;
5323                 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
5324             }
5325         }
5326     }
5327 
5328     /**
5329      * This class is an interface this ViewAncestor provides to the
5330      * AccessibilityManagerService to the latter can interact with
5331      * the view hierarchy in this ViewAncestor.
5332      */
5333     static final class AccessibilityInteractionConnection
5334             extends IAccessibilityInteractionConnection.Stub {
5335         private final WeakReference<ViewRootImpl> mViewRootImpl;
5336 
AccessibilityInteractionConnection(ViewRootImpl viewRootImpl)5337         AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) {
5338             mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
5339         }
5340 
5341         @Override
findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid)5342         public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
5343                 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
5344                 int interrogatingPid, long interrogatingTid) {
5345             ViewRootImpl viewRootImpl = mViewRootImpl.get();
5346             if (viewRootImpl != null && viewRootImpl.mView != null) {
5347                 viewRootImpl.getAccessibilityInteractionController()
5348                     .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
5349                             interactionId, callback, flags, interrogatingPid, interrogatingTid);
5350             } else {
5351                 // We cannot make the call and notify the caller so it does not wait.
5352                 try {
5353                     callback.setFindAccessibilityNodeInfosResult(null, interactionId);
5354                 } catch (RemoteException re) {
5355                     /* best effort - ignore */
5356                 }
5357             }
5358         }
5359 
5360         @Override
performAccessibilityAction(long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interogatingPid, long interrogatingTid)5361         public void performAccessibilityAction(long accessibilityNodeId, int action,
5362                 Bundle arguments, int interactionId,
5363                 IAccessibilityInteractionConnectionCallback callback, int flags,
5364                 int interogatingPid, long interrogatingTid) {
5365             ViewRootImpl viewRootImpl = mViewRootImpl.get();
5366             if (viewRootImpl != null && viewRootImpl.mView != null) {
5367                 viewRootImpl.getAccessibilityInteractionController()
5368                     .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
5369                             interactionId, callback, flags, interogatingPid, interrogatingTid);
5370             } else {
5371                 // We cannot make the call and notify the caller so it does not wait.
5372                 try {
5373                     callback.setPerformAccessibilityActionResult(false, interactionId);
5374                 } catch (RemoteException re) {
5375                     /* best effort - ignore */
5376                 }
5377             }
5378         }
5379 
5380         @Override
findAccessibilityNodeInfoByViewId(long accessibilityNodeId, int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid)5381         public void findAccessibilityNodeInfoByViewId(long accessibilityNodeId, int viewId,
5382                 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
5383                 int interrogatingPid, long interrogatingTid) {
5384             ViewRootImpl viewRootImpl = mViewRootImpl.get();
5385             if (viewRootImpl != null && viewRootImpl.mView != null) {
5386                 viewRootImpl.getAccessibilityInteractionController()
5387                     .findAccessibilityNodeInfoByViewIdClientThread(accessibilityNodeId, viewId,
5388                             interactionId, callback, flags, interrogatingPid, interrogatingTid);
5389             } else {
5390                 // We cannot make the call and notify the caller so it does not wait.
5391                 try {
5392                     callback.setFindAccessibilityNodeInfoResult(null, interactionId);
5393                 } catch (RemoteException re) {
5394                     /* best effort - ignore */
5395                 }
5396             }
5397         }
5398 
5399         @Override
findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid)5400         public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
5401                 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
5402                 int interrogatingPid, long interrogatingTid) {
5403             ViewRootImpl viewRootImpl = mViewRootImpl.get();
5404             if (viewRootImpl != null && viewRootImpl.mView != null) {
5405                 viewRootImpl.getAccessibilityInteractionController()
5406                     .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
5407                             interactionId, callback, flags, interrogatingPid, interrogatingTid);
5408             } else {
5409                 // We cannot make the call and notify the caller so it does not wait.
5410                 try {
5411                     callback.setFindAccessibilityNodeInfosResult(null, interactionId);
5412                 } catch (RemoteException re) {
5413                     /* best effort - ignore */
5414                 }
5415             }
5416         }
5417 
5418         @Override
findFocus(long accessibilityNodeId, int focusType, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid)5419         public void findFocus(long accessibilityNodeId, int focusType, int interactionId,
5420                 IAccessibilityInteractionConnectionCallback callback, int flags,
5421                 int interrogatingPid, long interrogatingTid) {
5422             ViewRootImpl viewRootImpl = mViewRootImpl.get();
5423             if (viewRootImpl != null && viewRootImpl.mView != null) {
5424                 viewRootImpl.getAccessibilityInteractionController()
5425                     .findFocusClientThread(accessibilityNodeId, focusType, interactionId, callback,
5426                             flags, interrogatingPid, interrogatingTid);
5427             } else {
5428                 // We cannot make the call and notify the caller so it does not wait.
5429                 try {
5430                     callback.setFindAccessibilityNodeInfoResult(null, interactionId);
5431                 } catch (RemoteException re) {
5432                     /* best effort - ignore */
5433                 }
5434             }
5435         }
5436 
5437         @Override
focusSearch(long accessibilityNodeId, int direction, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, long interrogatingTid)5438         public void focusSearch(long accessibilityNodeId, int direction, int interactionId,
5439                 IAccessibilityInteractionConnectionCallback callback, int flags,
5440                 int interrogatingPid, long interrogatingTid) {
5441             ViewRootImpl viewRootImpl = mViewRootImpl.get();
5442             if (viewRootImpl != null && viewRootImpl.mView != null) {
5443                 viewRootImpl.getAccessibilityInteractionController()
5444                     .focusSearchClientThread(accessibilityNodeId, direction, interactionId,
5445                             callback, flags, interrogatingPid, interrogatingTid);
5446             } else {
5447                 // We cannot make the call and notify the caller so it does not wait.
5448                 try {
5449                     callback.setFindAccessibilityNodeInfoResult(null, interactionId);
5450                 } catch (RemoteException re) {
5451                     /* best effort - ignore */
5452                 }
5453             }
5454         }
5455     }
5456 
5457     private class SendWindowContentChangedAccessibilityEvent implements Runnable {
5458         public View mSource;
5459 
run()5460         public void run() {
5461             if (mSource != null) {
5462                 mSource.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
5463                 mSource.resetAccessibilityStateChanged();
5464                 mSource = null;
5465             }
5466         }
5467     }
5468 }
5469