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