blob: b1d3d450a7f8f030478648c9aff44c24389c342c [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package android.view;
18
Romain Guy6b7bd242010-10-06 19:49:23 -070019import android.Manifest;
Chet Haasecca2c982011-05-20 14:34:18 -070020import android.animation.LayoutTransition;
Romain Guy6b7bd242010-10-06 19:49:23 -070021import android.app.ActivityManagerNative;
22import android.content.ClipDescription;
23import android.content.ComponentCallbacks;
24import android.content.Context;
25import android.content.pm.PackageManager;
26import android.content.res.CompatibilityInfo;
27import android.content.res.Configuration;
28import android.content.res.Resources;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.graphics.Canvas;
Alan Viverettefed3f722013-11-14 14:48:20 -080030import android.graphics.Matrix;
Dianne Hackborn0f761d62010-11-30 22:06:10 -080031import android.graphics.Paint;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.graphics.PixelFormat;
Christopher Tate2c095f32010-10-04 14:13:40 -070033import android.graphics.Point;
Christopher Tatea53146c2010-09-07 11:57:52 -070034import android.graphics.PointF;
Romain Guy6b7bd242010-10-06 19:49:23 -070035import android.graphics.PorterDuff;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.graphics.Rect;
37import android.graphics.Region;
Svetoslav Ganov42138042012-03-20 11:51:39 -070038import android.graphics.drawable.Drawable;
Jeff Brownd912e1f2014-04-11 18:46:22 -070039import android.hardware.display.DisplayManager;
40import android.hardware.display.DisplayManager.DisplayListener;
Romain Guy6b7bd242010-10-06 19:49:23 -070041import android.media.AudioManager;
42import android.os.Binder;
Michael Kolb437d3132014-06-20 13:28:44 -070043import android.os.Build;
Romain Guy6b7bd242010-10-06 19:49:23 -070044import android.os.Bundle;
45import android.os.Debug;
46import android.os.Handler;
Romain Guy6b7bd242010-10-06 19:49:23 -070047import android.os.Looper;
48import android.os.Message;
49import android.os.ParcelFileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.os.Process;
Romain Guy6b7bd242010-10-06 19:49:23 -070051import android.os.RemoteException;
Romain Guy6b7bd242010-10-06 19:49:23 -070052import android.os.SystemClock;
Romain Guy59a12ca2011-06-09 17:48:21 -070053import android.os.SystemProperties;
Jeff Brown481c1572012-03-09 14:41:15 -080054import android.os.Trace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.util.AndroidRuntimeException;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070056import android.util.DisplayMetrics;
Romain Guy6b7bd242010-10-06 19:49:23 -070057import android.util.Log;
Chet Haase949dbf72010-08-11 18:41:06 -070058import android.util.Slog;
Dianne Hackborn711e62a2010-11-29 16:38:22 -080059import android.util.TypedValue;
John Reck44fd8d22014-02-26 11:00:11 -080060import android.view.Surface.OutOfResourcesException;
Jeff Browna175a5b2012-02-15 19:18:31 -080061import android.view.View.AttachInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.view.View.MeasureSpec;
svetoslavganov75986cf2009-05-14 22:28:01 -070063import android.view.accessibility.AccessibilityEvent;
64import android.view.accessibility.AccessibilityManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070065import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
Chris Craikcce47eb2014-07-16 15:12:15 -070066import android.view.accessibility.AccessibilityManager.HighTextContrastChangeListener;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070067import android.view.accessibility.AccessibilityNodeInfo;
Svetoslav Ganov02107852011-10-03 17:06:56 -070068import android.view.accessibility.AccessibilityNodeProvider;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070069import android.view.accessibility.IAccessibilityInteractionConnection;
70import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
Dianne Hackborn0f761d62010-11-30 22:06:10 -080071import android.view.animation.AccelerateDecelerateInterpolator;
72import android.view.animation.Interpolator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.view.inputmethod.InputConnection;
74import android.view.inputmethod.InputMethodManager;
75import android.widget.Scroller;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070076
Svetoslav Ganov42138042012-03-20 11:51:39 -070077import com.android.internal.R;
Svetoslav Ganov758143e2012-08-06 16:40:27 -070078import com.android.internal.os.SomeArgs;
Joe Onorato86f67862010-11-05 18:57:34 -070079import com.android.internal.policy.PolicyManager;
Romain Guy6b7bd242010-10-06 19:49:23 -070080import com.android.internal.view.BaseSurfaceHolder;
Romain Guy6b7bd242010-10-06 19:49:23 -070081import com.android.internal.view.RootViewSurfaceTaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082
Jeff Brown5182c782013-10-15 20:31:52 -070083import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084import java.io.IOException;
85import java.io.OutputStream;
Jeff Brown5182c782013-10-15 20:31:52 -070086import java.io.PrintWriter;
Romain Guy6b7bd242010-10-06 19:49:23 -070087import java.lang.ref.WeakReference;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088import java.util.ArrayList;
Svetoslav Ganov42138042012-03-20 11:51:39 -070089import java.util.HashSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091/**
92 * The top of a view hierarchy, implementing the needed protocol between View
93 * and the WindowManager. This is for the most part an internal implementation
Jeff Brown98365d72012-08-19 20:30:52 -070094 * detail of {@link WindowManagerGlobal}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095 *
96 * {@hide}
97 */
Romain Guy812ccbe2010-06-01 14:07:24 -070098@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
Jeff Browna175a5b2012-02-15 19:18:31 -080099public final class ViewRootImpl implements ViewParent,
Jeff Brown4a06c802012-02-15 15:06:01 -0800100 View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
Dianne Hackborn70a3f672011-08-08 14:32:41 -0700101 private static final String TAG = "ViewRootImpl";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 private static final boolean DBG = false;
Romain Guy812ccbe2010-06-01 14:07:24 -0700103 private static final boolean LOCAL_LOGV = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 /** @noinspection PointlessBooleanExpression*/
105 private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
106 private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800107 private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
109 private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
110 private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
111 private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700112 private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
Chet Haase2f2022a2011-10-11 06:41:59 -0700113 private static final boolean DEBUG_FPS = false;
Michael Wright06a79252014-05-05 17:45:29 -0700114 private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115
Romain Guy59a12ca2011-06-09 17:48:21 -0700116 /**
117 * Set this system property to true to force the view hierarchy to render
118 * at 60 Hz. This can be used to measure the potential framerate.
119 */
Romain Guye9bc11f2013-05-23 12:47:26 -0700120 private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering";
Dan Morrille4d9a012013-03-28 18:10:43 -0700121 private static final String PROPERTY_MEDIA_DISABLED = "config.disable_media";
Michael Chan53071d62009-05-13 17:29:48 -0700122
Michael Kolb437d3132014-06-20 13:28:44 -0700123 // property used by emulator to determine display shape
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700124 public static final String PROPERTY_EMULATOR_CIRCULAR = "ro.emulator.circular";
Michael Kolb437d3132014-06-20 13:28:44 -0700125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 /**
127 * Maximum time we allow the user to roll the trackball enough to generate
128 * a key event, before resetting the counters.
129 */
130 static final int MAX_TRACKBALL_DELAY = 250;
131
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132 static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>();
133
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800134 static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
135 static boolean sFirstDrawComplete = false;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700136
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800137 static final ArrayList<ComponentCallbacks> sConfigCallbacks
138 = new ArrayList<ComponentCallbacks>();
Romain Guy59a12ca2011-06-09 17:48:21 -0700139
Jeff Brownf9e989d2013-04-04 23:04:03 -0700140 final Context mContext;
Jeff Brown98365d72012-08-19 20:30:52 -0700141 final IWindowSession mWindowSession;
142 final Display mDisplay;
Jeff Brownd912e1f2014-04-11 18:46:22 -0700143 final DisplayManager mDisplayManager;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800144 final String mBasePackageName;
Jeff Brown98365d72012-08-19 20:30:52 -0700145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 final int[] mTmpLocation = new int[2];
Romain Guy8506ab42009-06-11 17:35:47 -0700147
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800148 final TypedValue mTmpValue = new TypedValue();
Jeff Brownf9e989d2013-04-04 23:04:03 -0700149
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 final Thread mThread;
151
152 final WindowLeaked mLocation;
153
154 final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
155
156 final W mWindow;
157
Dianne Hackborn180c4842011-09-13 12:39:25 -0700158 final int mTargetSdkVersion;
159
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700160 int mSeq;
161
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 View mView;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700163
164 View mAccessibilityFocusedHost;
165 AccessibilityNodeInfo mAccessibilityFocusedVirtualView;
166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 int mViewVisibility;
168 boolean mAppVisible = true;
Dianne Hackborn180c4842011-09-13 12:39:25 -0700169 int mOrigWindowType = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170
Dianne Hackbornce418e62011-03-01 14:31:38 -0800171 // Set to true if the owner of this window is in the stopped state,
172 // so the window should no longer be active.
173 boolean mStopped = false;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700174
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700175 boolean mLastInCompatMode = false;
176
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700177 SurfaceHolder.Callback2 mSurfaceHolderCallback;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700178 BaseSurfaceHolder mSurfaceHolder;
179 boolean mIsCreating;
180 boolean mDrawingAllowed;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700181
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 final Region mTransparentRegion;
183 final Region mPreviousTransparentRegion;
184
185 int mWidth;
186 int mHeight;
Romain Guy7d7b5492011-01-24 16:33:45 -0800187 Rect mDirty;
Romain Guybb93d552009-03-24 21:04:15 -0700188 boolean mIsAnimating;
Romain Guy8506ab42009-06-11 17:35:47 -0700189
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700190 CompatibilityInfo.Translator mTranslator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191
192 final View.AttachInfo mAttachInfo;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700193 InputChannel mInputChannel;
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -0700194 InputQueue.Callback mInputQueueCallback;
195 InputQueue mInputQueue;
Joe Onorato86f67862010-11-05 18:57:34 -0700196 FallbackEventHandler mFallbackEventHandler;
Jeff Brown96e942d2011-11-30 19:55:01 -0800197 Choreographer mChoreographer;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700198
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 final Rect mTempRect; // used in the transaction to not thrash the heap.
200 final Rect mVisRect; // used to retrieve visible rect of focused view.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201
202 boolean mTraversalScheduled;
Jeff Browne0dbd002012-02-15 19:34:58 -0800203 int mTraversalBarrier;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 boolean mWillDrawSoon;
Craig Mautnerdf2390a2012-08-29 20:59:22 -0700205 /** Set to true while in performTraversals for detecting when die(true) is called from internal
206 * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */
207 boolean mIsInTraversal;
Adrian Roosfa104232014-06-20 16:10:14 -0700208 boolean mApplyInsetsRequested;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 boolean mLayoutRequested;
210 boolean mFirst;
211 boolean mReportNextDraw;
212 boolean mFullRedrawNeeded;
213 boolean mNewSurfaceNeeded;
214 boolean mHasHadWindowFocus;
215 boolean mLastWasImTarget;
Dianne Hackborn12d3a942012-04-27 14:16:30 -0700216 boolean mWindowsAnimating;
Michael Jurkaf42d90102013-05-08 18:00:04 +0200217 boolean mDrawDuringWindowsAnimating;
Romain Guy1f59e5c2012-05-06 14:11:16 -0700218 boolean mIsDrawing;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700219 int mLastSystemUiVisibility;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700220 int mClientWindowLayoutFlags;
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800221 boolean mLastOverscanRequested;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800222
223 // Pool of queued input events.
224 private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
225 private QueuedInputEvent mQueuedInputEventPool;
226 private int mQueuedInputEventPoolSize;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800227
Michael Wrightc8a7e542013-03-20 17:58:33 -0700228 /* Input event queue.
Jeff Brownf9e989d2013-04-04 23:04:03 -0700229 * Pending input events are input events waiting to be delivered to the input stages
230 * and handled by the application.
Michael Wrightc8a7e542013-03-20 17:58:33 -0700231 */
232 QueuedInputEvent mPendingInputEventHead;
233 QueuedInputEvent mPendingInputEventTail;
Michael Wright95ae9422013-03-14 10:58:50 -0700234 int mPendingInputEventCount;
Jeff Brown96e942d2011-11-30 19:55:01 -0800235 boolean mProcessInputEventsScheduled;
Michael Wright9d744c72014-02-18 21:27:42 -0800236 boolean mUnbufferedInputDispatch;
Michael Wright95ae9422013-03-14 10:58:50 -0700237 String mPendingInputEventQueueLengthCounterName = "pq";
Jeff Brownf9e989d2013-04-04 23:04:03 -0700238
239 InputStage mFirstInputStage;
240 InputStage mFirstPostImeInputStage;
Michael Wright899d7052014-04-23 17:23:39 -0700241 InputStage mSyntheticInputStage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242
243 boolean mWindowAttributesChanged = false;
Romain Guyf21c9b02011-09-06 16:56:54 -0700244 int mWindowAttributesChangesFlag = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245
246 // These can be accessed by any thread, must be protected with a lock.
Mathias Agopian5583dc62009-07-09 16:28:11 -0700247 // Surface can never be reassigned or cleared (use Surface.clear()).
248 private final Surface mSurface = new Surface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249
250 boolean mAdded;
251 boolean mAddedTouchMode;
252
Craig Mautner48d0d182013-06-11 07:53:06 -0700253 final DisplayAdjustments mDisplayAdjustments;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 // These are accessed by multiple threads.
256 final Rect mWinFrame; // frame given by window manager.
257
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800258 final Rect mPendingOverscanInsets = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 final Rect mPendingVisibleInsets = new Rect();
Adrian Roosfa104232014-06-20 16:10:14 -0700260 final Rect mPendingStableInsets = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 final Rect mPendingContentInsets = new Rect();
262 final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
263 = new ViewTreeObserver.InternalInsetsInfo();
264
Adrian Roosfa104232014-06-20 16:10:14 -0700265 final Rect mDispatchContentInsets = new Rect();
266 final Rect mDispatchStableInsets = new Rect();
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700267
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700268 final Configuration mLastConfiguration = new Configuration();
269 final Configuration mPendingConfiguration = new Configuration();
Romain Guy59a12ca2011-06-09 17:48:21 -0700270
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800271 boolean mScrollMayChange;
272 int mSoftInputMode;
Svetoslav Ganov149567f2013-01-08 15:23:34 -0800273 WeakReference<View> mLastScrolledFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274 int mScrollY;
275 int mCurScrollY;
276 Scroller mScroller;
John Recke56e9df2014-02-21 15:45:10 -0800277 HardwareLayer mResizeBuffer;
278 long mResizeBufferStartTime;
279 int mResizeBufferDuration;
John Reckf9a901e2014-02-28 13:02:15 -0800280 // Used to block the creation of the ResizeBuffer due to invalidations in
281 // the previous DisplayList tree that must prevent re-execution.
282 // Currently this means a functor was detached.
283 boolean mBlockResizeBuffer;
John Recke56e9df2014-02-21 15:45:10 -0800284 static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
Chet Haasecca2c982011-05-20 14:34:18 -0700285 private ArrayList<LayoutTransition> mPendingTransitions;
Romain Guy8506ab42009-06-11 17:35:47 -0700286
Romain Guy8506ab42009-06-11 17:35:47 -0700287 final ViewConfiguration mViewConfiguration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288
Christopher Tatea53146c2010-09-07 11:57:52 -0700289 /* Drag/drop */
290 ClipDescription mDragDescription;
291 View mCurrentDragView;
Christopher Tate7fb8b562011-01-20 13:46:41 -0800292 volatile Object mLocalDragState;
Christopher Tatea53146c2010-09-07 11:57:52 -0700293 final PointF mDragPoint = new PointF();
Christopher Tate2c095f32010-10-04 14:13:40 -0700294 final PointF mLastTouchPoint = new PointF();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700295
296 private boolean mProfileRendering;
Romain Guyd0750312012-11-29 11:34:43 -0800297 private Choreographer.FrameCallback mRenderProfiler;
298 private boolean mRenderProfilingEnabled;
Christopher Tatea53146c2010-09-07 11:57:52 -0700299
Dan Morrille4d9a012013-03-28 18:10:43 -0700300 private boolean mMediaDisabled;
301
Chet Haase2f2022a2011-10-11 06:41:59 -0700302 // Variables to track frames per second, enabled via DEBUG_FPS flag
303 private long mFpsStartTime = -1;
304 private long mFpsPrevTime = -1;
305 private int mFpsNumFrames;
306
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307 /**
308 * see {@link #playSoundEffect(int)}
309 */
310 AudioManager mAudioManager;
311
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700312 final AccessibilityManager mAccessibilityManager;
313
Gilles Debunne5ac84422011-10-19 09:35:58 -0700314 AccessibilityInteractionController mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700315
316 AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager;
Chris Craikcce47eb2014-07-16 15:12:15 -0700317 HighContrastTextManager mHighContrastTextManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700318
Svetoslav Ganova0156172011-06-26 17:55:44 -0700319 SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700320
Svetoslav Ganov42138042012-03-20 11:51:39 -0700321 HashSet<View> mTempHashSet;
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800322
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700323 private final int mDensity;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700324 private final int mNoncompatDensity;
Adam Powellb08013c2010-09-16 16:28:11 -0700325
Chet Haase97140572012-09-13 14:56:47 -0700326 private boolean mInLayout = false;
327 ArrayList<View> mLayoutRequesters = new ArrayList<View>();
328 boolean mHandlingLayoutInLayoutRequest = false;
329
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700330 private int mViewLayoutDirectionInitial;
Chet Haase97140572012-09-13 14:56:47 -0700331
Craig Mautner8f303ad2013-06-14 11:32:22 -0700332 /** Set to true once doDie() has been called. */
333 private boolean mRemoved;
334
Michael Kolb22dfdcb2014-06-20 15:39:04 -0700335 private boolean mIsEmulator;
Filip Gruszczynskif14d9242014-08-25 17:05:11 -0700336 private boolean mIsCircularEmulator;
337 private final boolean mWindowIsRound;
Michael Kolb22dfdcb2014-06-20 15:39:04 -0700338
Jeff Brown21bc5c92011-02-28 18:27:14 -0800339 /**
340 * Consistency verifier for debugging purposes.
341 */
342 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
343 InputEventConsistencyVerifier.isInstrumentationEnabled() ?
344 new InputEventConsistencyVerifier(this, 0) : null;
345
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700346 static final class SystemUiVisibilityInfo {
347 int seq;
348 int globalVisibility;
349 int localValue;
350 int localChanges;
351 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700352
Jeff Brown98365d72012-08-19 20:30:52 -0700353 public ViewRootImpl(Context context, Display display) {
Jeff Brownf9e989d2013-04-04 23:04:03 -0700354 mContext = context;
355 mWindowSession = WindowManagerGlobal.getWindowSession();
Jeff Brown98365d72012-08-19 20:30:52 -0700356 mDisplay = display;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800357 mBasePackageName = context.getBasePackageName();
Jeff Brown98365d72012-08-19 20:30:52 -0700358
Craig Mautner48d0d182013-06-11 07:53:06 -0700359 mDisplayAdjustments = display.getDisplayAdjustments();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 mThread = Thread.currentThread();
362 mLocation = new WindowLeaked(null);
363 mLocation.fillInStackTrace();
364 mWidth = -1;
365 mHeight = -1;
366 mDirty = new Rect();
367 mTempRect = new Rect();
368 mVisRect = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 mWinFrame = new Rect();
Romain Guyfb8b7632010-08-23 21:05:08 -0700370 mWindow = new W(this);
Dianne Hackborn180c4842011-09-13 12:39:25 -0700371 mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372 mViewVisibility = View.GONE;
373 mTransparentRegion = new Region();
374 mPreviousTransparentRegion = new Region();
375 mFirst = true; // true for the first time the view is added
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 mAdded = false;
Chris Craikcce47eb2014-07-16 15:12:15 -0700377 mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700378 mAccessibilityManager = AccessibilityManager.getInstance(context);
379 mAccessibilityInteractionConnectionManager =
380 new AccessibilityInteractionConnectionManager();
Svetoslav Ganov00d0c142012-02-24 11:30:49 -0800381 mAccessibilityManager.addAccessibilityStateChangeListener(
382 mAccessibilityInteractionConnectionManager);
Chris Craikcce47eb2014-07-16 15:12:15 -0700383 mHighContrastTextManager = new HighContrastTextManager();
384 mAccessibilityManager.addHighTextContrastStateChangeListener(
385 mHighContrastTextManager);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 mViewConfiguration = ViewConfiguration.get(context);
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700387 mDensity = context.getResources().getDisplayMetrics().densityDpi;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700388 mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
Joe Onorato86f67862010-11-05 18:57:34 -0700389 mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
Jeff Brown96e942d2011-11-30 19:55:01 -0800390 mChoreographer = Choreographer.getInstance();
Jeff Brownd912e1f2014-04-11 18:46:22 -0700391 mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
Dianne Hackborna53de062012-05-08 18:53:51 -0700392 loadSystemProperties();
Filip Gruszczynskif14d9242014-08-25 17:05:11 -0700393 mWindowIsRound = context.getResources().getBoolean(
394 com.android.internal.R.bool.config_windowIsRound);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 }
396
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800397 public static void addFirstDrawHandler(Runnable callback) {
398 synchronized (sFirstDrawHandlers) {
399 if (!sFirstDrawComplete) {
400 sFirstDrawHandlers.add(callback);
401 }
402 }
403 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700404
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800405 public static void addConfigCallback(ComponentCallbacks callback) {
406 synchronized (sConfigCallbacks) {
407 sConfigCallbacks.add(callback);
408 }
409 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700410
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 // FIXME for perf testing only
412 private boolean mProfile = false;
413
414 /**
415 * Call this to profile the next traversal call.
416 * FIXME for perf testing only. Remove eventually
417 */
418 public void profile() {
419 mProfile = true;
420 }
421
422 /**
423 * Indicates whether we are in touch mode. Calling this method triggers an IPC
424 * call and should be avoided whenever possible.
425 *
426 * @return True, if the device is in touch mode, false otherwise.
427 *
428 * @hide
429 */
430 static boolean isInTouchMode() {
Jeff Brown98365d72012-08-19 20:30:52 -0700431 IWindowSession windowSession = WindowManagerGlobal.peekWindowSession();
432 if (windowSession != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 try {
Jeff Brown98365d72012-08-19 20:30:52 -0700434 return windowSession.getInTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 } catch (RemoteException e) {
436 }
437 }
438 return false;
439 }
440
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441 /**
442 * We have one child
443 */
Romain Guye4d01122010-06-16 18:44:05 -0700444 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800445 synchronized (this) {
446 if (mView == null) {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700447 mView = view;
Jeff Brownd912e1f2014-04-11 18:46:22 -0700448
449 mAttachInfo.mDisplayState = mDisplay.getState();
450 mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
451
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700452 mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
Joe Onorato86f67862010-11-05 18:57:34 -0700453 mFallbackEventHandler.setView(view);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700454 mWindowAttributes.copyFrom(attrs);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800455 if (mWindowAttributes.packageName == null) {
456 mWindowAttributes.packageName = mBasePackageName;
457 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700458 attrs = mWindowAttributes;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700459 // Keep track of the actual window flags supplied by the client.
460 mClientWindowLayoutFlags = attrs.flags;
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700461
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700462 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700463
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700464 if (view instanceof RootViewSurfaceTaker) {
465 mSurfaceHolderCallback =
466 ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
467 if (mSurfaceHolderCallback != null) {
468 mSurfaceHolder = new TakenSurfaceHolder();
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700469 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700470 }
471 }
Romain Guy1aec9a22011-01-05 09:37:12 -0800472
Alan Viverette49a22e82014-07-12 20:01:27 -0700473 // Compute surface insets required to draw at specified Z value.
474 // TODO: Use real shadow insets for a constant max Z.
Alan Viveretteac89416c2014-07-21 12:10:30 -0700475 final int surfaceInset = (int) Math.ceil(view.getZ() * 2);
476 attrs.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
Alan Viverette49a22e82014-07-12 20:01:27 -0700477
Craig Mautner48d0d182013-06-11 07:53:06 -0700478 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
Romain Guy856d4e12011-10-14 15:47:55 -0700479 mTranslator = compatibilityInfo.getTranslator();
Craig Mautner48d0d182013-06-11 07:53:06 -0700480 mDisplayAdjustments.setActivityToken(attrs.token);
Romain Guy856d4e12011-10-14 15:47:55 -0700481
Romain Guy1aec9a22011-01-05 09:37:12 -0800482 // If the application owns the surface, don't enable hardware acceleration
483 if (mSurfaceHolder == null) {
Romain Guy3b748a42013-04-17 18:54:38 -0700484 enableHardwareAcceleration(attrs);
Romain Guy1aec9a22011-01-05 09:37:12 -0800485 }
486
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700487 boolean restore = false;
Romain Guy35b38ce2009-10-07 13:38:55 -0700488 if (mTranslator != null) {
Romain Guy856d4e12011-10-14 15:47:55 -0700489 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700490 restore = true;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700491 attrs.backup();
492 mTranslator.translateWindowLayout(attrs);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700493 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700494 if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
495
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700496 if (!compatibilityInfo.supportsScreen()) {
Adam Lesinski95c42972013-10-02 10:13:27 -0700497 attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700498 mLastInCompatMode = true;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700499 }
500
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 mSoftInputMode = attrs.softInputMode;
502 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -0700503 mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 mAttachInfo.mRootView = view;
Romain Guy35b38ce2009-10-07 13:38:55 -0700505 mAttachInfo.mScalingRequired = mTranslator != null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700506 mAttachInfo.mApplicationScale =
507 mTranslator == null ? 1.0f : mTranslator.applicationScale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 if (panelParentView != null) {
509 mAttachInfo.mPanelParentWindowToken
510 = panelParentView.getApplicationWindowToken();
511 }
512 mAdded = true;
513 int res; /* = WindowManagerImpl.ADD_OKAY; */
Romain Guy8506ab42009-06-11 17:35:47 -0700514
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515 // Schedule the first layout -before- adding to the window
516 // manager, to make sure we do the relayout before receiving
517 // any other events from the system.
518 requestLayout();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700519 if ((mWindowAttributes.inputFeatures
520 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
521 mInputChannel = new InputChannel();
522 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 try {
Dianne Hackborn180c4842011-09-13 12:39:25 -0700524 mOrigWindowType = mWindowAttributes.type;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700525 mAttachInfo.mRecomputeGlobalAttributes = true;
526 collectViewAttributes();
Jeff Brown98365d72012-08-19 20:30:52 -0700527 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
528 getHostVisibility(), mDisplay.getDisplayId(),
Craig Mautner6881a102012-07-27 13:04:51 -0700529 mAttachInfo.mContentInsets, mInputChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530 } catch (RemoteException e) {
531 mAdded = false;
532 mView = null;
533 mAttachInfo.mRootView = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700534 mInputChannel = null;
Joe Onorato86f67862010-11-05 18:57:34 -0700535 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700537 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800538 throw new RuntimeException("Adding window failed", e);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700539 } finally {
540 if (restore) {
541 attrs.restore();
542 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700544
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700545 if (mTranslator != null) {
546 mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700547 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800548 mPendingOverscanInsets.set(0, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 mPendingContentInsets.set(mAttachInfo.mContentInsets);
Adrian Roosfa104232014-06-20 16:10:14 -0700550 mPendingStableInsets.set(mAttachInfo.mStableInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 mPendingVisibleInsets.set(0, 0, 0, 0);
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800552 if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
Jeff Brown98365d72012-08-19 20:30:52 -0700553 if (res < WindowManagerGlobal.ADD_OKAY) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800554 mAttachInfo.mRootView = null;
555 mAdded = false;
Joe Onorato86f67862010-11-05 18:57:34 -0700556 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700558 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559 switch (res) {
Jeff Brown98365d72012-08-19 20:30:52 -0700560 case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
561 case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
562 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 "Unable to add window -- token " + attrs.token
564 + " is not valid; is your activity running?");
Jeff Brown98365d72012-08-19 20:30:52 -0700565 case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
566 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 "Unable to add window -- token " + attrs.token
568 + " is not for an application");
Jeff Brown98365d72012-08-19 20:30:52 -0700569 case WindowManagerGlobal.ADD_APP_EXITING:
570 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571 "Unable to add window -- app for token " + attrs.token
572 + " is exiting");
Jeff Brown98365d72012-08-19 20:30:52 -0700573 case WindowManagerGlobal.ADD_DUPLICATE_ADD:
574 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575 "Unable to add window -- window " + mWindow
576 + " has already been added");
Jeff Brown98365d72012-08-19 20:30:52 -0700577 case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 // Silently ignore -- we would have just removed it
579 // right away, anyway.
580 return;
Jeff Brown98365d72012-08-19 20:30:52 -0700581 case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
582 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 "Unable to add window " + mWindow +
584 " -- another window of this type already exists");
Jeff Brown98365d72012-08-19 20:30:52 -0700585 case WindowManagerGlobal.ADD_PERMISSION_DENIED:
586 throw new WindowManager.BadTokenException(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587 "Unable to add window " + mWindow +
588 " -- permission denied for this window type");
Craig Mautner6018aee2012-10-23 14:27:49 -0700589 case WindowManagerGlobal.ADD_INVALID_DISPLAY:
590 throw new WindowManager.InvalidDisplayException(
591 "Unable to add window " + mWindow +
592 " -- the specified display can not be found");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 }
594 throw new RuntimeException(
595 "Unable to add window -- unknown error code " + res);
596 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700597
Jeff Brown00fa7bd2010-07-02 15:37:36 -0700598 if (view instanceof RootViewSurfaceTaker) {
599 mInputQueueCallback =
600 ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
601 }
Jeff Browncc4f7db2011-08-30 20:34:48 -0700602 if (mInputChannel != null) {
603 if (mInputQueueCallback != null) {
Michael Wrighta44dd262013-04-10 21:12:00 -0700604 mInputQueue = new InputQueue();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700605 mInputQueueCallback.onInputQueueCreated(mInputQueue);
Jeff Browncc4f7db2011-08-30 20:34:48 -0700606 }
Michael Wrighta44dd262013-04-10 21:12:00 -0700607 mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
608 Looper.myLooper());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700609 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700610
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 view.assignParent(this);
Jeff Brown98365d72012-08-19 20:30:52 -0700612 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
613 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700614
615 if (mAccessibilityManager.isEnabled()) {
616 mAccessibilityInteractionConnectionManager.ensureConnection();
617 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700618
619 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
620 view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
621 }
Michael Wright95ae9422013-03-14 10:58:50 -0700622
Jeff Brownf9e989d2013-04-04 23:04:03 -0700623 // Set up the input pipeline.
624 CharSequence counterSuffix = attrs.getTitle();
Michael Wright899d7052014-04-23 17:23:39 -0700625 mSyntheticInputStage = new SyntheticInputStage();
626 InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
Jeff Brownf9e989d2013-04-04 23:04:03 -0700627 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
628 "aq:native-post-ime:" + counterSuffix);
629 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
630 InputStage imeStage = new ImeInputStage(earlyPostImeStage,
631 "aq:ime:" + counterSuffix);
632 InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
633 InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
634 "aq:native-pre-ime:" + counterSuffix);
635
636 mFirstInputStage = nativePreImeStage;
637 mFirstPostImeInputStage = earlyPostImeStage;
638 mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 }
640 }
641 }
642
keunyoung30f420f2013-08-02 14:23:10 -0700643 /** Whether the window is in local focus mode or not */
644 private boolean isInLocalFocusMode() {
645 return (mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0;
646 }
647
Romain Guy8ff6b9e2011-11-09 20:10:18 -0800648 void destroyHardwareResources() {
Romain Guy31f2c2e2011-11-21 10:55:41 -0800649 if (mAttachInfo.mHardwareRenderer != null) {
650 mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
John Reckf47a5942014-06-30 16:20:04 -0700651 mAttachInfo.mHardwareRenderer.destroy();
Romain Guy31f2c2e2011-11-21 10:55:41 -0800652 }
653 }
654
Bo Liu845535a2014-03-21 12:06:23 -0700655 public void detachFunctor(long functor) {
John Reck832b15142014-05-07 14:39:44 -0700656 // TODO: Make the resize buffer some other way to not need this block
John Reckf9a901e2014-02-28 13:02:15 -0800657 mBlockResizeBuffer = true;
John Reck44ac42a2014-05-16 14:46:07 -0700658 if (mAttachInfo.mHardwareRenderer != null) {
659 // Fence so that any pending invokeFunctor() messages will be processed
660 // before we return from detachFunctor.
John Reckf47a5942014-06-30 16:20:04 -0700661 mAttachInfo.mHardwareRenderer.stopDrawing();
John Reck44ac42a2014-05-16 14:46:07 -0700662 }
Romain Guyba6be8a2012-04-23 18:22:09 -0700663 }
664
John Reck3b202512014-06-23 13:13:08 -0700665 /**
666 * Schedules the functor for execution in either kModeProcess or
667 * kModeProcessNoContext, depending on whether or not there is an EGLContext.
668 *
669 * @param functor The native functor to invoke
670 * @param waitForCompletion If true, this will not return until the functor
671 * has invoked. If false, the functor may be invoked
672 * asynchronously.
673 */
Hui Shu9970aee2014-06-23 17:10:30 -0700674 public void invokeFunctor(long functor, boolean waitForCompletion) {
John Reck3b202512014-06-23 13:13:08 -0700675 ThreadedRenderer.invokeFunctor(functor, waitForCompletion);
Bo Liuae738a72014-04-27 16:22:04 -0700676 }
677
John Reck119907c2014-08-14 09:02:01 -0700678 public void registerAnimatingRenderNode(RenderNode animator) {
679 if (mAttachInfo.mHardwareRenderer != null) {
680 mAttachInfo.mHardwareRenderer.registerAnimatingRenderNode(animator);
681 } else {
682 if (mAttachInfo.mPendingAnimatingRenderNodes == null) {
683 mAttachInfo.mPendingAnimatingRenderNodes = new ArrayList<RenderNode>();
684 }
685 mAttachInfo.mPendingAnimatingRenderNodes.add(animator);
686 }
687 }
688
Romain Guy3b748a42013-04-17 18:54:38 -0700689 private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800690 mAttachInfo.mHardwareAccelerated = false;
691 mAttachInfo.mHardwareAccelerationRequested = false;
Romain Guy4f6aff32011-01-12 16:21:41 -0800692
Romain Guy856d4e12011-10-14 15:47:55 -0700693 // Don't enable hardware acceleration when the application is in compatibility mode
John Reckdd58e792014-04-02 16:54:28 +0000694 if (mTranslator != null) return;
Romain Guy856d4e12011-10-14 15:47:55 -0700695
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800696 // Try to enable hardware acceleration if requested
Igor Murashkina86ab6402013-08-30 12:58:36 -0700697 final boolean hardwareAccelerated =
Jim Miller1b365922011-03-09 19:38:07 -0800698 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
699
John Reckdd58e792014-04-02 16:54:28 +0000700 if (hardwareAccelerated) {
Romain Guy1af23a32011-03-24 16:03:55 -0700701 if (!HardwareRenderer.isAvailable()) {
Romain Guy1af23a32011-03-24 16:03:55 -0700702 return;
703 }
704
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700705 // Persistent processes (including the system) should not do
706 // accelerated rendering on low-end devices. In that case,
707 // sRendererDisabled will be set. In addition, the system process
708 // itself should never do accelerated rendering. In that case, both
709 // sRendererDisabled and sSystemRendererDisabled are set. When
710 // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
711 // can be used by code on the system process to escape that and enable
712 // HW accelerated drawing. (This is basically for the lock screen.)
Jim Miller1b365922011-03-09 19:38:07 -0800713
John Reck61375a82014-09-18 19:27:48 +0000714 final boolean fakeHwAccelerated = (attrs.privateFlags &
715 WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700716 final boolean forceHwAccelerated = (attrs.privateFlags &
717 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
Jim Miller1b365922011-03-09 19:38:07 -0800718
John Reck61375a82014-09-18 19:27:48 +0000719 if (fakeHwAccelerated) {
720 // This is exclusively for the preview windows the window manager
721 // shows for launching applications, so they will look more like
722 // the app being launched.
723 mAttachInfo.mHardwareAccelerationRequested = true;
724 } else if (!HardwareRenderer.sRendererDisabled
John Reck1dd0e0f2014-08-12 09:27:33 -0700725 || (HardwareRenderer.sSystemRendererDisabled && forceHwAccelerated)) {
Romain Guyb051e892010-09-28 19:09:36 -0700726 if (mAttachInfo.mHardwareRenderer != null) {
John Reckf47a5942014-06-30 16:20:04 -0700727 mAttachInfo.mHardwareRenderer.destroy();
Romain Guy211370f2012-02-01 16:10:55 -0800728 }
729
730 final boolean translucent = attrs.format != PixelFormat.OPAQUE;
John Reckb8802b12014-06-16 15:28:50 -0700731 mAttachInfo.mHardwareRenderer = HardwareRenderer.create(mContext, translucent);
Romain Guye55945e2013-04-04 15:26:04 -0700732 if (mAttachInfo.mHardwareRenderer != null) {
733 mAttachInfo.mHardwareRenderer.setName(attrs.getTitle().toString());
734 mAttachInfo.mHardwareAccelerated =
735 mAttachInfo.mHardwareAccelerationRequested = true;
736 }
Romain Guye4d01122010-06-16 18:44:05 -0700737 }
738 }
739 }
740
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 public View getView() {
742 return mView;
743 }
744
745 final WindowLeaked getLocation() {
746 return mLocation;
747 }
748
749 void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
750 synchronized (this) {
Alan Viverettedbed8932014-08-06 17:54:52 -0700751 final int oldInsetLeft = mWindowAttributes.surfaceInsets.left;
752 final int oldInsetTop = mWindowAttributes.surfaceInsets.top;
753 final int oldInsetRight = mWindowAttributes.surfaceInsets.right;
754 final int oldInsetBottom = mWindowAttributes.surfaceInsets.bottom;
755 final int oldSoftInputMode = mWindowAttributes.softInputMode;
756
Dianne Hackborn9d090892012-06-11 18:35:41 -0700757 // Keep track of the actual window flags supplied by the client.
758 mClientWindowLayoutFlags = attrs.flags;
Alan Viverettedbed8932014-08-06 17:54:52 -0700759
760 // Preserve compatible window flag if exists.
761 final int compatibleWindowFlag = mWindowAttributes.privateFlags
Adam Lesinski95c42972013-10-02 10:13:27 -0700762 & WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Alan Viverettedbed8932014-08-06 17:54:52 -0700763
764 // Transfer over system UI visibility values as they carry current state.
Craig Mautner3fe38c02012-05-03 17:28:09 -0700765 attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
766 attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
Alan Viverettedbed8932014-08-06 17:54:52 -0700767
Romain Guyf21c9b02011-09-06 16:56:54 -0700768 mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
John Spurlockbd957402013-10-03 11:38:39 -0400769 if ((mWindowAttributesChangesFlag
770 & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) {
771 // Recompute system ui visibility.
772 mAttachInfo.mRecomputeGlobalAttributes = true;
773 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800774 if (mWindowAttributes.packageName == null) {
775 mWindowAttributes.packageName = mBasePackageName;
776 }
Adam Lesinski95c42972013-10-02 10:13:27 -0700777 mWindowAttributes.privateFlags |= compatibleWindowFlag;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700778
Alan Viverettedbed8932014-08-06 17:54:52 -0700779 // Restore old surface insets.
780 mWindowAttributes.surfaceInsets.set(
781 oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
782
Dianne Hackborn9d090892012-06-11 18:35:41 -0700783 applyKeepScreenOnFlag(mWindowAttributes);
784
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 if (newView) {
786 mSoftInputMode = attrs.softInputMode;
787 requestLayout();
788 }
Alan Viverettedbed8932014-08-06 17:54:52 -0700789
The Android Open Source Project10592532009-03-18 17:39:46 -0700790 // Don't lose the mode we last auto-computed.
Alan Viverettedbed8932014-08-06 17:54:52 -0700791 if ((attrs.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
The Android Open Source Project10592532009-03-18 17:39:46 -0700792 == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
793 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
794 & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
Alan Viverettedbed8932014-08-06 17:54:52 -0700795 | (oldSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
The Android Open Source Project10592532009-03-18 17:39:46 -0700796 }
Alan Viverettedbed8932014-08-06 17:54:52 -0700797
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798 mWindowAttributesChanged = true;
799 scheduleTraversals();
800 }
801 }
802
803 void handleAppVisibility(boolean visible) {
804 if (mAppVisible != visible) {
805 mAppVisible = visible;
806 scheduleTraversals();
John Reck73840ea2014-09-22 07:39:18 -0700807 if (!mAppVisible) {
808 WindowManagerGlobal.trimForeground();
809 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 }
811 }
812
813 void handleGetNewSurface() {
814 mNewSurfaceNeeded = true;
815 mFullRedrawNeeded = true;
816 scheduleTraversals();
817 }
818
Jeff Brownd912e1f2014-04-11 18:46:22 -0700819 private final DisplayListener mDisplayListener = new DisplayListener() {
820 @Override
821 public void onDisplayChanged(int displayId) {
822 if (mView != null && mDisplay.getDisplayId() == displayId) {
823 final int oldDisplayState = mAttachInfo.mDisplayState;
824 final int newDisplayState = mDisplay.getState();
825 if (oldDisplayState != newDisplayState) {
826 mAttachInfo.mDisplayState = newDisplayState;
827 if (oldDisplayState != Display.STATE_UNKNOWN) {
828 final int oldScreenState = toViewScreenState(oldDisplayState);
829 final int newScreenState = toViewScreenState(newDisplayState);
830 if (oldScreenState != newScreenState) {
831 mView.dispatchScreenStateChanged(newScreenState);
832 }
833 if (oldDisplayState == Display.STATE_OFF) {
834 // Draw was suppressed so we need to for it to happen here.
835 mFullRedrawNeeded = true;
836 scheduleTraversals();
837 }
838 }
839 }
Romain Guy7e4e5612012-03-05 14:37:29 -0800840 }
841 }
Jeff Brownd912e1f2014-04-11 18:46:22 -0700842
843 @Override
844 public void onDisplayRemoved(int displayId) {
845 }
846
847 @Override
848 public void onDisplayAdded(int displayId) {
849 }
850
851 private int toViewScreenState(int displayState) {
852 return displayState == Display.STATE_OFF ?
853 View.SCREEN_STATE_OFF : View.SCREEN_STATE_ON;
854 }
855 };
Romain Guy7e4e5612012-03-05 14:37:29 -0800856
Craig Mautner6018aee2012-10-23 14:27:49 -0700857 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700858 public void requestFitSystemWindows() {
859 checkThread();
Adrian Roosfa104232014-06-20 16:10:14 -0700860 mApplyInsetsRequested = true;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700861 scheduleTraversals();
862 }
863
Craig Mautner6018aee2012-10-23 14:27:49 -0700864 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800865 public void requestLayout() {
Chet Haase3efa7b52012-12-03 08:33:17 -0800866 if (!mHandlingLayoutInLayoutRequest) {
867 checkThread();
868 mLayoutRequested = true;
869 scheduleTraversals();
870 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871 }
872
Craig Mautner6018aee2012-10-23 14:27:49 -0700873 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800874 public boolean isLayoutRequested() {
875 return mLayoutRequested;
876 }
877
Romain Guycfef1232012-02-23 13:50:37 -0800878 void invalidate() {
879 mDirty.set(0, 0, mWidth, mHeight);
John Recke4267ea2014-06-03 15:53:15 -0700880 if (!mWillDrawSoon) {
881 scheduleTraversals();
882 }
Romain Guycfef1232012-02-23 13:50:37 -0800883 }
884
Dianne Hackborna53de062012-05-08 18:53:51 -0700885 void invalidateWorld(View view) {
886 view.invalidate();
887 if (view instanceof ViewGroup) {
Romain Guyf84208f2012-09-13 22:50:18 -0700888 ViewGroup parent = (ViewGroup) view;
889 for (int i = 0; i < parent.getChildCount(); i++) {
Dianne Hackborna53de062012-05-08 18:53:51 -0700890 invalidateWorld(parent.getChildAt(i));
891 }
892 }
893 }
894
Craig Mautner6018aee2012-10-23 14:27:49 -0700895 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800896 public void invalidateChild(View child, Rect dirty) {
Romain Guycfef1232012-02-23 13:50:37 -0800897 invalidateChildInParent(null, dirty);
898 }
899
Craig Mautner8f303ad2013-06-14 11:32:22 -0700900 @Override
Romain Guycfef1232012-02-23 13:50:37 -0800901 public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902 checkThread();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700903 if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
Romain Guycfef1232012-02-23 13:50:37 -0800904
Chet Haase70d4ba12010-10-06 09:46:45 -0700905 if (dirty == null) {
Chet Haase70d4ba12010-10-06 09:46:45 -0700906 invalidate();
Romain Guycfef1232012-02-23 13:50:37 -0800907 return null;
Chet Haase3561d062012-10-23 12:54:51 -0700908 } else if (dirty.isEmpty() && !mIsAnimating) {
Chet Haase05e91ed2012-07-03 14:17:57 -0700909 return null;
Chet Haase70d4ba12010-10-06 09:46:45 -0700910 }
Romain Guycfef1232012-02-23 13:50:37 -0800911
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700912 if (mCurScrollY != 0 || mTranslator != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800913 mTempRect.set(dirty);
Romain Guy1e095972009-07-07 11:22:45 -0700914 dirty = mTempRect;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700915 if (mCurScrollY != 0) {
Romain Guycfef1232012-02-23 13:50:37 -0800916 dirty.offset(0, -mCurScrollY);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700917 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700918 if (mTranslator != null) {
Romain Guy1e095972009-07-07 11:22:45 -0700919 mTranslator.translateRectInAppWindowToScreen(dirty);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700920 }
Romain Guy1e095972009-07-07 11:22:45 -0700921 if (mAttachInfo.mScalingRequired) {
922 dirty.inset(-1, -1);
923 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924 }
Romain Guycfef1232012-02-23 13:50:37 -0800925
926 final Rect localDirty = mDirty;
927 if (!localDirty.isEmpty() && !localDirty.contains(dirty)) {
Romain Guy02ccac62011-06-24 13:20:23 -0700928 mAttachInfo.mSetIgnoreDirtyState = true;
Romain Guy7d695942010-12-01 17:22:29 -0800929 mAttachInfo.mIgnoreDirtyState = true;
930 }
Romain Guycfef1232012-02-23 13:50:37 -0800931
932 // Add the new dirty rect to the current one
933 localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
934 // Intersect with the bounds of the window to skip
935 // updates that lie outside of the visible region
Romain Guy7b2f8b82012-03-19 17:18:54 -0700936 final float appScale = mAttachInfo.mApplicationScale;
Chet Haase3561d062012-10-23 12:54:51 -0700937 final boolean intersected = localDirty.intersect(0, 0,
938 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
939 if (!intersected) {
Chet Haaseb78ee0e2012-10-17 11:32:01 -0700940 localDirty.setEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 }
Chet Haase3561d062012-10-23 12:54:51 -0700942 if (!mWillDrawSoon && (intersected || mIsAnimating)) {
943 scheduleTraversals();
944 }
Romain Guycfef1232012-02-23 13:50:37 -0800945
946 return null;
Romain Guy0d9275e2010-10-26 14:22:30 -0700947 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800948
Dianne Hackbornce418e62011-03-01 14:31:38 -0800949 void setStopped(boolean stopped) {
950 if (mStopped != stopped) {
951 mStopped = stopped;
952 if (!stopped) {
953 scheduleTraversals();
954 }
955 }
956 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957
Craig Mautner8f303ad2013-06-14 11:32:22 -0700958 @Override
Romain Guycfef1232012-02-23 13:50:37 -0800959 public ViewParent getParent() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800960 return null;
961 }
962
Craig Mautner8f303ad2013-06-14 11:32:22 -0700963 @Override
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700964 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 if (child != mView) {
966 throw new RuntimeException("child is not mine, honest!");
967 }
968 // Note: don't apply scroll offset, because we want to know its
969 // visibility in the virtual canvas being given to the view hierarchy.
970 return r.intersect(0, 0, mWidth, mHeight);
971 }
972
Igor Murashkina86ab6402013-08-30 12:58:36 -0700973 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974 public void bringChildToFront(View child) {
975 }
976
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800977 int getHostVisibility() {
978 return mAppVisible ? mView.getVisibility() : View.GONE;
979 }
Romain Guy8506ab42009-06-11 17:35:47 -0700980
John Recke56e9df2014-02-21 15:45:10 -0800981 void disposeResizeBuffer() {
982 if (mResizeBuffer != null) {
983 mResizeBuffer.destroy();
984 mResizeBuffer = null;
985 }
986 }
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800987
Chet Haasecca2c982011-05-20 14:34:18 -0700988 /**
989 * Add LayoutTransition to the list of transitions to be started in the next traversal.
990 * This list will be cleared after the transitions on the list are start()'ed. These
991 * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
992 * happens during the layout phase of traversal, which we want to complete before any of the
993 * animations are started (because those animations may side-effect properties that layout
994 * depends upon, like the bounding rectangles of the affected views). So we add the transition
995 * to the list and it is started just prior to starting the drawing phase of traversal.
996 *
997 * @param transition The LayoutTransition to be started on the next traversal.
998 *
999 * @hide
1000 */
1001 public void requestTransitionStart(LayoutTransition transition) {
1002 if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
1003 if (mPendingTransitions == null) {
1004 mPendingTransitions = new ArrayList<LayoutTransition>();
1005 }
1006 mPendingTransitions.add(transition);
1007 }
1008 }
1009
John Recka5dda642014-05-22 15:43:54 -07001010 /**
1011 * Notifies the HardwareRenderer that a new frame will be coming soon.
1012 * Currently only {@link ThreadedRenderer} cares about this, and uses
1013 * this knowledge to adjust the scheduling of off-thread animations
1014 */
1015 void notifyRendererOfFramePending() {
1016 if (mAttachInfo.mHardwareRenderer != null) {
1017 mAttachInfo.mHardwareRenderer.notifyFramePending();
1018 }
1019 }
1020
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001021 void scheduleTraversals() {
1022 if (!mTraversalScheduled) {
1023 mTraversalScheduled = true;
1024 mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
1025 mChoreographer.postCallback(
1026 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
Michael Wright9d744c72014-02-18 21:27:42 -08001027 if (!mUnbufferedInputDispatch) {
1028 scheduleConsumeBatchedInput();
1029 }
John Recka5dda642014-05-22 15:43:54 -07001030 notifyRendererOfFramePending();
Jeff Brown96e942d2011-11-30 19:55:01 -08001031 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001032 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001033
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001034 void unscheduleTraversals() {
1035 if (mTraversalScheduled) {
1036 mTraversalScheduled = false;
1037 mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
1038 mChoreographer.removeCallbacks(
1039 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
1040 }
1041 }
1042
1043 void doTraversal() {
1044 if (mTraversalScheduled) {
1045 mTraversalScheduled = false;
1046 mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
1047
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001048 if (mProfile) {
1049 Debug.startMethodTracing("ViewAncestor");
Jeff Brown96e942d2011-11-30 19:55:01 -08001050 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001051
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001052 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
1053 try {
1054 performTraversals();
1055 } finally {
1056 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
1057 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001058
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001059 if (mProfile) {
1060 Debug.stopMethodTracing();
1061 mProfile = false;
1062 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001063 }
1064 }
1065
Dianne Hackborn9d090892012-06-11 18:35:41 -07001066 private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) {
1067 // Update window's global keep screen on flag: if a view has requested
1068 // that the screen be kept on, then it is always set; otherwise, it is
1069 // set to whatever the client last requested for the global state.
1070 if (mAttachInfo.mKeepScreenOn) {
1071 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
1072 } else {
1073 params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
1074 | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1075 }
1076 }
1077
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001078 private boolean collectViewAttributes() {
Chris Craikd36a81f2014-07-17 10:16:51 -07001079 if (mAttachInfo.mRecomputeGlobalAttributes) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001080 //Log.i(TAG, "Computing view hierarchy attributes!");
Chris Craikd36a81f2014-07-17 10:16:51 -07001081 mAttachInfo.mRecomputeGlobalAttributes = false;
1082 boolean oldScreenOn = mAttachInfo.mKeepScreenOn;
1083 mAttachInfo.mKeepScreenOn = false;
1084 mAttachInfo.mSystemUiVisibility = 0;
1085 mAttachInfo.mHasSystemUiListeners = false;
1086 mView.dispatchCollectViewAttributes(mAttachInfo, 0);
1087 mAttachInfo.mSystemUiVisibility &= ~mAttachInfo.mDisabledSystemUiVisibility;
Craig Mautner7eac0f52012-09-13 13:14:14 -07001088 WindowManager.LayoutParams params = mWindowAttributes;
Chris Craikd36a81f2014-07-17 10:16:51 -07001089 mAttachInfo.mSystemUiVisibility |= getImpliedSystemUiVisibility(params);
1090 if (mAttachInfo.mKeepScreenOn != oldScreenOn
1091 || mAttachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
1092 || mAttachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
Dianne Hackborn9d090892012-06-11 18:35:41 -07001093 applyKeepScreenOnFlag(params);
Chris Craikd36a81f2014-07-17 10:16:51 -07001094 params.subtreeSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
1095 params.hasSystemUiListeners = mAttachInfo.mHasSystemUiListeners;
1096 mView.dispatchWindowSystemUiVisiblityChanged(mAttachInfo.mSystemUiVisibility);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001097 return true;
1098 }
1099 }
1100 return false;
1101 }
1102
John Spurlockbd957402013-10-03 11:38:39 -04001103 private int getImpliedSystemUiVisibility(WindowManager.LayoutParams params) {
1104 int vis = 0;
1105 // Translucent decor window flags imply stable system ui visibility.
1106 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) != 0) {
1107 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
1108 }
1109 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) != 0) {
1110 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
1111 }
1112 return vis;
1113 }
1114
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001115 private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
1116 final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
1117 int childWidthMeasureSpec;
1118 int childHeightMeasureSpec;
1119 boolean windowSizeMayChange = false;
1120
1121 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
1122 "Measuring " + host + " in display " + desiredWindowWidth
1123 + "x" + desiredWindowHeight + "...");
1124
1125 boolean goodMeasure = false;
1126 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
1127 // On large screens, we don't want to allow dialogs to just
1128 // stretch to fill the entire width of the screen to display
1129 // one line of text. First try doing the layout at a smaller
1130 // size to see if it will fit.
1131 final DisplayMetrics packageMetrics = res.getDisplayMetrics();
1132 res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
1133 int baseSize = 0;
1134 if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
1135 baseSize = (int)mTmpValue.getDimension(packageMetrics);
1136 }
1137 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize);
1138 if (baseSize != 0 && desiredWindowWidth > baseSize) {
1139 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
1140 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001141 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001142 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
1143 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1144 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1145 goodMeasure = true;
1146 } else {
1147 // Didn't fit in that size... try expanding a bit.
1148 baseSize = (baseSize+desiredWindowWidth)/2;
1149 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
1150 + baseSize);
1151 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001152 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001153 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
1154 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1155 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1156 if (DEBUG_DIALOG) Log.v(TAG, "Good!");
1157 goodMeasure = true;
1158 }
1159 }
1160 }
1161 }
1162
1163 if (!goodMeasure) {
1164 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
1165 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001166 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001167 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
1168 windowSizeMayChange = true;
1169 }
1170 }
1171
1172 if (DBG) {
1173 System.out.println("======================================");
1174 System.out.println("performTraversals -- after measure");
1175 host.debug();
1176 }
1177
1178 return windowSizeMayChange;
1179 }
1180
Alan Viverettefed3f722013-11-14 14:48:20 -08001181 /**
1182 * Modifies the input matrix such that it maps view-local coordinates to
1183 * on-screen coordinates.
1184 *
1185 * @param m input matrix to modify
1186 */
1187 void transformMatrixToGlobal(Matrix m) {
Dake Gu7bf379c2014-07-15 16:29:38 -07001188 m.preTranslate(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
Alan Viverettefed3f722013-11-14 14:48:20 -08001189 }
1190
1191 /**
1192 * Modifies the input matrix such that it maps on-screen coordinates to
1193 * view-local coordinates.
1194 *
1195 * @param m input matrix to modify
1196 */
1197 void transformMatrixToLocal(Matrix m) {
Dake Gu7bf379c2014-07-15 16:29:38 -07001198 m.postTranslate(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
Alan Viverettefed3f722013-11-14 14:48:20 -08001199 }
1200
Adam Powell2accbf92014-04-16 23:14:57 +00001201 void dispatchApplyInsets(View host) {
Adrian Roosfa104232014-06-20 16:10:14 -07001202 mDispatchContentInsets.set(mAttachInfo.mContentInsets);
1203 mDispatchStableInsets.set(mAttachInfo.mStableInsets);
Filip Gruszczynskif14d9242014-08-25 17:05:11 -07001204 final boolean isRound = (mIsEmulator && mIsCircularEmulator) || mWindowIsRound;
Michael Kolb6642e51a2014-04-17 14:45:29 -07001205 host.dispatchApplyWindowInsets(new WindowInsets(
Adrian Roosfa104232014-06-20 16:10:14 -07001206 mDispatchContentInsets, null /* windowDecorInsets */,
1207 mDispatchStableInsets, isRound));
Adam Powell2accbf92014-04-16 23:14:57 +00001208 }
1209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210 private void performTraversals() {
1211 // cache mView since it is used so much below...
1212 final View host = mView;
1213
1214 if (DBG) {
1215 System.out.println("======================================");
1216 System.out.println("performTraversals");
1217 host.debug();
1218 }
1219
1220 if (host == null || !mAdded)
1221 return;
1222
Craig Mautnerdf2390a2012-08-29 20:59:22 -07001223 mIsInTraversal = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001224 mWillDrawSoon = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001225 boolean windowSizeMayChange = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 boolean newSurface = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001227 boolean surfaceChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001228 WindowManager.LayoutParams lp = mWindowAttributes;
1229
1230 int desiredWindowWidth;
1231 int desiredWindowHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001232
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001233 final int viewVisibility = getHostVisibility();
1234 boolean viewVisibilityChanged = mViewVisibility != viewVisibility
1235 || mNewSurfaceNeeded;
1236
1237 WindowManager.LayoutParams params = null;
1238 if (mWindowAttributesChanged) {
1239 mWindowAttributesChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001240 surfaceChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001241 params = lp;
1242 }
Craig Mautner48d0d182013-06-11 07:53:06 -07001243 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001244 if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
1245 params = lp;
Jeff Brown96e942d2011-11-30 19:55:01 -08001246 mFullRedrawNeeded = true;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001247 mLayoutRequested = true;
1248 if (mLastInCompatMode) {
Adam Lesinski95c42972013-10-02 10:13:27 -07001249 params.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001250 mLastInCompatMode = false;
1251 } else {
Adam Lesinski95c42972013-10-02 10:13:27 -07001252 params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001253 mLastInCompatMode = true;
1254 }
1255 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001256
Romain Guyf21c9b02011-09-06 16:56:54 -07001257 mWindowAttributesChangesFlag = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -07001258
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001259 Rect frame = mWinFrame;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001260 if (mFirst) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001261 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001262 mLayoutRequested = true;
1263
John Spurlockf8508272013-10-14 21:06:52 -04001264 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL
1265 || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
Dianne Hackborna239c842011-06-01 12:28:20 -07001266 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001267 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001268 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001269 desiredWindowWidth = size.x;
1270 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001271 } else {
1272 DisplayMetrics packageMetrics =
1273 mView.getContext().getResources().getDisplayMetrics();
1274 desiredWindowWidth = packageMetrics.widthPixels;
1275 desiredWindowHeight = packageMetrics.heightPixels;
1276 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001277
Romain Guyc5d55862011-01-21 19:01:46 -08001278 // We used to use the following condition to choose 32 bits drawing caches:
1279 // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
1280 // However, windows are now always 32 bits by default, so choose 32 bits
Chris Craikd36a81f2014-07-17 10:16:51 -07001281 mAttachInfo.mUse32BitDrawingCache = true;
1282 mAttachInfo.mHasWindowFocus = false;
1283 mAttachInfo.mWindowVisibility = viewVisibility;
1284 mAttachInfo.mRecomputeGlobalAttributes = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 viewVisibilityChanged = false;
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001286 mLastConfiguration.setTo(host.getResources().getConfiguration());
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001287 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Fabrice Di Megliob003e282012-10-17 17:20:19 -07001288 // Set the layout direction if it has not been set before (inherit is the default)
1289 if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
1290 host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
1291 }
Chris Craikd36a81f2014-07-17 10:16:51 -07001292 host.dispatchAttachedToWindow(mAttachInfo, 0);
1293 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
Adam Powell2accbf92014-04-16 23:14:57 +00001294 dispatchApplyInsets(host);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001295 //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
svetoslavganov75986cf2009-05-14 22:28:01 -07001296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001297 } else {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001298 desiredWindowWidth = frame.width();
1299 desiredWindowHeight = frame.height();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001300 if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001301 if (DEBUG_ORIENTATION) Log.v(TAG,
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001302 "View " + host + " resized to: " + frame);
Jeff Brown96e942d2011-11-30 19:55:01 -08001303 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001304 mLayoutRequested = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001305 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001306 }
1307 }
1308
1309 if (viewVisibilityChanged) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001310 mAttachInfo.mWindowVisibility = viewVisibility;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001311 host.dispatchWindowVisibilityChanged(viewVisibility);
1312 if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
Romain Guy65b345f2011-07-27 18:51:50 -07001313 destroyHardwareResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001314 }
1315 if (viewVisibility == View.GONE) {
1316 // After making a window gone, we will count it as being
1317 // shown for the first time the next time it gets focus.
1318 mHasHadWindowFocus = false;
1319 }
1320 }
1321
Chet Haaseb78c2842012-04-19 13:39:50 -07001322 // Execute enqueued actions on every traversal in case a detached view enqueued an action
Chris Craikd36a81f2014-07-17 10:16:51 -07001323 getRunQueue().executeActions(mAttachInfo.mHandler);
Chet Haaseb78c2842012-04-19 13:39:50 -07001324
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001325 boolean insetsChanged = false;
Romain Guy8506ab42009-06-11 17:35:47 -07001326
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001327 boolean layoutRequested = mLayoutRequested && !mStopped;
1328 if (layoutRequested) {
Romain Guy15df6702009-08-17 20:17:30 -07001329
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001330 final Resources res = mView.getContext().getResources();
1331
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001332 if (mFirst) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001333 // make sure touch mode code executes by setting cached value
1334 // to opposite of the added touch mode.
1335 mAttachInfo.mInTouchMode = !mAddedTouchMode;
Romain Guy2d4cff62010-04-09 15:39:00 -07001336 ensureTouchModeLocally(mAddedTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001337 } else {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001338 if (!mPendingOverscanInsets.equals(mAttachInfo.mOverscanInsets)) {
1339 insetsChanged = true;
1340 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001341 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342 insetsChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001343 }
Adrian Roosfa104232014-06-20 16:10:14 -07001344 if (!mPendingStableInsets.equals(mAttachInfo.mStableInsets)) {
1345 insetsChanged = true;
1346 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001347 if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001348 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1349 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1350 + mAttachInfo.mVisibleInsets);
1351 }
1352 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
1353 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001354 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001355
John Spurlockf8508272013-10-14 21:06:52 -04001356 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL
1357 || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
Dianne Hackborna239c842011-06-01 12:28:20 -07001358 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001359 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001360 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001361 desiredWindowWidth = size.x;
1362 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001363 } else {
1364 DisplayMetrics packageMetrics = res.getDisplayMetrics();
1365 desiredWindowWidth = packageMetrics.widthPixels;
1366 desiredWindowHeight = packageMetrics.heightPixels;
1367 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001368 }
1369 }
1370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001371 // Ask host how big it wants to be
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001372 windowSizeMayChange |= measureHierarchy(host, lp, res,
1373 desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001374 }
1375
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001376 if (collectViewAttributes()) {
1377 params = lp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378 }
Chris Craikd36a81f2014-07-17 10:16:51 -07001379 if (mAttachInfo.mForceReportNewAttributes) {
1380 mAttachInfo.mForceReportNewAttributes = false;
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001381 params = lp;
1382 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001383
Chris Craikd36a81f2014-07-17 10:16:51 -07001384 if (mFirst || mAttachInfo.mViewVisibilityChanged) {
1385 mAttachInfo.mViewVisibilityChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001386 int resizeMode = mSoftInputMode &
1387 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
1388 // If we are in auto resize mode, then we need to determine
1389 // what mode to use now.
1390 if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001391 final int N = mAttachInfo.mScrollContainers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392 for (int i=0; i<N; i++) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001393 if (mAttachInfo.mScrollContainers.get(i).isShown()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001394 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
1395 }
1396 }
1397 if (resizeMode == 0) {
1398 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
1399 }
1400 if ((lp.softInputMode &
1401 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
1402 lp.softInputMode = (lp.softInputMode &
1403 ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
1404 resizeMode;
1405 params = lp;
1406 }
1407 }
1408 }
Romain Guy8506ab42009-06-11 17:35:47 -07001409
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001410 if (params != null) {
1411 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
1412 if (!PixelFormat.formatHasAlpha(params.format)) {
1413 params.format = PixelFormat.TRANSLUCENT;
1414 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001415 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001416 mAttachInfo.mOverscanRequested = (params.flags
1417 & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001418 }
1419
Adrian Roosfa104232014-06-20 16:10:14 -07001420 if (mApplyInsetsRequested) {
1421 mApplyInsetsRequested = false;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001422 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Adam Powell2accbf92014-04-16 23:14:57 +00001423 dispatchApplyInsets(host);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001424 if (mLayoutRequested) {
1425 // Short-circuit catching a new layout request here, so
1426 // we don't need to go through two layout passes when things
1427 // change due to fitting system windows, which can happen a lot.
1428 windowSizeMayChange |= measureHierarchy(host, lp,
1429 mView.getContext().getResources(),
1430 desiredWindowWidth, desiredWindowHeight);
1431 }
1432 }
1433
1434 if (layoutRequested) {
1435 // Clear this now, so that if anything requests a layout in the
1436 // rest of this function we will catch it and re-run a full
1437 // layout pass.
1438 mLayoutRequested = false;
1439 }
1440
1441 boolean windowShouldResize = layoutRequested && windowSizeMayChange
Dianne Hackborn189ee182010-12-02 21:48:53 -08001442 && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
Romain Guy2e4f4262010-04-06 11:07:52 -07001443 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
1444 frame.width() < desiredWindowWidth && frame.width() != mWidth)
1445 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
1446 frame.height() < desiredWindowHeight && frame.height() != mHeight));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001447
Jeff Brown2e05ec32013-09-30 15:57:43 -07001448 // Determine whether to compute insets.
1449 // If there are no inset listeners remaining then we may still need to compute
1450 // insets in case the old insets were non-empty and must be reset.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451 final boolean computesInternalInsets =
Chris Craikd36a81f2014-07-17 10:16:51 -07001452 mAttachInfo.mTreeObserver.hasComputeInternalInsetsListeners()
1453 || mAttachInfo.mHasNonEmptyGivenInternalInsets;
Romain Guy812ccbe2010-06-01 14:07:24 -07001454
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001455 boolean insetsPending = false;
1456 int relayoutResult = 0;
Romain Guy812ccbe2010-06-01 14:07:24 -07001457
1458 if (mFirst || windowShouldResize || insetsChanged ||
1459 viewVisibilityChanged || params != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460
1461 if (viewVisibility == View.VISIBLE) {
1462 // If this window is giving internal insets to the window
1463 // manager, and it is being added or changing its visibility,
1464 // then we want to first give the window manager "fake"
1465 // insets to cause it to effectively ignore the content of
1466 // the window during layout. This avoids it briefly causing
1467 // other windows to resize/move based on the raw frame of the
1468 // window, waiting until we can finish laying out this window
1469 // and get back to the window manager with the ultimately
1470 // computed insets.
Romain Guy812ccbe2010-06-01 14:07:24 -07001471 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472 }
1473
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001474 if (mSurfaceHolder != null) {
1475 mSurfaceHolder.mSurfaceLock.lock();
1476 mDrawingAllowed = true;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001477 }
Romain Guy812ccbe2010-06-01 14:07:24 -07001478
Romain Guyc361da82010-10-25 15:29:10 -07001479 boolean hwInitialized = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001480 boolean contentInsetsChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001481 boolean hadSurface = mSurface.isValid();
Romain Guy812ccbe2010-06-01 14:07:24 -07001482
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001483 try {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001484 if (DEBUG_LAYOUT) {
Dianne Hackborn189ee182010-12-02 21:48:53 -08001485 Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" +
1486 host.getMeasuredHeight() + ", params=" + params);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001487 }
Romain Guy2a83f002011-01-18 18:28:21 -08001488
John Reckf7d9c1d2014-04-09 10:01:03 -07001489 if (mAttachInfo.mHardwareRenderer != null) {
1490 // relayoutWindow may decide to destroy mSurface. As that decision
1491 // happens in WindowManager service, we need to be defensive here
1492 // and stop using the surface in case it gets destroyed.
1493 mAttachInfo.mHardwareRenderer.pauseSurface(mSurface);
1494 }
Romain Guy2a83f002011-01-18 18:28:21 -08001495 final int surfaceGenerationId = mSurface.getGenerationId();
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001496 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
Dianne Hackborn021d2432013-10-13 15:20:09 -07001497 if (!mDrawDuringWindowsAnimating &&
1498 (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_ANIMATING) != 0) {
1499 mWindowsAnimating = true;
Michael Jurkaf42d90102013-05-08 18:00:04 +02001500 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001501
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001502 if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001503 + " overscan=" + mPendingOverscanInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001504 + " content=" + mPendingContentInsets.toShortString()
1505 + " visible=" + mPendingVisibleInsets.toShortString()
Adrian Roosfa104232014-06-20 16:10:14 -07001506 + " visible=" + mPendingStableInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001507 + " surface=" + mSurface);
Romain Guy8506ab42009-06-11 17:35:47 -07001508
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001509 if (mPendingConfiguration.seq != 0) {
1510 if (DEBUG_CONFIGURATION) Log.v(TAG, "Visible with new config: "
1511 + mPendingConfiguration);
1512 updateConfiguration(mPendingConfiguration, !mFirst);
1513 mPendingConfiguration.seq = 0;
1514 }
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001515
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001516 final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
1517 mAttachInfo.mOverscanInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001518 contentInsetsChanged = !mPendingContentInsets.equals(
1519 mAttachInfo.mContentInsets);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001520 final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001521 mAttachInfo.mVisibleInsets);
Adrian Roosfa104232014-06-20 16:10:14 -07001522 final boolean stableInsetsChanged = !mPendingStableInsets.equals(
1523 mAttachInfo.mStableInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001524 if (contentInsetsChanged) {
John Recke56e9df2014-02-21 15:45:10 -08001525 if (mWidth > 0 && mHeight > 0 && lp != null &&
1526 ((lp.systemUiVisibility|lp.subtreeSystemUiVisibility)
1527 & View.SYSTEM_UI_LAYOUT_FLAGS) == 0 &&
1528 mSurface != null && mSurface.isValid() &&
1529 !mAttachInfo.mTurnOffWindowResizeAnim &&
1530 mAttachInfo.mHardwareRenderer != null &&
1531 mAttachInfo.mHardwareRenderer.isEnabled() &&
John Reckf9a901e2014-02-28 13:02:15 -08001532 lp != null && !PixelFormat.formatHasAlpha(lp.format)
1533 && !mBlockResizeBuffer) {
John Recke56e9df2014-02-21 15:45:10 -08001534
1535 disposeResizeBuffer();
1536
John Reck25fbb3f2014-06-12 13:46:45 -07001537// TODO: Again....
1538// if (mResizeBuffer == null) {
1539// mResizeBuffer = mAttachInfo.mHardwareRenderer.createDisplayListLayer(
1540// mWidth, mHeight);
1541// }
1542// mResizeBuffer.prepare(mWidth, mHeight, false);
1543// RenderNode layerRenderNode = mResizeBuffer.startRecording();
1544// HardwareCanvas layerCanvas = layerRenderNode.start(mWidth, mHeight);
1545// try {
1546// final int restoreCount = layerCanvas.save();
1547//
1548// int yoff;
1549// final boolean scrolling = mScroller != null
1550// && mScroller.computeScrollOffset();
1551// if (scrolling) {
1552// yoff = mScroller.getCurrY();
1553// mScroller.abortAnimation();
1554// } else {
1555// yoff = mScrollY;
1556// }
1557//
1558// layerCanvas.translate(0, -yoff);
1559// if (mTranslator != null) {
1560// mTranslator.translateCanvas(layerCanvas);
1561// }
1562//
1563// RenderNode renderNode = mView.mRenderNode;
1564// if (renderNode != null && renderNode.isValid()) {
1565// layerCanvas.drawDisplayList(renderNode, null,
1566// RenderNode.FLAG_CLIP_CHILDREN);
1567// } else {
1568// mView.draw(layerCanvas);
1569// }
1570//
1571// drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
1572//
1573// mResizeBufferStartTime = SystemClock.uptimeMillis();
1574// mResizeBufferDuration = mView.getResources().getInteger(
1575// com.android.internal.R.integer.config_mediumAnimTime);
1576//
1577// layerCanvas.restoreToCount(restoreCount);
1578// layerRenderNode.end(layerCanvas);
1579// layerRenderNode.setCaching(true);
1580// layerRenderNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
1581// mTempRect.set(0, 0, mWidth, mHeight);
1582// } finally {
1583// mResizeBuffer.endRecording(mTempRect);
1584// }
1585// mAttachInfo.mHardwareRenderer.flushLayerUpdates();
John Recke56e9df2014-02-21 15:45:10 -08001586 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001587 mAttachInfo.mContentInsets.set(mPendingContentInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001588 if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
1589 + mAttachInfo.mContentInsets);
1590 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001591 if (overscanInsetsChanged) {
1592 mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets);
1593 if (DEBUG_LAYOUT) Log.v(TAG, "Overscan insets changing to: "
1594 + mAttachInfo.mOverscanInsets);
1595 // Need to relayout with content insets.
1596 contentInsetsChanged = true;
1597 }
Adrian Roosfa104232014-06-20 16:10:14 -07001598 if (stableInsetsChanged) {
1599 mAttachInfo.mStableInsets.set(mPendingStableInsets);
1600 if (DEBUG_LAYOUT) Log.v(TAG, "Decor insets changing to: "
1601 + mAttachInfo.mStableInsets);
1602 // Need to relayout with content insets.
1603 contentInsetsChanged = true;
1604 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001605 if (contentInsetsChanged || mLastSystemUiVisibility !=
Adrian Roosfa104232014-06-20 16:10:14 -07001606 mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001607 || mLastOverscanRequested != mAttachInfo.mOverscanRequested) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001608 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001609 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Adrian Roosfa104232014-06-20 16:10:14 -07001610 mApplyInsetsRequested = false;
Adam Powell2accbf92014-04-16 23:14:57 +00001611 dispatchApplyInsets(host);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001612 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001613 if (visibleInsetsChanged) {
1614 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1615 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1616 + mAttachInfo.mVisibleInsets);
1617 }
1618
1619 if (!hadSurface) {
1620 if (mSurface.isValid()) {
1621 // If we are creating a new surface, then we need to
1622 // completely redraw it. Also, when we get to the
1623 // point of drawing it we will hold off and schedule
1624 // a new traversal instead. This is so we can tell the
1625 // window manager about all of the windows being displayed
1626 // before actually drawing them, so it can display then
1627 // all at once.
1628 newSurface = true;
Jeff Brown96e942d2011-11-30 19:55:01 -08001629 mFullRedrawNeeded = true;
Jack Palevich61a6e682009-10-09 17:37:50 -07001630 mPreviousTransparentRegion.setEmpty();
Romain Guy8506ab42009-06-11 17:35:47 -07001631
Romain Guyb051e892010-09-28 19:09:36 -07001632 if (mAttachInfo.mHardwareRenderer != null) {
Dianne Hackborn64825172011-03-02 21:32:58 -08001633 try {
Romain Guy786fc932012-07-24 16:24:56 -07001634 hwInitialized = mAttachInfo.mHardwareRenderer.initialize(
John Reck79d81e62013-11-05 13:26:57 -08001635 mSurface);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001636 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08001637 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08001638 return;
1639 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001640 }
1641 }
1642 } else if (!mSurface.isValid()) {
1643 // If the surface has been removed, then reset the scroll
1644 // positions.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001645 if (mLastScrolledFocus != null) {
1646 mLastScrolledFocus.clear();
1647 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001648 mScrollY = mCurScrollY = 0;
1649 if (mScroller != null) {
1650 mScroller.abortAnimation();
1651 }
John Recke56e9df2014-02-21 15:45:10 -08001652 disposeResizeBuffer();
Romain Guy1d0c7082011-08-03 16:22:24 -07001653 // Our surface is gone
1654 if (mAttachInfo.mHardwareRenderer != null &&
1655 mAttachInfo.mHardwareRenderer.isEnabled()) {
John Reckf47a5942014-06-30 16:20:04 -07001656 mAttachInfo.mHardwareRenderer.destroy();
Romain Guy1d0c7082011-08-03 16:22:24 -07001657 }
Romain Guy2a83f002011-01-18 18:28:21 -08001658 } else if (surfaceGenerationId != mSurface.getGenerationId() &&
1659 mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001660 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08001661 try {
John Reck79d81e62013-11-05 13:26:57 -08001662 mAttachInfo.mHardwareRenderer.updateSurface(mSurface);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001663 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08001664 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08001665 return;
1666 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001667 }
1668 } catch (RemoteException e) {
1669 }
Romain Guy1d0c7082011-08-03 16:22:24 -07001670
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 if (DEBUG_ORIENTATION) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07001672 TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001673
Chris Craikd36a81f2014-07-17 10:16:51 -07001674 mAttachInfo.mWindowLeft = frame.left;
1675 mAttachInfo.mWindowTop = frame.top;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001676
1677 // !!FIXME!! This next section handles the case where we did not get the
1678 // window size we asked for. We should avoid this by getting a maximum size from
1679 // the window session beforehand.
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001680 if (mWidth != frame.width() || mHeight != frame.height()) {
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001681 mWidth = frame.width();
1682 mHeight = frame.height();
1683 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001684
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001685 if (mSurfaceHolder != null) {
1686 // The app owns the surface; tell it about what is going on.
1687 if (mSurface.isValid()) {
1688 // XXX .copyFrom() doesn't work!
1689 //mSurfaceHolder.mSurface.copyFrom(mSurface);
1690 mSurfaceHolder.mSurface = mSurface;
1691 }
Jeff Brown30bc34f2011-01-25 12:56:56 -08001692 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001693 mSurfaceHolder.mSurfaceLock.unlock();
1694 if (mSurface.isValid()) {
1695 if (!hadSurface) {
1696 mSurfaceHolder.ungetCallbacks();
1697
1698 mIsCreating = true;
1699 mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder);
1700 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1701 if (callbacks != null) {
1702 for (SurfaceHolder.Callback c : callbacks) {
1703 c.surfaceCreated(mSurfaceHolder);
1704 }
1705 }
1706 surfaceChanged = true;
1707 }
1708 if (surfaceChanged) {
1709 mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
1710 lp.format, mWidth, mHeight);
1711 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1712 if (callbacks != null) {
1713 for (SurfaceHolder.Callback c : callbacks) {
1714 c.surfaceChanged(mSurfaceHolder, lp.format,
1715 mWidth, mHeight);
1716 }
1717 }
1718 }
1719 mIsCreating = false;
1720 } else if (hadSurface) {
1721 mSurfaceHolder.ungetCallbacks();
1722 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1723 mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
1724 if (callbacks != null) {
1725 for (SurfaceHolder.Callback c : callbacks) {
1726 c.surfaceDestroyed(mSurfaceHolder);
1727 }
1728 }
1729 mSurfaceHolder.mSurfaceLock.lock();
Jozef BABJAK93c5b6a2011-02-22 09:33:19 +01001730 try {
1731 mSurfaceHolder.mSurface = new Surface();
1732 } finally {
1733 mSurfaceHolder.mSurfaceLock.unlock();
1734 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001735 }
1736 }
Romain Guy53389bd2010-09-07 17:16:32 -07001737
Chet Haase40e03832011-10-06 08:34:13 -07001738 if (mAttachInfo.mHardwareRenderer != null &&
1739 mAttachInfo.mHardwareRenderer.isEnabled()) {
Romain Guy370ab062013-05-21 12:15:07 -07001740 if (hwInitialized ||
Chet Haase40e03832011-10-06 08:34:13 -07001741 mWidth != mAttachInfo.mHardwareRenderer.getWidth() ||
1742 mHeight != mAttachInfo.mHardwareRenderer.getHeight()) {
Alan Viverette49a22e82014-07-12 20:01:27 -07001743 final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
1744 mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight, surfaceInsets);
Chet Haase40e03832011-10-06 08:34:13 -07001745 if (!hwInitialized) {
John Reck79d81e62013-11-05 13:26:57 -08001746 mAttachInfo.mHardwareRenderer.invalidate(mSurface);
Chet Haase391fef02012-09-27 15:26:36 -07001747 mFullRedrawNeeded = true;
Chet Haase40e03832011-10-06 08:34:13 -07001748 }
Romain Guy03985752011-07-11 15:33:51 -07001749 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 }
1751
Dianne Hackbornce418e62011-03-01 14:31:38 -08001752 if (!mStopped) {
1753 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
Jeff Brown98365d72012-08-19 20:30:52 -07001754 (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001755 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
1756 || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001757 int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
1758 int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001759
Dianne Hackbornce418e62011-03-01 14:31:38 -08001760 if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed! mWidth="
1761 + mWidth + " measuredWidth=" + host.getMeasuredWidth()
1762 + " mHeight=" + mHeight
1763 + " measuredHeight=" + host.getMeasuredHeight()
1764 + " coveredInsetsChanged=" + contentInsetsChanged);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001765
Dianne Hackbornce418e62011-03-01 14:31:38 -08001766 // Ask host how big it wants to be
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001767 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001768
Dianne Hackbornce418e62011-03-01 14:31:38 -08001769 // Implementation of weights from WindowManager.LayoutParams
1770 // We just grow the dimensions as needed and re-measure if
1771 // needs be
1772 int width = host.getMeasuredWidth();
1773 int height = host.getMeasuredHeight();
1774 boolean measureAgain = false;
Igor Murashkina86ab6402013-08-30 12:58:36 -07001775
Dianne Hackbornce418e62011-03-01 14:31:38 -08001776 if (lp.horizontalWeight > 0.0f) {
1777 width += (int) ((mWidth - width) * lp.horizontalWeight);
1778 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
1779 MeasureSpec.EXACTLY);
1780 measureAgain = true;
1781 }
1782 if (lp.verticalWeight > 0.0f) {
1783 height += (int) ((mHeight - height) * lp.verticalWeight);
1784 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
1785 MeasureSpec.EXACTLY);
1786 measureAgain = true;
1787 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001788
Dianne Hackbornce418e62011-03-01 14:31:38 -08001789 if (measureAgain) {
1790 if (DEBUG_LAYOUT) Log.v(TAG,
1791 "And hey let's measure once more: width=" + width
1792 + " height=" + height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001793 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001794 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001795
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001796 layoutRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001797 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001798 }
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001799 } else {
1800 // Not the first pass and no window/insets/visibility change but the window
1801 // may have moved and we need check that and if so to update the left and right
1802 // in the attach info. We translate only the window frame since on window move
1803 // the window manager tells us only for the new frame but the insets are the
1804 // same and we do not want to translate them more than once.
1805
1806 // TODO: Well, we are checking whether the frame has changed similarly
1807 // to how this is done for the insets. This is however incorrect since
1808 // the insets and the frame are translated. For example, the old frame
1809 // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new
1810 // reported frame is (2, 2 - 2, 2) which implies no change but this is not
1811 // true since we are comparing a not translated value to a translated one.
1812 // This scenario is rare but we may want to fix that.
1813
Chris Craikd36a81f2014-07-17 10:16:51 -07001814 final boolean windowMoved = (mAttachInfo.mWindowLeft != frame.left
1815 || mAttachInfo.mWindowTop != frame.top);
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001816 if (windowMoved) {
1817 if (mTranslator != null) {
1818 mTranslator.translateRectInScreenToAppWinFrame(frame);
1819 }
Chris Craikd36a81f2014-07-17 10:16:51 -07001820 mAttachInfo.mWindowLeft = frame.left;
1821 mAttachInfo.mWindowTop = frame.top;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001822 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001823 }
1824
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001825 final boolean didLayout = layoutRequested && !mStopped;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001826 boolean triggerGlobalLayoutListener = didLayout
Chris Craikd36a81f2014-07-17 10:16:51 -07001827 || mAttachInfo.mRecomputeGlobalAttributes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001828 if (didLayout) {
Chet Haase3efa7b52012-12-03 08:33:17 -08001829 performLayout(lp, desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001830
Mathias Agopian54e3d3842013-04-12 15:13:12 -07001831 // By this point all views have been sized and positioned
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001832 // We can compute the transparent area
1833
Dianne Hackborn4702a852012-08-17 15:18:29 -07001834 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001835 // start out transparent
1836 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
1837 host.getLocationInWindow(mTmpLocation);
1838 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
1839 mTmpLocation[0] + host.mRight - host.mLeft,
1840 mTmpLocation[1] + host.mBottom - host.mTop);
1841
1842 host.gatherTransparentRegion(mTransparentRegion);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001843 if (mTranslator != null) {
1844 mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
1845 }
1846
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001847 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
1848 mPreviousTransparentRegion.set(mTransparentRegion);
Mathias Agopian54e3d3842013-04-12 15:13:12 -07001849 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850 // reconfigure window manager
1851 try {
Jeff Brown98365d72012-08-19 20:30:52 -07001852 mWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001853 } catch (RemoteException e) {
1854 }
1855 }
1856 }
1857
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001858 if (DBG) {
1859 System.out.println("======================================");
1860 System.out.println("performTraversals -- after setFrame");
1861 host.debug();
1862 }
1863 }
1864
1865 if (triggerGlobalLayoutListener) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001866 mAttachInfo.mRecomputeGlobalAttributes = false;
1867 mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001868 }
1869
1870 if (computesInternalInsets) {
Jeff Brownfbf09772011-01-16 14:06:57 -08001871 // Clear the original insets.
Chris Craikd36a81f2014-07-17 10:16:51 -07001872 final ViewTreeObserver.InternalInsetsInfo insets = mAttachInfo.mGivenInternalInsets;
Jeff Brownfbf09772011-01-16 14:06:57 -08001873 insets.reset();
1874
1875 // Compute new insets in place.
Chris Craikd36a81f2014-07-17 10:16:51 -07001876 mAttachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
1877 mAttachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty();
Jeff Brownfbf09772011-01-16 14:06:57 -08001878
1879 // Tell the window manager.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001880 if (insetsPending || !mLastGivenInsets.equals(insets)) {
1881 mLastGivenInsets.set(insets);
Jeff Brownfbf09772011-01-16 14:06:57 -08001882
1883 // Translate insets to screen coordinates if needed.
1884 final Rect contentInsets;
1885 final Rect visibleInsets;
1886 final Region touchableRegion;
1887 if (mTranslator != null) {
1888 contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
1889 visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
1890 touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
1891 } else {
1892 contentInsets = insets.contentInsets;
1893 visibleInsets = insets.visibleInsets;
1894 touchableRegion = insets.touchableRegion;
1895 }
1896
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001897 try {
Jeff Brown98365d72012-08-19 20:30:52 -07001898 mWindowSession.setInsets(mWindow, insets.mTouchableInsets,
Jeff Brownfbf09772011-01-16 14:06:57 -08001899 contentInsets, visibleInsets, touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001900 } catch (RemoteException e) {
1901 }
1902 }
1903 }
Romain Guy8506ab42009-06-11 17:35:47 -07001904
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001905 boolean skipDraw = false;
1906
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001907 if (mFirst) {
1908 // handle first focus request
1909 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()="
1910 + mView.hasFocus());
1911 if (mView != null) {
1912 if (!mView.hasFocus()) {
1913 mView.requestFocus(View.FOCUS_FORWARD);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001914 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view="
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001915 + mView.findFocus());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001916 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001917 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view="
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001918 + mView.findFocus());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001919 }
1920 }
Jeff Brown98365d72012-08-19 20:30:52 -07001921 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_ANIMATING) != 0) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001922 // The first time we relayout the window, if the system is
1923 // doing window animations, we want to hold of on any future
1924 // draws until the animation is done.
1925 mWindowsAnimating = true;
1926 }
1927 } else if (mWindowsAnimating) {
1928 skipDraw = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001929 }
1930
1931 mFirst = false;
1932 mWillDrawSoon = false;
1933 mNewSurfaceNeeded = false;
1934 mViewVisibility = viewVisibility;
1935
keunyoung30f420f2013-08-02 14:23:10 -07001936 if (mAttachInfo.mHasWindowFocus && !isInLocalFocusMode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001937 final boolean imTarget = WindowManager.LayoutParams
1938 .mayUseInputMethod(mWindowAttributes.flags);
1939 if (imTarget != mLastWasImTarget) {
1940 mLastWasImTarget = imTarget;
1941 InputMethodManager imm = InputMethodManager.peekInstance();
1942 if (imm != null && imTarget) {
1943 imm.startGettingWindowFocus(mView);
1944 imm.onWindowFocus(mView, mView.findFocus(),
1945 mWindowAttributes.softInputMode,
1946 !mHasHadWindowFocus, mWindowAttributes.flags);
1947 }
1948 }
1949 }
Romain Guy8506ab42009-06-11 17:35:47 -07001950
Jeff Brown96e942d2011-11-30 19:55:01 -08001951 // Remember if we must report the next draw.
Jeff Brown98365d72012-08-19 20:30:52 -07001952 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001953 mReportNextDraw = true;
1954 }
1955
Chris Craikd36a81f2014-07-17 10:16:51 -07001956 boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() ||
Romain Guyea835032011-07-28 19:24:37 -07001957 viewVisibility != View.VISIBLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001958
Chet Haase61158c62011-09-06 22:19:45 -07001959 if (!cancelDraw && !newSurface) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001960 if (!skipDraw || mReportNextDraw) {
1961 if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
1962 for (int i = 0; i < mPendingTransitions.size(); ++i) {
1963 mPendingTransitions.get(i).startChangingAnimations();
1964 }
1965 mPendingTransitions.clear();
Chet Haased56c6952011-09-07 08:46:23 -07001966 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001967
Dianne Hackborn12d3a942012-04-27 14:16:30 -07001968 performDraw();
Chet Haased56c6952011-09-07 08:46:23 -07001969 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001970 } else {
Chris Wren78cb7cf2012-05-15 12:36:44 -04001971 if (viewVisibility == View.VISIBLE) {
1972 // Try again
1973 scheduleTraversals();
1974 } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
Chet Haased56c6952011-09-07 08:46:23 -07001975 for (int i = 0; i < mPendingTransitions.size(); ++i) {
1976 mPendingTransitions.get(i).endChangingAnimations();
1977 }
1978 mPendingTransitions.clear();
1979 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001980 }
Craig Mautnerdf2390a2012-08-29 20:59:22 -07001981
1982 mIsInTraversal = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001983 }
1984
Romain Guy3696779b2013-01-28 14:04:07 -08001985 private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
1986 Log.e(TAG, "OutOfResourcesException initializing HW surface", e);
1987 try {
1988 if (!mWindowSession.outOfMemory(mWindow) &&
1989 Process.myUid() != Process.SYSTEM_UID) {
1990 Slog.w(TAG, "No processes killed for memory; killing self");
1991 Process.killProcess(Process.myPid());
1992 }
1993 } catch (RemoteException ex) {
1994 }
1995 mLayoutRequested = true; // ask wm for a new surface next time.
1996 }
1997
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001998 private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
1999 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
2000 try {
2001 mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
2002 } finally {
2003 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2004 }
2005 }
2006
Chet Haase97140572012-09-13 14:56:47 -07002007 /**
2008 * Called by {@link android.view.View#isInLayout()} to determine whether the view hierarchy
2009 * is currently undergoing a layout pass.
2010 *
2011 * @return whether the view hierarchy is currently undergoing a layout pass
2012 */
2013 boolean isInLayout() {
2014 return mInLayout;
2015 }
2016
2017 /**
Chet Haasecc699b42012-12-13 09:06:55 -08002018 * Called by {@link android.view.View#requestLayout()} if the view hierarchy is currently
2019 * undergoing a layout pass. requestLayout() should not generally be called during layout,
2020 * unless the container hierarchy knows what it is doing (i.e., it is fine as long as
2021 * all children in that container hierarchy are measured and laid out at the end of the layout
2022 * pass for that container). If requestLayout() is called anyway, we handle it correctly
2023 * by registering all requesters during a frame as it proceeds. At the end of the frame,
2024 * we check all of those views to see if any still have pending layout requests, which
2025 * indicates that they were not correctly handled by their container hierarchy. If that is
2026 * the case, we clear all such flags in the tree, to remove the buggy flag state that leads
2027 * to blank containers, and force a second request/measure/layout pass in this frame. If
Chet Haase97140572012-09-13 14:56:47 -07002028 * more requestLayout() calls are received during that second layout pass, we post those
Chet Haasecc699b42012-12-13 09:06:55 -08002029 * requests to the next frame to avoid possible infinite loops.
2030 *
2031 * <p>The return value from this method indicates whether the request should proceed
2032 * (if it is a request during the first layout pass) or should be skipped and posted to the
2033 * next frame (if it is a request during the second layout pass).</p>
Chet Haase97140572012-09-13 14:56:47 -07002034 *
2035 * @param view the view that requested the layout.
Chet Haasecc699b42012-12-13 09:06:55 -08002036 *
2037 * @return true if request should proceed, false otherwise.
Chet Haase97140572012-09-13 14:56:47 -07002038 */
Chet Haasecc699b42012-12-13 09:06:55 -08002039 boolean requestLayoutDuringLayout(final View view) {
2040 if (view.mParent == null || view.mAttachInfo == null) {
2041 // Would not normally trigger another layout, so just let it pass through as usual
2042 return true;
2043 }
Chet Haase107a4822013-03-13 06:46:50 -07002044 if (!mLayoutRequesters.contains(view)) {
2045 mLayoutRequesters.add(view);
2046 }
Chet Haase97140572012-09-13 14:56:47 -07002047 if (!mHandlingLayoutInLayoutRequest) {
Chet Haase107a4822013-03-13 06:46:50 -07002048 // Let the request proceed normally; it will be processed in a second layout pass
2049 // if necessary
Chet Haasecc699b42012-12-13 09:06:55 -08002050 return true;
Chet Haase97140572012-09-13 14:56:47 -07002051 } else {
Chet Haase107a4822013-03-13 06:46:50 -07002052 // Don't let the request proceed during the second layout pass.
2053 // It will post to the next frame instead.
Chet Haasecc699b42012-12-13 09:06:55 -08002054 return false;
Chet Haase97140572012-09-13 14:56:47 -07002055 }
2056 }
2057
Chet Haase3efa7b52012-12-03 08:33:17 -08002058 private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
2059 int desiredWindowHeight) {
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002060 mLayoutRequested = false;
2061 mScrollMayChange = true;
Chet Haase97140572012-09-13 14:56:47 -07002062 mInLayout = true;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002063
2064 final View host = mView;
2065 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
2066 Log.v(TAG, "Laying out " + host + " to (" +
2067 host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
2068 }
2069
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002070 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
2071 try {
2072 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haasecc699b42012-12-13 09:06:55 -08002073
Chet Haased5a83522012-11-21 16:24:44 -08002074 mInLayout = false;
Chet Haase97140572012-09-13 14:56:47 -07002075 int numViewsRequestingLayout = mLayoutRequesters.size();
2076 if (numViewsRequestingLayout > 0) {
Chet Haasecc699b42012-12-13 09:06:55 -08002077 // requestLayout() was called during layout.
2078 // If no layout-request flags are set on the requesting views, there is no problem.
2079 // If some requests are still pending, then we need to clear those flags and do
2080 // a full request/measure/layout pass to handle this situation.
Chet Haase107a4822013-03-13 06:46:50 -07002081 ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
2082 false);
2083 if (validLayoutRequesters != null) {
2084 // Set this flag to indicate that any further requests are happening during
2085 // the second pass, which may result in posting those requests to the next
2086 // frame instead
Chet Haasecc699b42012-12-13 09:06:55 -08002087 mHandlingLayoutInLayoutRequest = true;
Chet Haase107a4822013-03-13 06:46:50 -07002088
2089 // Process fresh layout requests, then measure and layout
2090 int numValidRequests = validLayoutRequesters.size();
Chet Haasecc699b42012-12-13 09:06:55 -08002091 for (int i = 0; i < numValidRequests; ++i) {
Chet Haase107a4822013-03-13 06:46:50 -07002092 final View view = validLayoutRequesters.get(i);
2093 Log.w("View", "requestLayout() improperly called by " + view +
2094 " during layout: running second layout pass");
2095 view.requestLayout();
Chet Haasecc699b42012-12-13 09:06:55 -08002096 }
2097 measureHierarchy(host, lp, mView.getContext().getResources(),
2098 desiredWindowWidth, desiredWindowHeight);
2099 mInLayout = true;
2100 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haase107a4822013-03-13 06:46:50 -07002101
Chet Haasecc699b42012-12-13 09:06:55 -08002102 mHandlingLayoutInLayoutRequest = false;
Chet Haase107a4822013-03-13 06:46:50 -07002103
2104 // Check the valid requests again, this time without checking/clearing the
2105 // layout flags, since requests happening during the second pass get noop'd
2106 validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);
2107 if (validLayoutRequesters != null) {
2108 final ArrayList<View> finalRequesters = validLayoutRequesters;
2109 // Post second-pass requests to the next frame
2110 getRunQueue().post(new Runnable() {
2111 @Override
2112 public void run() {
2113 int numValidRequests = finalRequesters.size();
2114 for (int i = 0; i < numValidRequests; ++i) {
2115 final View view = finalRequesters.get(i);
2116 Log.w("View", "requestLayout() improperly called by " + view +
2117 " during second layout pass: posting in next frame");
2118 view.requestLayout();
2119 }
2120 }
2121 });
2122 }
Chet Haasecc699b42012-12-13 09:06:55 -08002123 }
Chet Haase107a4822013-03-13 06:46:50 -07002124
Chet Haase97140572012-09-13 14:56:47 -07002125 }
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002126 } finally {
2127 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2128 }
Chet Haase97140572012-09-13 14:56:47 -07002129 mInLayout = false;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002130 }
2131
Chet Haase107a4822013-03-13 06:46:50 -07002132 /**
2133 * This method is called during layout when there have been calls to requestLayout() during
2134 * layout. It walks through the list of views that requested layout to determine which ones
2135 * still need it, based on visibility in the hierarchy and whether they have already been
2136 * handled (as is usually the case with ListView children).
2137 *
2138 * @param layoutRequesters The list of views that requested layout during layout
2139 * @param secondLayoutRequests Whether the requests were issued during the second layout pass.
2140 * If so, the FORCE_LAYOUT flag was not set on requesters.
2141 * @return A list of the actual views that still need to be laid out.
2142 */
2143 private ArrayList<View> getValidLayoutRequesters(ArrayList<View> layoutRequesters,
2144 boolean secondLayoutRequests) {
2145
2146 int numViewsRequestingLayout = layoutRequesters.size();
2147 ArrayList<View> validLayoutRequesters = null;
2148 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2149 View view = layoutRequesters.get(i);
2150 if (view != null && view.mAttachInfo != null && view.mParent != null &&
2151 (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) ==
2152 View.PFLAG_FORCE_LAYOUT)) {
2153 boolean gone = false;
2154 View parent = view;
2155 // Only trigger new requests for views in a non-GONE hierarchy
2156 while (parent != null) {
2157 if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) {
2158 gone = true;
2159 break;
2160 }
2161 if (parent.mParent instanceof View) {
2162 parent = (View) parent.mParent;
2163 } else {
2164 parent = null;
2165 }
2166 }
2167 if (!gone) {
2168 if (validLayoutRequesters == null) {
2169 validLayoutRequesters = new ArrayList<View>();
2170 }
2171 validLayoutRequesters.add(view);
2172 }
2173 }
2174 }
2175 if (!secondLayoutRequests) {
2176 // If we're checking the layout flags, then we need to clean them up also
2177 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2178 View view = layoutRequesters.get(i);
2179 while (view != null &&
2180 (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
2181 view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
2182 if (view.mParent instanceof View) {
2183 view = (View) view.mParent;
2184 } else {
2185 view = null;
2186 }
2187 }
2188 }
2189 }
2190 layoutRequesters.clear();
2191 return validLayoutRequesters;
2192 }
2193
Igor Murashkina86ab6402013-08-30 12:58:36 -07002194 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002195 public void requestTransparentRegion(View child) {
2196 // the test below should not fail unless someone is messing with us
2197 checkThread();
2198 if (mView == child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002199 mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002200 // Need to make sure we re-evaluate the window attributes next
2201 // time around, to ensure the window has the correct format.
2202 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -07002203 mWindowAttributesChangesFlag = 0;
Mathias Agopian1bd80ad2010-11-04 17:13:39 -07002204 requestLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002205 }
2206 }
2207
2208 /**
2209 * Figures out the measure spec for the root view in a window based on it's
2210 * layout params.
2211 *
2212 * @param windowSize
2213 * The available width or height of the window
2214 *
2215 * @param rootDimension
2216 * The layout params for one dimension (width or height) of the
2217 * window.
2218 *
2219 * @return The measure spec to use to measure the root view.
2220 */
Romain Guya998dff2012-03-23 18:58:36 -07002221 private static int getRootMeasureSpec(int windowSize, int rootDimension) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002222 int measureSpec;
2223 switch (rootDimension) {
2224
Romain Guy980a9382010-01-08 15:06:28 -08002225 case ViewGroup.LayoutParams.MATCH_PARENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002226 // Window can't resize. Force root view to be windowSize.
2227 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
2228 break;
2229 case ViewGroup.LayoutParams.WRAP_CONTENT:
2230 // Window can resize. Set max size for root view.
2231 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
2232 break;
2233 default:
2234 // Window wants to be an exact size. Force root view to be that size.
2235 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
2236 break;
2237 }
2238 return measureSpec;
2239 }
2240
Alan Viveretteccb11e12014-07-08 16:04:02 -07002241 int mHardwareXOffset;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002242 int mHardwareYOffset;
2243 int mResizeAlpha;
2244 final Paint mResizePaint = new Paint();
2245
Igor Murashkina86ab6402013-08-30 12:58:36 -07002246 @Override
Romain Guy7d70fbf2011-05-24 17:40:25 -07002247 public void onHardwarePreDraw(HardwareCanvas canvas) {
Alan Viveretteccb11e12014-07-08 16:04:02 -07002248 canvas.translate(-mHardwareXOffset, -mHardwareYOffset);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002249 }
2250
Igor Murashkina86ab6402013-08-30 12:58:36 -07002251 @Override
Romain Guy7d70fbf2011-05-24 17:40:25 -07002252 public void onHardwarePostDraw(HardwareCanvas canvas) {
John Recke56e9df2014-02-21 15:45:10 -08002253 if (mResizeBuffer != null) {
2254 mResizePaint.setAlpha(mResizeAlpha);
Alan Viveretteccb11e12014-07-08 16:04:02 -07002255 canvas.drawHardwareLayer(mResizeBuffer, mHardwareXOffset, mHardwareYOffset,
2256 mResizePaint);
John Recke56e9df2014-02-21 15:45:10 -08002257 }
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002258 }
2259
Chet Haaseed30fd82011-04-22 16:18:45 -07002260 /**
2261 * @hide
2262 */
2263 void outputDisplayList(View view) {
Chris Craik64a12e12014-03-28 18:12:12 -07002264 RenderNode renderNode = view.getDisplayList();
2265 if (renderNode != null) {
2266 renderNode.output();
John Reck63049192013-12-10 15:22:01 -08002267 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002268 }
2269
2270 /**
2271 * @see #PROPERTY_PROFILE_RENDERING
2272 */
2273 private void profileRendering(boolean enabled) {
2274 if (mProfileRendering) {
2275 mRenderProfilingEnabled = enabled;
Chris Craikae4f32042013-02-07 12:57:10 -08002276
2277 if (mRenderProfiler != null) {
2278 mChoreographer.removeFrameCallback(mRenderProfiler);
2279 }
2280 if (mRenderProfilingEnabled) {
2281 if (mRenderProfiler == null) {
2282 mRenderProfiler = new Choreographer.FrameCallback() {
2283 @Override
2284 public void doFrame(long frameTimeNanos) {
2285 mDirty.set(0, 0, mWidth, mHeight);
2286 scheduleTraversals();
2287 if (mRenderProfilingEnabled) {
2288 mChoreographer.postFrameCallback(mRenderProfiler);
2289 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002290 }
Chris Craikae4f32042013-02-07 12:57:10 -08002291 };
2292 }
Romain Guy5bb3c732012-11-29 17:52:58 -08002293 mChoreographer.postFrameCallback(mRenderProfiler);
Romain Guy59a12ca2011-06-09 17:48:21 -07002294 } else {
Romain Guy59a12ca2011-06-09 17:48:21 -07002295 mRenderProfiler = null;
Chet Haaseed30fd82011-04-22 16:18:45 -07002296 }
2297 }
2298 }
2299
Chet Haase2f2022a2011-10-11 06:41:59 -07002300 /**
2301 * Called from draw() when DEBUG_FPS is enabled
2302 */
2303 private void trackFPS() {
2304 // Tracks frames per second drawn. First value in a series of draws may be bogus
2305 // because it down not account for the intervening idle time
2306 long nowTime = System.currentTimeMillis();
2307 if (mFpsStartTime < 0) {
2308 mFpsStartTime = mFpsPrevTime = nowTime;
2309 mFpsNumFrames = 0;
2310 } else {
2311 ++mFpsNumFrames;
2312 String thisHash = Integer.toHexString(System.identityHashCode(this));
2313 long frameTime = nowTime - mFpsPrevTime;
2314 long totalTime = nowTime - mFpsStartTime;
2315 Log.v(TAG, "0x" + thisHash + "\tFrame time:\t" + frameTime);
2316 mFpsPrevTime = nowTime;
2317 if (totalTime > 1000) {
2318 float fps = (float) mFpsNumFrames * 1000 / totalTime;
2319 Log.v(TAG, "0x" + thisHash + "\tFPS:\t" + fps);
2320 mFpsStartTime = nowTime;
2321 mFpsNumFrames = 0;
2322 }
2323 }
2324 }
2325
Jeff Brown96e942d2011-11-30 19:55:01 -08002326 private void performDraw() {
Jeff Brownd912e1f2014-04-11 18:46:22 -07002327 if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
Craig Mautner006f0e42012-03-21 11:00:32 -07002328 return;
2329 }
Romain Guy7e4e5612012-03-05 14:37:29 -08002330
Jeff Brown96e942d2011-11-30 19:55:01 -08002331 final boolean fullRedrawNeeded = mFullRedrawNeeded;
2332 mFullRedrawNeeded = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002333
Romain Guy1f59e5c2012-05-06 14:11:16 -07002334 mIsDrawing = true;
Jeff Brown481c1572012-03-09 14:41:15 -08002335 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
2336 try {
2337 draw(fullRedrawNeeded);
2338 } finally {
Romain Guy1f59e5c2012-05-06 14:11:16 -07002339 mIsDrawing = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002340 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2341 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002342
John Reck119907c2014-08-14 09:02:01 -07002343 // For whatever reason we didn't create a HardwareRenderer, end any
2344 // hardware animations that are now dangling
2345 if (mAttachInfo.mPendingAnimatingRenderNodes != null) {
2346 final int count = mAttachInfo.mPendingAnimatingRenderNodes.size();
2347 for (int i = 0; i < count; i++) {
2348 mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators();
2349 }
2350 mAttachInfo.mPendingAnimatingRenderNodes.clear();
2351 }
2352
Jeff Brown96e942d2011-11-30 19:55:01 -08002353 if (mReportNextDraw) {
2354 mReportNextDraw = false;
John Reck28ad7b52014-04-07 16:59:25 -07002355 if (mAttachInfo.mHardwareRenderer != null) {
2356 mAttachInfo.mHardwareRenderer.fence();
2357 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002358
2359 if (LOCAL_LOGV) {
2360 Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
2361 }
2362 if (mSurfaceHolder != null && mSurface.isValid()) {
2363 mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
2364 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
2365 if (callbacks != null) {
2366 for (SurfaceHolder.Callback c : callbacks) {
2367 if (c instanceof SurfaceHolder.Callback2) {
2368 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
2369 mSurfaceHolder);
2370 }
2371 }
2372 }
2373 }
2374 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002375 mWindowSession.finishDrawing(mWindow);
Jeff Brown96e942d2011-11-30 19:55:01 -08002376 } catch (RemoteException e) {
2377 }
2378 }
2379 }
2380
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002381 private void draw(boolean fullRedrawNeeded) {
2382 Surface surface = mSurface;
Romain Guyfbb93fa2012-12-03 18:50:35 -08002383 if (!surface.isValid()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002384 return;
2385 }
2386
Chet Haase2f2022a2011-10-11 06:41:59 -07002387 if (DEBUG_FPS) {
2388 trackFPS();
2389 }
2390
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002391 if (!sFirstDrawComplete) {
2392 synchronized (sFirstDrawHandlers) {
2393 sFirstDrawComplete = true;
Romain Guy812ccbe2010-06-01 14:07:24 -07002394 final int count = sFirstDrawHandlers.size();
2395 for (int i = 0; i< count; i++) {
Jeff Browna175a5b2012-02-15 19:18:31 -08002396 mHandler.post(sFirstDrawHandlers.get(i));
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002397 }
2398 }
2399 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002401 scrollToRectOrFocus(null, false);
2402
Chris Craikd36a81f2014-07-17 10:16:51 -07002403 if (mAttachInfo.mViewScrollChanged) {
2404 mAttachInfo.mViewScrollChanged = false;
2405 mAttachInfo.mTreeObserver.dispatchOnScrollChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002406 }
Romain Guy8506ab42009-06-11 17:35:47 -07002407
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002408 boolean animating = mScroller != null && mScroller.computeScrollOffset();
Alan Viveretteccb11e12014-07-08 16:04:02 -07002409 final int curScrollY;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002410 if (animating) {
Alan Viveretteccb11e12014-07-08 16:04:02 -07002411 curScrollY = mScroller.getCurrY();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002412 } else {
Alan Viveretteccb11e12014-07-08 16:04:02 -07002413 curScrollY = mScrollY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002414 }
Alan Viveretteccb11e12014-07-08 16:04:02 -07002415 if (mCurScrollY != curScrollY) {
2416 mCurScrollY = curScrollY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002417 fullRedrawNeeded = true;
2418 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002419
Chris Craikd36a81f2014-07-17 10:16:51 -07002420 final float appScale = mAttachInfo.mApplicationScale;
2421 final boolean scalingRequired = mAttachInfo.mScalingRequired;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002422
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002423 int resizeAlpha = 0;
John Recke56e9df2014-02-21 15:45:10 -08002424 if (mResizeBuffer != null) {
2425 long deltaTime = SystemClock.uptimeMillis() - mResizeBufferStartTime;
2426 if (deltaTime < mResizeBufferDuration) {
2427 float amt = deltaTime/(float) mResizeBufferDuration;
2428 amt = mResizeInterpolator.getInterpolation(amt);
2429 animating = true;
2430 resizeAlpha = 255 - (int)(amt*255);
2431 } else {
2432 disposeResizeBuffer();
2433 }
2434 }
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002435
Jeff Brown96e942d2011-11-30 19:55:01 -08002436 final Rect dirty = mDirty;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002437 if (mSurfaceHolder != null) {
2438 // The app owns the surface, we won't draw.
2439 dirty.setEmpty();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002440 if (animating) {
2441 if (mScroller != null) {
2442 mScroller.abortAnimation();
2443 }
John Recke56e9df2014-02-21 15:45:10 -08002444 disposeResizeBuffer();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002445 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002446 return;
2447 }
Romain Guy58ef7fb2010-09-13 12:52:37 -07002448
2449 if (fullRedrawNeeded) {
Chris Craikd36a81f2014-07-17 10:16:51 -07002450 mAttachInfo.mIgnoreDirtyState = true;
Romain Guyc3166e12011-08-08 15:00:03 -07002451 dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
Romain Guy58ef7fb2010-09-13 12:52:37 -07002452 }
Chet Haasead4f7032011-06-22 09:18:31 -07002453
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002454 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07002455 Log.v(TAG, "Draw " + mView + "/"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002456 + mWindowAttributes.getTitle()
2457 + ": dirty={" + dirty.left + "," + dirty.top
2458 + "," + dirty.right + "," + dirty.bottom + "} surface="
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002459 + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
2460 appScale + ", width=" + mWidth + ", height=" + mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002461 }
2462
Chris Craikd36a81f2014-07-17 10:16:51 -07002463 mAttachInfo.mTreeObserver.dispatchOnDraw();
Romain Guy25eba5c2012-04-04 17:29:03 -07002464
Alan Viverettea51cab92014-07-16 15:15:49 -07002465 int xOffset = 0;
2466 int yOffset = curScrollY;
2467 final WindowManager.LayoutParams params = mWindowAttributes;
2468 final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
2469 if (surfaceInsets != null) {
2470 xOffset -= surfaceInsets.left;
2471 yOffset -= surfaceInsets.top;
2472
2473 // Offset dirty rect for surface insets.
2474 dirty.offset(surfaceInsets.left, surfaceInsets.right);
2475 }
2476
Mathias Agopiana62b09a2010-04-21 18:36:53 -07002477 if (!dirty.isEmpty() || mIsAnimating) {
Chris Craikd36a81f2014-07-17 10:16:51 -07002478 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
Jeff Brown96e942d2011-11-30 19:55:01 -08002479 // Draw with hardware renderer.
2480 mIsAnimating = false;
Alan Viverettef6cf1a02014-08-11 14:13:02 -07002481 boolean invalidateRoot = false;
John Reck0a973302014-07-16 13:29:45 -07002482 if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
2483 mHardwareYOffset = yOffset;
2484 mHardwareXOffset = xOffset;
Alan Viverettef6cf1a02014-08-11 14:13:02 -07002485 mAttachInfo.mHardwareRenderer.invalidateRoot();
2486 }
Alan Viverette997aa402014-08-19 13:34:30 -07002487 mResizeAlpha = resizeAlpha;
Alan Viverettef6cf1a02014-08-11 14:13:02 -07002488
Jeff Brown96e942d2011-11-30 19:55:01 -08002489 dirty.setEmpty();
2490
John Reckf9a901e2014-02-28 13:02:15 -08002491 mBlockResizeBuffer = false;
John Reck61375a82014-09-18 19:27:48 +00002492 mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this);
Romain Guy3696779b2013-01-28 14:04:07 -08002493 } else {
2494 // If we get here with a disabled & requested hardware renderer, something went
2495 // wrong (an invalidate posted right before we destroyed the hardware surface
2496 // for instance) so we should just bail out. Locking the surface with software
2497 // rendering at this point would lock it forever and prevent hardware renderer
2498 // from doing its job when it comes back.
2499 // Before we request a new frame we must however attempt to reinitiliaze the
2500 // hardware renderer if it's in requested state. This would happen after an
2501 // eglTerminate() for instance.
Chris Craikd36a81f2014-07-17 10:16:51 -07002502 if (mAttachInfo.mHardwareRenderer != null &&
2503 !mAttachInfo.mHardwareRenderer.isEnabled() &&
2504 mAttachInfo.mHardwareRenderer.isRequested()) {
Romain Guy3696779b2013-01-28 14:04:07 -08002505
2506 try {
Chris Craikd36a81f2014-07-17 10:16:51 -07002507 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
Alan Viverette58c42c32014-07-12 20:33:45 -07002508 mWidth, mHeight, mSurface, surfaceInsets);
Igor Murashkina86ab6402013-08-30 12:58:36 -07002509 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002510 handleOutOfResourcesException(e);
2511 return;
2512 }
2513
2514 mFullRedrawNeeded = true;
2515 scheduleTraversals();
2516 return;
2517 }
2518
Chris Craikd36a81f2014-07-17 10:16:51 -07002519 if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
Romain Guy3696779b2013-01-28 14:04:07 -08002520 return;
2521 }
Jeff Brown95db2b22011-11-30 19:54:41 -08002522 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002523 }
Romain Guy8506ab42009-06-11 17:35:47 -07002524
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002525 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002526 mFullRedrawNeeded = true;
2527 scheduleTraversals();
2528 }
2529 }
2530
Romain Guy25eba5c2012-04-04 17:29:03 -07002531 /**
Alan Viveretteccb11e12014-07-08 16:04:02 -07002532 * @return true if drawing was successful, false if an error occurred
Romain Guy25eba5c2012-04-04 17:29:03 -07002533 */
Alan Viveretteccb11e12014-07-08 16:04:02 -07002534 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
Romain Guy25eba5c2012-04-04 17:29:03 -07002535 boolean scalingRequired, Rect dirty) {
2536
2537 // Draw with software renderer.
Alan Viverettea51cab92014-07-16 15:15:49 -07002538 final Canvas canvas;
Romain Guy25eba5c2012-04-04 17:29:03 -07002539 try {
Alan Viverettea51cab92014-07-16 15:15:49 -07002540 final int left = dirty.left;
2541 final int top = dirty.top;
2542 final int right = dirty.right;
2543 final int bottom = dirty.bottom;
Romain Guy25eba5c2012-04-04 17:29:03 -07002544
Romain Guy25eba5c2012-04-04 17:29:03 -07002545 canvas = mSurface.lockCanvas(dirty);
2546
Romain Guye55945e2013-04-04 15:26:04 -07002547 // The dirty rectangle can be modified by Surface.lockCanvas()
2548 //noinspection ConstantConditions
Alan Viverettea51cab92014-07-16 15:15:49 -07002549 if (left != dirty.left || top != dirty.top || right != dirty.right
2550 || bottom != dirty.bottom) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002551 attachInfo.mIgnoreDirtyState = true;
2552 }
2553
2554 // TODO: Do this in native
2555 canvas.setDensity(mDensity);
2556 } catch (Surface.OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002557 handleOutOfResourcesException(e);
Romain Guy25eba5c2012-04-04 17:29:03 -07002558 return false;
2559 } catch (IllegalArgumentException e) {
Romain Guydddcd222012-05-18 15:33:57 -07002560 Log.e(TAG, "Could not lock surface", e);
Romain Guy25eba5c2012-04-04 17:29:03 -07002561 // Don't assume this is due to out of memory, it could be
2562 // something else, and if it is something else then we could
2563 // kill stuff (or ourself) for no reason.
2564 mLayoutRequested = true; // ask wm for a new surface next time.
2565 return false;
2566 }
2567
2568 try {
2569 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
2570 Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
2571 + canvas.getWidth() + ", h=" + canvas.getHeight());
2572 //canvas.drawARGB(255, 255, 0, 0);
2573 }
2574
Romain Guy25eba5c2012-04-04 17:29:03 -07002575 // If this bitmap's format includes an alpha channel, we
2576 // need to clear it before drawing so that the child will
2577 // properly re-composite its drawing on a transparent
2578 // background. This automatically respects the clip/dirty region
2579 // or
2580 // If we are applying an offset, we need to clear the area
2581 // where the offset doesn't appear to avoid having garbage
2582 // left in the blank areas.
Alan Viveretteccb11e12014-07-08 16:04:02 -07002583 if (!canvas.isOpaque() || yoff != 0 || xoff != 0) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002584 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
2585 }
2586
2587 dirty.setEmpty();
2588 mIsAnimating = false;
2589 attachInfo.mDrawingTime = SystemClock.uptimeMillis();
Dianne Hackborn4702a852012-08-17 15:18:29 -07002590 mView.mPrivateFlags |= View.PFLAG_DRAWN;
Romain Guy25eba5c2012-04-04 17:29:03 -07002591
2592 if (DEBUG_DRAW) {
2593 Context cxt = mView.getContext();
2594 Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
2595 ", metrics=" + cxt.getResources().getDisplayMetrics() +
2596 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
2597 }
2598 try {
Alan Viveretteccb11e12014-07-08 16:04:02 -07002599 canvas.translate(-xoff, -yoff);
Romain Guy25eba5c2012-04-04 17:29:03 -07002600 if (mTranslator != null) {
2601 mTranslator.translateCanvas(canvas);
2602 }
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002603 canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
Romain Guy25eba5c2012-04-04 17:29:03 -07002604 attachInfo.mSetIgnoreDirtyState = false;
2605
Romain Guy25eba5c2012-04-04 17:29:03 -07002606 mView.draw(canvas);
Romain Guy25eba5c2012-04-04 17:29:03 -07002607 } finally {
2608 if (!attachInfo.mSetIgnoreDirtyState) {
2609 // Only clear the flag if it was not set during the mView.draw() call
2610 attachInfo.mIgnoreDirtyState = false;
2611 }
2612 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002613 } finally {
Romain Guydddcd222012-05-18 15:33:57 -07002614 try {
2615 surface.unlockCanvasAndPost(canvas);
2616 } catch (IllegalArgumentException e) {
2617 Log.e(TAG, "Could not unlock surface", e);
2618 mLayoutRequested = true; // ask wm for a new surface next time.
2619 //noinspection ReturnInsideFinallyBlock
2620 return false;
2621 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002622
Romain Guy25eba5c2012-04-04 17:29:03 -07002623 if (LOCAL_LOGV) {
2624 Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
2625 }
2626 }
2627 return true;
2628 }
2629
Alan Viverette997aa402014-08-19 13:34:30 -07002630 Drawable getAccessibilityFocusedDrawable() {
Chris Craikd36a81f2014-07-17 10:16:51 -07002631 // Lazily load the accessibility focus drawable.
2632 if (mAttachInfo.mAccessibilityFocusDrawable == null) {
Alan Viverettef6cf1a02014-08-11 14:13:02 -07002633 final TypedValue value = new TypedValue();
Chris Craikd36a81f2014-07-17 10:16:51 -07002634 final boolean resolved = mView.mContext.getTheme().resolveAttribute(
2635 R.attr.accessibilityFocusedDrawable, value, true);
2636 if (resolved) {
2637 mAttachInfo.mAccessibilityFocusDrawable =
Alan Viverette8eea3ea2014-02-03 18:40:20 -08002638 mView.mContext.getDrawable(value.resourceId);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002639 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002640 }
Chris Craikd36a81f2014-07-17 10:16:51 -07002641 return mAttachInfo.mAccessibilityFocusDrawable;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002642 }
2643
Michael Jurkaf42d90102013-05-08 18:00:04 +02002644 /**
2645 * @hide
2646 */
2647 public void setDrawDuringWindowsAnimating(boolean value) {
2648 mDrawDuringWindowsAnimating = value;
2649 if (value) {
2650 handleDispatchDoneAnimating();
2651 }
2652 }
2653
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002654 boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
Chris Craikd36a81f2014-07-17 10:16:51 -07002655 final Rect ci = mAttachInfo.mContentInsets;
2656 final Rect vi = mAttachInfo.mVisibleInsets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002657 int scrollY = 0;
2658 boolean handled = false;
Romain Guy8506ab42009-06-11 17:35:47 -07002659
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002660 if (vi.left > ci.left || vi.top > ci.top
2661 || vi.right > ci.right || vi.bottom > ci.bottom) {
2662 // We'll assume that we aren't going to change the scroll
2663 // offset, since we want to avoid that unless it is actually
2664 // going to make the focus visible... otherwise we scroll
2665 // all over the place.
2666 scrollY = mScrollY;
2667 // We can be called for two different situations: during a draw,
2668 // to update the scroll position if the focus has changed (in which
2669 // case 'rectangle' is null), or in response to a
2670 // requestChildRectangleOnScreen() call (in which case 'rectangle'
2671 // is non-null and we just want to scroll to whatever that
2672 // rectangle is).
Craig Mautner26a84df2013-04-11 19:09:05 -07002673 final View focus = mView.findFocus();
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002674 if (focus == null) {
Romain Guye8b16522009-07-14 13:06:42 -07002675 return false;
2676 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002677 View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null;
Craig Mautner26a84df2013-04-11 19:09:05 -07002678 if (focus != lastScrolledFocus) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002679 // If the focus has changed, then ignore any requests to scroll
2680 // to a rectangle; first we want to make sure the entire focus
2681 // view is visible.
2682 rectangle = null;
2683 }
2684 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus
2685 + " rectangle=" + rectangle + " ci=" + ci
2686 + " vi=" + vi);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002687 if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002688 // Optimization: if the focus hasn't changed since last
2689 // time, and no layout has happened, then just leave things
2690 // as they are.
2691 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y="
2692 + mScrollY + " vi=" + vi.toShortString());
Craig Mautner26a84df2013-04-11 19:09:05 -07002693 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002694 // We need to determine if the currently focused view is
2695 // within the visible part of the window and, if not, apply
2696 // a pan so it can be seen.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002697 mLastScrolledFocus = new WeakReference<View>(focus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002698 mScrollMayChange = false;
2699 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?");
2700 // Try to find the rectangle from the focus view.
2701 if (focus.getGlobalVisibleRect(mVisRect, null)) {
2702 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w="
2703 + mView.getWidth() + " h=" + mView.getHeight()
2704 + " ci=" + ci.toShortString()
2705 + " vi=" + vi.toShortString());
2706 if (rectangle == null) {
2707 focus.getFocusedRect(mTempRect);
2708 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus
2709 + ": focusRect=" + mTempRect.toShortString());
Dianne Hackborn1c6a8942010-03-23 16:34:20 -07002710 if (mView instanceof ViewGroup) {
2711 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
2712 focus, mTempRect);
2713 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002714 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2715 "Focus in window: focusRect="
2716 + mTempRect.toShortString()
2717 + " visRect=" + mVisRect.toShortString());
2718 } else {
2719 mTempRect.set(rectangle);
2720 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2721 "Request scroll to rect: "
2722 + mTempRect.toShortString()
2723 + " visRect=" + mVisRect.toShortString());
2724 }
2725 if (mTempRect.intersect(mVisRect)) {
2726 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2727 "Focus window visible rect: "
2728 + mTempRect.toShortString());
2729 if (mTempRect.height() >
2730 (mView.getHeight()-vi.top-vi.bottom)) {
2731 // If the focus simply is not going to fit, then
2732 // best is probably just to leave things as-is.
2733 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2734 "Too tall; leaving scrollY=" + scrollY);
2735 } else if ((mTempRect.top-scrollY) < vi.top) {
2736 scrollY -= vi.top - (mTempRect.top-scrollY);
2737 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2738 "Top covered; scrollY=" + scrollY);
2739 } else if ((mTempRect.bottom-scrollY)
2740 > (mView.getHeight()-vi.bottom)) {
2741 scrollY += (mTempRect.bottom-scrollY)
2742 - (mView.getHeight()-vi.bottom);
2743 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2744 "Bottom covered; scrollY=" + scrollY);
2745 }
2746 handled = true;
2747 }
2748 }
2749 }
2750 }
Romain Guy8506ab42009-06-11 17:35:47 -07002751
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002752 if (scrollY != mScrollY) {
2753 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
2754 + mScrollY + " , new=" + scrollY);
John Recke56e9df2014-02-21 15:45:10 -08002755 if (!immediate && mResizeBuffer == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002756 if (mScroller == null) {
2757 mScroller = new Scroller(mView.getContext());
2758 }
2759 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
2760 } else if (mScroller != null) {
2761 mScroller.abortAnimation();
2762 }
2763 mScrollY = scrollY;
2764 }
Romain Guy8506ab42009-06-11 17:35:47 -07002765
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002766 return handled;
2767 }
Romain Guy8506ab42009-06-11 17:35:47 -07002768
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07002769 /**
2770 * @hide
2771 */
2772 public View getAccessibilityFocusedHost() {
2773 return mAccessibilityFocusedHost;
2774 }
2775
2776 /**
2777 * @hide
2778 */
2779 public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
2780 return mAccessibilityFocusedVirtualView;
2781 }
2782
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002783 void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002784 // If we have a virtual view with accessibility focus we need
2785 // to clear the focus and invalidate the virtual view bounds.
2786 if (mAccessibilityFocusedVirtualView != null) {
2787
2788 AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
2789 View focusHost = mAccessibilityFocusedHost;
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002790
2791 // Wipe the state of the current accessibility focus since
2792 // the call into the provider to clear accessibility focus
2793 // will fire an accessibility event which will end up calling
2794 // this method and we want to have clean state when this
2795 // invocation happens.
2796 mAccessibilityFocusedHost = null;
2797 mAccessibilityFocusedVirtualView = null;
2798
Alan Viverette239a0c02013-05-07 17:17:35 -07002799 // Clear accessibility focus on the host after clearing state since
2800 // this method may be reentrant.
2801 focusHost.clearAccessibilityFocusNoCallbacks();
2802
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002803 AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
2804 if (provider != null) {
2805 // Invalidate the area of the cleared accessibility focus.
2806 focusNode.getBoundsInParent(mTempRect);
2807 focusHost.invalidate(mTempRect);
2808 // Clear accessibility focus in the virtual node.
2809 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
2810 focusNode.getSourceNodeId());
2811 provider.performAction(virtualNodeId,
2812 AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
2813 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002814 focusNode.recycle();
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002815 }
2816 if (mAccessibilityFocusedHost != null) {
2817 // Clear accessibility focus in the view.
Svetoslav Ganov42138042012-03-20 11:51:39 -07002818 mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks();
2819 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002820
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002821 // Set the new focus host and node.
2822 mAccessibilityFocusedHost = view;
2823 mAccessibilityFocusedVirtualView = node;
John Reck0a973302014-07-16 13:29:45 -07002824
2825 if (mAttachInfo.mHardwareRenderer != null) {
2826 mAttachInfo.mHardwareRenderer.invalidateRoot();
2827 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002828 }
2829
Igor Murashkina86ab6402013-08-30 12:58:36 -07002830 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002831 public void requestChildFocus(View child, View focused) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002832 if (DEBUG_INPUT_RESIZE) {
2833 Log.v(TAG, "Request child focus: focus now " + focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002834 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002835 checkThread();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002836 scheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002837 }
2838
Igor Murashkina86ab6402013-08-30 12:58:36 -07002839 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002840 public void clearChildFocus(View child) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002841 if (DEBUG_INPUT_RESIZE) {
2842 Log.v(TAG, "Clearing child focus");
Amith Yamasani73eb97f2012-02-14 15:45:15 -08002843 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002844 checkThread();
2845 scheduleTraversals();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08002846 }
Amith Yamasani73eb97f2012-02-14 15:45:15 -08002847
Svetoslav Ganov42138042012-03-20 11:51:39 -07002848 @Override
2849 public ViewParent getParentForAccessibility() {
2850 return null;
2851 }
2852
Igor Murashkina86ab6402013-08-30 12:58:36 -07002853 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002854 public void focusableViewAvailable(View v) {
2855 checkThread();
Romain Guy1c90f032011-05-24 14:59:50 -07002856 if (mView != null) {
2857 if (!mView.hasFocus()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002858 v.requestFocus();
Romain Guy1c90f032011-05-24 14:59:50 -07002859 } else {
2860 // the one case where will transfer focus away from the current one
2861 // is if the current view is a view group that prefers to give focus
2862 // to its children first AND the view is a descendant of it.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002863 View focused = mView.findFocus();
2864 if (focused instanceof ViewGroup) {
2865 ViewGroup group = (ViewGroup) focused;
2866 if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
2867 && isViewDescendantOf(v, focused)) {
2868 v.requestFocus();
2869 }
Romain Guy1c90f032011-05-24 14:59:50 -07002870 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002871 }
2872 }
2873 }
2874
Igor Murashkina86ab6402013-08-30 12:58:36 -07002875 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002876 public void recomputeViewAttributes(View child) {
2877 checkThread();
2878 if (mView == child) {
2879 mAttachInfo.mRecomputeGlobalAttributes = true;
2880 if (!mWillDrawSoon) {
2881 scheduleTraversals();
2882 }
2883 }
2884 }
2885
2886 void dispatchDetachedFromWindow() {
Romain Guy90fc03b2011-01-16 13:07:15 -08002887 if (mView != null && mView.mAttachInfo != null) {
Dianne Hackborn961cae92013-03-20 14:59:43 -07002888 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002889 mView.dispatchDetachedFromWindow();
2890 }
2891
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002892 mAccessibilityInteractionConnectionManager.ensureNoConnection();
2893 mAccessibilityManager.removeAccessibilityStateChangeListener(
2894 mAccessibilityInteractionConnectionManager);
Chris Craikcce47eb2014-07-16 15:12:15 -07002895 mAccessibilityManager.removeHighTextContrastStateChangeListener(
2896 mHighContrastTextManager);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07002897 removeSendWindowContentChangedCallback();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002898
Romain Guya998dff2012-03-23 18:58:36 -07002899 destroyHardwareRenderer();
2900
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002901 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002902
Craig Mautner8f303ad2013-06-14 11:32:22 -07002903 mView.assignParent(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002904 mView = null;
2905 mAttachInfo.mRootView = null;
2906
Dianne Hackborn0586a1b2009-09-06 21:08:27 -07002907 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002908
Jeff Browncc4f7db2011-08-30 20:34:48 -07002909 if (mInputQueueCallback != null && mInputQueue != null) {
2910 mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
Michael Wrighta44dd262013-04-10 21:12:00 -07002911 mInputQueue.dispose();
Jeff Browncc4f7db2011-08-30 20:34:48 -07002912 mInputQueueCallback = null;
2913 mInputQueue = null;
Michael Wrighta44dd262013-04-10 21:12:00 -07002914 }
2915 if (mInputEventReceiver != null) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08002916 mInputEventReceiver.dispose();
2917 mInputEventReceiver = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -07002918 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002919 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002920 mWindowSession.remove(mWindow);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002921 } catch (RemoteException e) {
2922 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07002923
Jeff Brown00fa7bd2010-07-02 15:37:36 -07002924 // Dispose the input channel after removing the window so the Window Manager
2925 // doesn't interpret the input channel being closed as an abnormal termination.
2926 if (mInputChannel != null) {
2927 mInputChannel.dispose();
2928 mInputChannel = null;
Jeff Brown349703e2010-06-22 01:27:15 -07002929 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002930
Jeff Brownd912e1f2014-04-11 18:46:22 -07002931 mDisplayManager.unregisterDisplayListener(mDisplayListener);
2932
Jeff Brownebb2d8d2012-03-23 17:14:34 -07002933 unscheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002934 }
Romain Guy8506ab42009-06-11 17:35:47 -07002935
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002936 void updateConfiguration(Configuration config, boolean force) {
2937 if (DEBUG_CONFIGURATION) Log.v(TAG,
2938 "Applying new config to window "
2939 + mWindowAttributes.getTitle()
2940 + ": " + config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002941
Craig Mautner48d0d182013-06-11 07:53:06 -07002942 CompatibilityInfo ci = mDisplayAdjustments.getCompatibilityInfo();
2943 if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002944 config = new Configuration(config);
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002945 ci.applyToConfiguration(mNoncompatDensity, config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002946 }
2947
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002948 synchronized (sConfigCallbacks) {
2949 for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
2950 sConfigCallbacks.get(i).onConfigurationChanged(config);
2951 }
2952 }
2953 if (mView != null) {
2954 // At this point the resources have been updated to
2955 // have the most recent config, whatever that is. Use
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002956 // the one in them which may be newer.
Romain Guy1c90f032011-05-24 14:59:50 -07002957 config = mView.getResources().getConfiguration();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002958 if (force || mLastConfiguration.diff(config) != 0) {
Fabrice Di Megliocf128972012-10-16 20:51:12 -07002959 final int lastLayoutDirection = mLastConfiguration.getLayoutDirection();
2960 final int currentLayoutDirection = config.getLayoutDirection();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002961 mLastConfiguration.setTo(config);
Fabrice Di Megliob003e282012-10-17 17:20:19 -07002962 if (lastLayoutDirection != currentLayoutDirection &&
2963 mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
Fabrice Di Megliocf128972012-10-16 20:51:12 -07002964 mView.setLayoutDirection(currentLayoutDirection);
2965 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002966 mView.dispatchConfigurationChanged(config);
2967 }
2968 }
2969 }
John Reck05e85842014-04-23 14:48:28 -07002970
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002971 /**
2972 * Return true if child is an ancestor of parent, (or equal to the parent).
2973 */
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07002974 public static boolean isViewDescendantOf(View child, View parent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002975 if (child == parent) {
2976 return true;
2977 }
2978
2979 final ViewParent theParent = child.getParent();
2980 return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
2981 }
2982
Romain Guycdb86672010-03-18 18:54:50 -07002983 private static void forceLayout(View view) {
2984 view.forceLayout();
2985 if (view instanceof ViewGroup) {
2986 ViewGroup group = (ViewGroup) view;
2987 final int count = group.getChildCount();
2988 for (int i = 0; i < count; i++) {
2989 forceLayout(group.getChildAt(i));
2990 }
2991 }
2992 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002993
Jeff Browna175a5b2012-02-15 19:18:31 -08002994 private final static int MSG_INVALIDATE = 1;
2995 private final static int MSG_INVALIDATE_RECT = 2;
2996 private final static int MSG_DIE = 3;
2997 private final static int MSG_RESIZED = 4;
2998 private final static int MSG_RESIZED_REPORT = 5;
2999 private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
keunyoung30f420f2013-08-02 14:23:10 -07003000 private final static int MSG_DISPATCH_INPUT_EVENT = 7;
Jeff Browna175a5b2012-02-15 19:18:31 -08003001 private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
3002 private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
Jeff Browna175a5b2012-02-15 19:18:31 -08003003 private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
3004 private final static int MSG_FINISH_INPUT_CONNECTION = 12;
3005 private final static int MSG_CHECK_FOCUS = 13;
3006 private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
3007 private final static int MSG_DISPATCH_DRAG_EVENT = 15;
3008 private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
3009 private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
3010 private final static int MSG_UPDATE_CONFIGURATION = 18;
Svetoslav Ganov42138042012-03-20 11:51:39 -07003011 private final static int MSG_PROCESS_INPUT_EVENTS = 19;
Romain Guyfbb93fa2012-12-03 18:50:35 -08003012 private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
3013 private final static int MSG_DISPATCH_DONE_ANIMATING = 22;
3014 private final static int MSG_INVALIDATE_WORLD = 23;
3015 private final static int MSG_WINDOW_MOVED = 24;
John Reck918ad522014-06-27 14:45:25 -07003016 private final static int MSG_SYNTHESIZE_INPUT_EVENT = 25;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003017
Jeff Browna175a5b2012-02-15 19:18:31 -08003018 final class ViewRootHandler extends Handler {
3019 @Override
3020 public String getMessageName(Message message) {
3021 switch (message.what) {
3022 case MSG_INVALIDATE:
3023 return "MSG_INVALIDATE";
3024 case MSG_INVALIDATE_RECT:
3025 return "MSG_INVALIDATE_RECT";
3026 case MSG_DIE:
3027 return "MSG_DIE";
3028 case MSG_RESIZED:
3029 return "MSG_RESIZED";
3030 case MSG_RESIZED_REPORT:
3031 return "MSG_RESIZED_REPORT";
3032 case MSG_WINDOW_FOCUS_CHANGED:
3033 return "MSG_WINDOW_FOCUS_CHANGED";
keunyoung30f420f2013-08-02 14:23:10 -07003034 case MSG_DISPATCH_INPUT_EVENT:
3035 return "MSG_DISPATCH_INPUT_EVENT";
Jeff Browna175a5b2012-02-15 19:18:31 -08003036 case MSG_DISPATCH_APP_VISIBILITY:
3037 return "MSG_DISPATCH_APP_VISIBILITY";
3038 case MSG_DISPATCH_GET_NEW_SURFACE:
3039 return "MSG_DISPATCH_GET_NEW_SURFACE";
Jeff Browna175a5b2012-02-15 19:18:31 -08003040 case MSG_DISPATCH_KEY_FROM_IME:
3041 return "MSG_DISPATCH_KEY_FROM_IME";
3042 case MSG_FINISH_INPUT_CONNECTION:
3043 return "MSG_FINISH_INPUT_CONNECTION";
3044 case MSG_CHECK_FOCUS:
3045 return "MSG_CHECK_FOCUS";
3046 case MSG_CLOSE_SYSTEM_DIALOGS:
3047 return "MSG_CLOSE_SYSTEM_DIALOGS";
3048 case MSG_DISPATCH_DRAG_EVENT:
3049 return "MSG_DISPATCH_DRAG_EVENT";
3050 case MSG_DISPATCH_DRAG_LOCATION_EVENT:
3051 return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
3052 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
3053 return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
3054 case MSG_UPDATE_CONFIGURATION:
3055 return "MSG_UPDATE_CONFIGURATION";
Jeff Browna175a5b2012-02-15 19:18:31 -08003056 case MSG_PROCESS_INPUT_EVENTS:
3057 return "MSG_PROCESS_INPUT_EVENTS";
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003058 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
3059 return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
Dianne Hackborn12d3a942012-04-27 14:16:30 -07003060 case MSG_DISPATCH_DONE_ANIMATING:
3061 return "MSG_DISPATCH_DONE_ANIMATING";
Craig Mautner5702d4d2012-06-30 14:10:16 -07003062 case MSG_WINDOW_MOVED:
3063 return "MSG_WINDOW_MOVED";
Michael Wright899d7052014-04-23 17:23:39 -07003064 case MSG_SYNTHESIZE_INPUT_EVENT:
3065 return "MSG_SYNTHESIZE_INPUT_EVENT";
Jeff Browna175a5b2012-02-15 19:18:31 -08003066 }
3067 return super.getMessageName(message);
Romain Guyf9284692011-07-13 18:46:21 -07003068 }
Romain Guyf9284692011-07-13 18:46:21 -07003069
Jeff Browna175a5b2012-02-15 19:18:31 -08003070 @Override
3071 public void handleMessage(Message msg) {
3072 switch (msg.what) {
3073 case MSG_INVALIDATE:
3074 ((View) msg.obj).invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003075 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003076 case MSG_INVALIDATE_RECT:
3077 final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
3078 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08003079 info.recycle();
Jeff Browna175a5b2012-02-15 19:18:31 -08003080 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003081 case MSG_PROCESS_INPUT_EVENTS:
3082 mProcessInputEventsScheduled = false;
3083 doProcessInputEvents();
3084 break;
3085 case MSG_DISPATCH_APP_VISIBILITY:
3086 handleAppVisibility(msg.arg1 != 0);
3087 break;
3088 case MSG_DISPATCH_GET_NEW_SURFACE:
3089 handleGetNewSurface();
3090 break;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003091 case MSG_RESIZED: {
3092 // Recycled in the fall through...
3093 SomeArgs args = (SomeArgs) msg.obj;
Romain Guydfab3632012-10-03 14:53:25 -07003094 if (mWinFrame.equals(args.arg1)
Dianne Hackbornc4aad012013-02-22 15:05:25 -08003095 && mPendingOverscanInsets.equals(args.arg5)
Romain Guydfab3632012-10-03 14:53:25 -07003096 && mPendingContentInsets.equals(args.arg2)
Adrian Roosfa104232014-06-20 16:10:14 -07003097 && mPendingStableInsets.equals(args.arg6)
Romain Guydfab3632012-10-03 14:53:25 -07003098 && mPendingVisibleInsets.equals(args.arg3)
3099 && args.arg4 == null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003100 break;
Romain Guycdb86672010-03-18 18:54:50 -07003101 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003102 } // fall through...
Jeff Browna175a5b2012-02-15 19:18:31 -08003103 case MSG_RESIZED_REPORT:
3104 if (mAdded) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003105 SomeArgs args = (SomeArgs) msg.obj;
3106
3107 Configuration config = (Configuration) args.arg4;
Jeff Browna175a5b2012-02-15 19:18:31 -08003108 if (config != null) {
3109 updateConfiguration(config, false);
3110 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003111
3112 mWinFrame.set((Rect) args.arg1);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08003113 mPendingOverscanInsets.set((Rect) args.arg5);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003114 mPendingContentInsets.set((Rect) args.arg2);
Adrian Roosfa104232014-06-20 16:10:14 -07003115 mPendingStableInsets.set((Rect) args.arg6);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003116 mPendingVisibleInsets.set((Rect) args.arg3);
3117
3118 args.recycle();
3119
Jeff Browna175a5b2012-02-15 19:18:31 -08003120 if (msg.what == MSG_RESIZED_REPORT) {
3121 mReportNextDraw = true;
3122 }
Romain Guy59a12ca2011-06-09 17:48:21 -07003123
Jeff Browna175a5b2012-02-15 19:18:31 -08003124 if (mView != null) {
3125 forceLayout(mView);
3126 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003127
Jeff Browna175a5b2012-02-15 19:18:31 -08003128 requestLayout();
3129 }
3130 break;
Craig Mautner5702d4d2012-06-30 14:10:16 -07003131 case MSG_WINDOW_MOVED:
3132 if (mAdded) {
3133 final int w = mWinFrame.width();
3134 final int h = mWinFrame.height();
3135 final int l = msg.arg1;
3136 final int t = msg.arg2;
3137 mWinFrame.left = l;
3138 mWinFrame.right = l + w;
3139 mWinFrame.top = t;
3140 mWinFrame.bottom = t + h;
3141
3142 if (mView != null) {
3143 forceLayout(mView);
3144 }
3145 requestLayout();
3146 }
3147 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003148 case MSG_WINDOW_FOCUS_CHANGED: {
3149 if (mAdded) {
3150 boolean hasWindowFocus = msg.arg1 != 0;
3151 mAttachInfo.mHasWindowFocus = hasWindowFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003152
Jeff Browna175a5b2012-02-15 19:18:31 -08003153 profileRendering(hasWindowFocus);
3154
3155 if (hasWindowFocus) {
3156 boolean inTouchMode = msg.arg2 != 0;
3157 ensureTouchModeLocally(inTouchMode);
3158
Romain Guye55945e2013-04-04 15:26:04 -07003159 if (mAttachInfo.mHardwareRenderer != null && mSurface.isValid()){
Jeff Browna175a5b2012-02-15 19:18:31 -08003160 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08003161 try {
Alan Viveretteccb11e12014-07-08 16:04:02 -07003162 final WindowManager.LayoutParams lp = mWindowAttributes;
Alan Viverette49a22e82014-07-12 20:01:27 -07003163 final Rect surfaceInsets = lp != null ? lp.surfaceInsets : null;
Romain Guy3696779b2013-01-28 14:04:07 -08003164 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
Alan Viverette58c42c32014-07-12 20:33:45 -07003165 mWidth, mHeight, mSurface, surfaceInsets);
Igor Murashkina86ab6402013-08-30 12:58:36 -07003166 } catch (OutOfResourcesException e) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003167 Log.e(TAG, "OutOfResourcesException locking surface", e);
3168 try {
Jeff Brown98365d72012-08-19 20:30:52 -07003169 if (!mWindowSession.outOfMemory(mWindow)) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003170 Slog.w(TAG, "No processes killed for memory; killing self");
3171 Process.killProcess(Process.myPid());
3172 }
3173 } catch (RemoteException ex) {
Dianne Hackborn64825172011-03-02 21:32:58 -08003174 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003175 // Retry in a bit.
3176 sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
3177 return;
Dianne Hackborn64825172011-03-02 21:32:58 -08003178 }
Dianne Hackborn64825172011-03-02 21:32:58 -08003179 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003180 }
Romain Guy8506ab42009-06-11 17:35:47 -07003181
Jeff Browna175a5b2012-02-15 19:18:31 -08003182 mLastWasImTarget = WindowManager.LayoutParams
3183 .mayUseInputMethod(mWindowAttributes.flags);
Romain Guy8506ab42009-06-11 17:35:47 -07003184
Jeff Browna175a5b2012-02-15 19:18:31 -08003185 InputMethodManager imm = InputMethodManager.peekInstance();
3186 if (mView != null) {
keunyoung30f420f2013-08-02 14:23:10 -07003187 if (hasWindowFocus && imm != null && mLastWasImTarget &&
3188 !isInLocalFocusMode()) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003189 imm.startGettingWindowFocus(mView);
3190 }
3191 mAttachInfo.mKeyDispatchState.reset();
3192 mView.dispatchWindowFocusChanged(hasWindowFocus);
Dianne Hackborn961cae92013-03-20 14:59:43 -07003193 mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003194 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003195
Jeff Browna175a5b2012-02-15 19:18:31 -08003196 // Note: must be done after the focus change callbacks,
3197 // so all of the view state is set up correctly.
3198 if (hasWindowFocus) {
keunyoung30f420f2013-08-02 14:23:10 -07003199 if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003200 imm.onWindowFocus(mView, mView.findFocus(),
3201 mWindowAttributes.softInputMode,
3202 !mHasHadWindowFocus, mWindowAttributes.flags);
3203 }
3204 // Clear the forward bit. We can just do this directly, since
3205 // the window manager doesn't care about it.
3206 mWindowAttributes.softInputMode &=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003207 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
Jeff Browna175a5b2012-02-15 19:18:31 -08003208 ((WindowManager.LayoutParams)mView.getLayoutParams())
3209 .softInputMode &=
3210 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
3211 mHasHadWindowFocus = true;
3212 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003213
Svetoslav Ganov42138042012-03-20 11:51:39 -07003214 if (mView != null && mAccessibilityManager.isEnabled()) {
3215 if (hasWindowFocus) {
3216 mView.sendAccessibilityEvent(
3217 AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
Svetoslav Ganov42138042012-03-20 11:51:39 -07003218 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003219 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003220 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003221 } break;
3222 case MSG_DIE:
3223 doDie();
3224 break;
keunyoung30f420f2013-08-02 14:23:10 -07003225 case MSG_DISPATCH_INPUT_EVENT: {
Jae Seo6a6059a2014-04-17 21:35:29 -07003226 SomeArgs args = (SomeArgs)msg.obj;
3227 InputEvent event = (InputEvent)args.arg1;
3228 InputEventReceiver receiver = (InputEventReceiver)args.arg2;
3229 enqueueInputEvent(event, receiver, 0, true);
3230 args.recycle();
Jeff Browna175a5b2012-02-15 19:18:31 -08003231 } break;
Michael Wright899d7052014-04-23 17:23:39 -07003232 case MSG_SYNTHESIZE_INPUT_EVENT: {
3233 InputEvent event = (InputEvent)msg.obj;
3234 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_UNHANDLED, true);
3235 } break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003236 case MSG_DISPATCH_KEY_FROM_IME: {
3237 if (LOCAL_LOGV) Log.v(
3238 TAG, "Dispatching key "
3239 + msg.obj + " from IME to " + mView);
3240 KeyEvent event = (KeyEvent)msg.obj;
3241 if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
3242 // The IME is trying to say this event is from the
3243 // system! Bad bad bad!
3244 //noinspection UnusedAssignment
Michael Wright899d7052014-04-23 17:23:39 -07003245 event = KeyEvent.changeFlags(event, event.getFlags() &
3246 ~KeyEvent.FLAG_FROM_SYSTEM);
Jeff Browna175a5b2012-02-15 19:18:31 -08003247 }
3248 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
3249 } break;
3250 case MSG_FINISH_INPUT_CONNECTION: {
3251 InputMethodManager imm = InputMethodManager.peekInstance();
3252 if (imm != null) {
3253 imm.reportFinishInputConnection((InputConnection)msg.obj);
3254 }
3255 } break;
3256 case MSG_CHECK_FOCUS: {
3257 InputMethodManager imm = InputMethodManager.peekInstance();
3258 if (imm != null) {
3259 imm.checkFocus();
3260 }
3261 } break;
3262 case MSG_CLOSE_SYSTEM_DIALOGS: {
3263 if (mView != null) {
3264 mView.onCloseSystemDialogs((String)msg.obj);
3265 }
3266 } break;
3267 case MSG_DISPATCH_DRAG_EVENT:
3268 case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
3269 DragEvent event = (DragEvent)msg.obj;
3270 event.mLocalState = mLocalDragState; // only present when this app called startDrag()
3271 handleDragEvent(event);
3272 } break;
3273 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
Romain Guyfbb93fa2012-12-03 18:50:35 -08003274 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj);
Jeff Browna175a5b2012-02-15 19:18:31 -08003275 } break;
3276 case MSG_UPDATE_CONFIGURATION: {
3277 Configuration config = (Configuration)msg.obj;
3278 if (config.isOtherSeqNewer(mLastConfiguration)) {
3279 config = mLastConfiguration;
3280 }
3281 updateConfiguration(config, false);
3282 } break;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003283 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003284 setAccessibilityFocus(null, null);
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003285 } break;
Dianne Hackborn12d3a942012-04-27 14:16:30 -07003286 case MSG_DISPATCH_DONE_ANIMATING: {
3287 handleDispatchDoneAnimating();
3288 } break;
Dianne Hackborna53de062012-05-08 18:53:51 -07003289 case MSG_INVALIDATE_WORLD: {
Romain Guyf84208f2012-09-13 22:50:18 -07003290 if (mView != null) {
3291 invalidateWorld(mView);
3292 }
Dianne Hackborna53de062012-05-08 18:53:51 -07003293 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003294 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003295 }
3296 }
Romain Guy51e4d4d2012-03-15 18:30:47 -07003297
Jeff Browna175a5b2012-02-15 19:18:31 -08003298 final ViewRootHandler mHandler = new ViewRootHandler();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003299
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003300 /**
3301 * Something in the current window tells us we need to change the touch mode. For
3302 * example, we are not in touch mode, and the user touches the screen.
3303 *
3304 * If the touch mode has changed, tell the window manager, and handle it locally.
3305 *
3306 * @param inTouchMode Whether we want to be in touch mode.
3307 * @return True if the touch mode changed and focus changed was changed as a result
3308 */
3309 boolean ensureTouchMode(boolean inTouchMode) {
3310 if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
3311 + "touch mode is " + mAttachInfo.mInTouchMode);
3312 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3313
3314 // tell the window manager
3315 try {
keunyoung30f420f2013-08-02 14:23:10 -07003316 if (!isInLocalFocusMode()) {
3317 mWindowSession.setInTouchMode(inTouchMode);
3318 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003319 } catch (RemoteException e) {
3320 throw new RuntimeException(e);
3321 }
3322
3323 // handle the change
Romain Guy2d4cff62010-04-09 15:39:00 -07003324 return ensureTouchModeLocally(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003325 }
3326
3327 /**
3328 * Ensure that the touch mode for this window is set, and if it is changing,
3329 * take the appropriate action.
3330 * @param inTouchMode Whether we want to be in touch mode.
3331 * @return True if the touch mode changed and focus changed was changed as a result
3332 */
Romain Guy2d4cff62010-04-09 15:39:00 -07003333 private boolean ensureTouchModeLocally(boolean inTouchMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003334 if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
3335 + "touch mode is " + mAttachInfo.mInTouchMode);
3336
3337 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3338
3339 mAttachInfo.mInTouchMode = inTouchMode;
3340 mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
3341
Romain Guy2d4cff62010-04-09 15:39:00 -07003342 return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003343 }
3344
3345 private boolean enterTouchMode() {
Alan Viveretteed7821a2013-07-24 15:49:23 -07003346 if (mView != null && mView.hasFocus()) {
3347 // note: not relying on mFocusedView here because this could
3348 // be when the window is first being added, and mFocused isn't
3349 // set yet.
3350 final View focused = mView.findFocus();
3351 if (focused != null && !focused.isFocusableInTouchMode()) {
3352 final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
3353 if (ancestorToTakeFocus != null) {
3354 // there is an ancestor that wants focus after its
3355 // descendants that is focusable in touch mode.. give it
3356 // focus
3357 return ancestorToTakeFocus.requestFocus();
3358 } else {
Alan Viverette973f3b42013-08-13 16:57:28 -07003359 // There's nothing to focus. Clear and propagate through the
3360 // hierarchy, but don't attempt to place new focus.
Alan Viverette223622a2013-12-17 13:29:02 -08003361 focused.clearFocusInternal(null, true, false);
Alan Viveretteed7821a2013-07-24 15:49:23 -07003362 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003363 }
3364 }
3365 }
3366 return false;
3367 }
3368
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003369 /**
3370 * Find an ancestor of focused that wants focus after its descendants and is
3371 * focusable in touch mode.
3372 * @param focused The currently focused view.
3373 * @return An appropriate view, or null if no such view exists.
3374 */
Romain Guya998dff2012-03-23 18:58:36 -07003375 private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003376 ViewParent parent = focused.getParent();
3377 while (parent instanceof ViewGroup) {
3378 final ViewGroup vgParent = (ViewGroup) parent;
3379 if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
3380 && vgParent.isFocusableInTouchMode()) {
3381 return vgParent;
3382 }
3383 if (vgParent.isRootNamespace()) {
3384 return null;
3385 } else {
3386 parent = vgParent.getParent();
3387 }
3388 }
3389 return null;
3390 }
3391
3392 private boolean leaveTouchMode() {
3393 if (mView != null) {
3394 if (mView.hasFocus()) {
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003395 View focusedView = mView.findFocus();
3396 if (!(focusedView instanceof ViewGroup)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003397 // some view has focus, let it keep it
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003398 return false;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003399 } else if (((ViewGroup) focusedView).getDescendantFocusability() !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003400 ViewGroup.FOCUS_AFTER_DESCENDANTS) {
3401 // some view group has focus, and doesn't prefer its children
3402 // over itself for focus, so let them keep it.
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003403 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003404 }
3405 }
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003406
3407 // find the best view to give focus to in this brave new non-touch-mode
3408 // world
3409 final View focused = focusSearch(null, View.FOCUS_DOWN);
3410 if (focused != null) {
3411 return focused.requestFocus(View.FOCUS_DOWN);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003412 }
3413 }
3414 return false;
3415 }
3416
Jeff Brownf9e989d2013-04-04 23:04:03 -07003417 /**
3418 * Base class for implementing a stage in the chain of responsibility
3419 * for processing input events.
3420 * <p>
3421 * Events are delivered to the stage by the {@link #deliver} method. The stage
3422 * then has the choice of finishing the event or forwarding it to the next stage.
3423 * </p>
3424 */
3425 abstract class InputStage {
3426 private final InputStage mNext;
3427
3428 protected static final int FORWARD = 0;
3429 protected static final int FINISH_HANDLED = 1;
3430 protected static final int FINISH_NOT_HANDLED = 2;
3431
3432 /**
3433 * Creates an input stage.
3434 * @param next The next stage to which events should be forwarded.
3435 */
3436 public InputStage(InputStage next) {
3437 mNext = next;
3438 }
3439
3440 /**
3441 * Delivers an event to be processed.
3442 */
3443 public final void deliver(QueuedInputEvent q) {
3444 if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
3445 forward(q);
Michael Wright17d28ca2013-10-31 17:47:45 -07003446 } else if (shouldDropInputEvent(q)) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003447 finish(q, false);
3448 } else {
3449 apply(q, onProcess(q));
3450 }
3451 }
3452
3453 /**
3454 * Marks the the input event as finished then forwards it to the next stage.
3455 */
3456 protected void finish(QueuedInputEvent q, boolean handled) {
3457 q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
3458 if (handled) {
3459 q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
3460 }
3461 forward(q);
3462 }
3463
3464 /**
3465 * Forwards the event to the next stage.
3466 */
3467 protected void forward(QueuedInputEvent q) {
3468 onDeliverToNext(q);
3469 }
3470
3471 /**
3472 * Applies a result code from {@link #onProcess} to the specified event.
3473 */
3474 protected void apply(QueuedInputEvent q, int result) {
3475 if (result == FORWARD) {
3476 forward(q);
3477 } else if (result == FINISH_HANDLED) {
3478 finish(q, true);
3479 } else if (result == FINISH_NOT_HANDLED) {
3480 finish(q, false);
3481 } else {
3482 throw new IllegalArgumentException("Invalid result: " + result);
3483 }
3484 }
3485
3486 /**
3487 * Called when an event is ready to be processed.
3488 * @return A result code indicating how the event was handled.
3489 */
3490 protected int onProcess(QueuedInputEvent q) {
3491 return FORWARD;
3492 }
3493
3494 /**
3495 * Called when an event is being delivered to the next stage.
3496 */
3497 protected void onDeliverToNext(QueuedInputEvent q) {
Michael Wright06a79252014-05-05 17:45:29 -07003498 if (DEBUG_INPUT_STAGES) {
3499 Log.v(TAG, "Done with " + getClass().getSimpleName() + ". " + q);
3500 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003501 if (mNext != null) {
3502 mNext.deliver(q);
3503 } else {
3504 finishInputEvent(q);
3505 }
3506 }
Jeff Brown5182c782013-10-15 20:31:52 -07003507
Michael Wright17d28ca2013-10-31 17:47:45 -07003508 protected boolean shouldDropInputEvent(QueuedInputEvent q) {
3509 if (mView == null || !mAdded) {
3510 Slog.w(TAG, "Dropping event due to root view being removed: " + q.mEvent);
3511 return true;
3512 } else if (!mAttachInfo.mHasWindowFocus &&
3513 !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER) &&
3514 !isTerminalInputEvent(q.mEvent)) {
3515 // If this is a focused event and the window doesn't currently have input focus,
3516 // then drop this event. This could be an event that came back from the previous
3517 // stage but the window has lost focus in the meantime.
3518 Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent);
3519 return true;
3520 }
3521 return false;
3522 }
3523
Jeff Brown5182c782013-10-15 20:31:52 -07003524 void dump(String prefix, PrintWriter writer) {
3525 if (mNext != null) {
3526 mNext.dump(prefix, writer);
3527 }
3528 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003529 }
3530
3531 /**
3532 * Base class for implementing an input pipeline stage that supports
3533 * asynchronous and out-of-order processing of input events.
3534 * <p>
3535 * In addition to what a normal input stage can do, an asynchronous
3536 * input stage may also defer an input event that has been delivered to it
3537 * and finish or forward it later.
3538 * </p>
3539 */
3540 abstract class AsyncInputStage extends InputStage {
3541 private final String mTraceCounter;
3542
3543 private QueuedInputEvent mQueueHead;
3544 private QueuedInputEvent mQueueTail;
3545 private int mQueueLength;
3546
3547 protected static final int DEFER = 3;
3548
3549 /**
3550 * Creates an asynchronous input stage.
3551 * @param next The next stage to which events should be forwarded.
3552 * @param traceCounter The name of a counter to record the size of
3553 * the queue of pending events.
3554 */
3555 public AsyncInputStage(InputStage next, String traceCounter) {
3556 super(next);
3557 mTraceCounter = traceCounter;
3558 }
3559
3560 /**
3561 * Marks the event as deferred, which is to say that it will be handled
3562 * asynchronously. The caller is responsible for calling {@link #forward}
3563 * or {@link #finish} later when it is done handling the event.
3564 */
3565 protected void defer(QueuedInputEvent q) {
3566 q.mFlags |= QueuedInputEvent.FLAG_DEFERRED;
3567 enqueue(q);
3568 }
3569
3570 @Override
3571 protected void forward(QueuedInputEvent q) {
3572 // Clear the deferred flag.
3573 q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED;
3574
3575 // Fast path if the queue is empty.
3576 QueuedInputEvent curr = mQueueHead;
3577 if (curr == null) {
3578 super.forward(q);
3579 return;
3580 }
3581
3582 // Determine whether the event must be serialized behind any others
3583 // before it can be delivered to the next stage. This is done because
3584 // deferred events might be handled out of order by the stage.
3585 final int deviceId = q.mEvent.getDeviceId();
3586 QueuedInputEvent prev = null;
3587 boolean blocked = false;
3588 while (curr != null && curr != q) {
3589 if (!blocked && deviceId == curr.mEvent.getDeviceId()) {
3590 blocked = true;
3591 }
3592 prev = curr;
3593 curr = curr.mNext;
3594 }
3595
3596 // If the event is blocked, then leave it in the queue to be delivered later.
3597 // Note that the event might not yet be in the queue if it was not previously
3598 // deferred so we will enqueue it if needed.
3599 if (blocked) {
3600 if (curr == null) {
3601 enqueue(q);
3602 }
3603 return;
3604 }
3605
3606 // The event is not blocked. Deliver it immediately.
3607 if (curr != null) {
3608 curr = curr.mNext;
3609 dequeue(q, prev);
3610 }
3611 super.forward(q);
3612
3613 // Dequeuing this event may have unblocked successors. Deliver them.
3614 while (curr != null) {
3615 if (deviceId == curr.mEvent.getDeviceId()) {
3616 if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) {
3617 break;
3618 }
3619 QueuedInputEvent next = curr.mNext;
3620 dequeue(curr, prev);
3621 super.forward(curr);
3622 curr = next;
3623 } else {
3624 prev = curr;
3625 curr = curr.mNext;
3626 }
3627 }
3628 }
3629
3630 @Override
3631 protected void apply(QueuedInputEvent q, int result) {
3632 if (result == DEFER) {
3633 defer(q);
3634 } else {
3635 super.apply(q, result);
3636 }
3637 }
3638
3639 private void enqueue(QueuedInputEvent q) {
3640 if (mQueueTail == null) {
3641 mQueueHead = q;
3642 mQueueTail = q;
3643 } else {
3644 mQueueTail.mNext = q;
3645 mQueueTail = q;
3646 }
3647
3648 mQueueLength += 1;
3649 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
3650 }
3651
3652 private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) {
3653 if (prev == null) {
3654 mQueueHead = q.mNext;
3655 } else {
3656 prev.mNext = q.mNext;
3657 }
3658 if (mQueueTail == q) {
3659 mQueueTail = prev;
3660 }
3661 q.mNext = null;
3662
3663 mQueueLength -= 1;
3664 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
3665 }
Jeff Brown5182c782013-10-15 20:31:52 -07003666
3667 @Override
3668 void dump(String prefix, PrintWriter writer) {
3669 writer.print(prefix);
3670 writer.print(getClass().getName());
3671 writer.print(": mQueueLength=");
3672 writer.println(mQueueLength);
3673
3674 super.dump(prefix, writer);
3675 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003676 }
3677
3678 /**
3679 * Delivers pre-ime input events to a native activity.
3680 * Does not support pointer events.
3681 */
Michael Wrighta44dd262013-04-10 21:12:00 -07003682 final class NativePreImeInputStage extends AsyncInputStage
3683 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003684 public NativePreImeInputStage(InputStage next, String traceCounter) {
3685 super(next, traceCounter);
3686 }
3687
3688 @Override
3689 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07003690 if (mInputQueue != null && q.mEvent instanceof KeyEvent) {
3691 mInputQueue.sendInputEvent(q.mEvent, q, true, this);
3692 return DEFER;
3693 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003694 return FORWARD;
3695 }
Michael Wrighta44dd262013-04-10 21:12:00 -07003696
3697 @Override
3698 public void onFinishedInputEvent(Object token, boolean handled) {
3699 QueuedInputEvent q = (QueuedInputEvent)token;
3700 if (handled) {
3701 finish(q, true);
3702 return;
3703 }
3704 forward(q);
3705 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003706 }
3707
3708 /**
3709 * Delivers pre-ime input events to the view hierarchy.
3710 * Does not support pointer events.
3711 */
3712 final class ViewPreImeInputStage extends InputStage {
3713 public ViewPreImeInputStage(InputStage next) {
3714 super(next);
3715 }
3716
3717 @Override
3718 protected int onProcess(QueuedInputEvent q) {
Jeff Brown481c1572012-03-09 14:41:15 -08003719 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003720 return processKeyEvent(q);
3721 }
3722 return FORWARD;
3723 }
3724
3725 private int processKeyEvent(QueuedInputEvent q) {
3726 final KeyEvent event = (KeyEvent)q.mEvent;
3727 if (mView.dispatchKeyEventPreIme(event)) {
3728 return FINISH_HANDLED;
3729 }
3730 return FORWARD;
3731 }
3732 }
3733
3734 /**
3735 * Delivers input events to the ime.
3736 * Does not support pointer events.
3737 */
3738 final class ImeInputStage extends AsyncInputStage
3739 implements InputMethodManager.FinishedInputEventCallback {
3740 public ImeInputStage(InputStage next, String traceCounter) {
3741 super(next, traceCounter);
3742 }
3743
3744 @Override
3745 protected int onProcess(QueuedInputEvent q) {
keunyoung30f420f2013-08-02 14:23:10 -07003746 if (mLastWasImTarget && !isInLocalFocusMode()) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003747 InputMethodManager imm = InputMethodManager.peekInstance();
3748 if (imm != null) {
3749 final InputEvent event = q.mEvent;
3750 if (DEBUG_IMF) Log.v(TAG, "Sending input event to IME: " + event);
3751 int result = imm.dispatchInputEvent(event, q, this, mHandler);
3752 if (result == InputMethodManager.DISPATCH_HANDLED) {
3753 return FINISH_HANDLED;
3754 } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
Adam Lesinskic0f6eed2013-10-28 16:03:19 -07003755 // The IME could not handle it, so skip along to the next InputStage
3756 return FORWARD;
Jeff Brownf9e989d2013-04-04 23:04:03 -07003757 } else {
3758 return DEFER; // callback will be invoked later
3759 }
3760 }
3761 }
3762 return FORWARD;
3763 }
3764
3765 @Override
3766 public void onFinishedInputEvent(Object token, boolean handled) {
3767 QueuedInputEvent q = (QueuedInputEvent)token;
3768 if (handled) {
3769 finish(q, true);
3770 return;
3771 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003772 forward(q);
3773 }
3774 }
3775
3776 /**
3777 * Performs early processing of post-ime input events.
3778 */
3779 final class EarlyPostImeInputStage extends InputStage {
3780 public EarlyPostImeInputStage(InputStage next) {
3781 super(next);
3782 }
3783
3784 @Override
3785 protected int onProcess(QueuedInputEvent q) {
3786 if (q.mEvent instanceof KeyEvent) {
3787 return processKeyEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08003788 } else {
Jeff Brown481c1572012-03-09 14:41:15 -08003789 final int source = q.mEvent.getSource();
3790 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003791 return processPointerEvent(q);
Jeff Brown481c1572012-03-09 14:41:15 -08003792 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08003793 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003794 return FORWARD;
3795 }
3796
3797 private int processKeyEvent(QueuedInputEvent q) {
3798 final KeyEvent event = (KeyEvent)q.mEvent;
3799
3800 // If the key's purpose is to exit touch mode then we consume it
3801 // and consider it handled.
3802 if (checkForLeavingTouchModeAndConsume(event)) {
3803 return FINISH_HANDLED;
3804 }
3805
3806 // Make sure the fallback event policy sees all keys that will be
3807 // delivered to the view hierarchy.
3808 mFallbackEventHandler.preDispatchKeyEvent(event);
3809 return FORWARD;
3810 }
3811
3812 private int processPointerEvent(QueuedInputEvent q) {
3813 final MotionEvent event = (MotionEvent)q.mEvent;
3814
3815 // Translate the pointer event for compatibility, if needed.
3816 if (mTranslator != null) {
3817 mTranslator.translateEventInScreenToAppWindow(event);
3818 }
3819
3820 // Enter touch mode on down or scroll.
3821 final int action = event.getAction();
3822 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
3823 ensureTouchMode(true);
3824 }
3825
3826 // Offset the scroll position.
3827 if (mCurScrollY != 0) {
3828 event.offsetLocation(0, mCurScrollY);
3829 }
3830
3831 // Remember the touch position for possible drag-initiation.
3832 if (event.isTouchEvent()) {
3833 mLastTouchPoint.x = event.getRawX();
3834 mLastTouchPoint.y = event.getRawY();
3835 }
3836 return FORWARD;
Jeff Brown4952dfd2011-11-30 19:23:22 -08003837 }
3838 }
3839
Jeff Brownf9e989d2013-04-04 23:04:03 -07003840 /**
3841 * Delivers post-ime input events to a native activity.
3842 */
Michael Wrighta44dd262013-04-10 21:12:00 -07003843 final class NativePostImeInputStage extends AsyncInputStage
3844 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003845 public NativePostImeInputStage(InputStage next, String traceCounter) {
3846 super(next, traceCounter);
3847 }
3848
3849 @Override
3850 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07003851 if (mInputQueue != null) {
3852 mInputQueue.sendInputEvent(q.mEvent, q, false, this);
3853 return DEFER;
3854 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003855 return FORWARD;
3856 }
Michael Wrighta44dd262013-04-10 21:12:00 -07003857
3858 @Override
3859 public void onFinishedInputEvent(Object token, boolean handled) {
3860 QueuedInputEvent q = (QueuedInputEvent)token;
3861 if (handled) {
3862 finish(q, true);
3863 return;
3864 }
3865 forward(q);
3866 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003867 }
3868
3869 /**
3870 * Delivers post-ime input events to the view hierarchy.
3871 */
3872 final class ViewPostImeInputStage extends InputStage {
3873 public ViewPostImeInputStage(InputStage next) {
3874 super(next);
3875 }
3876
3877 @Override
3878 protected int onProcess(QueuedInputEvent q) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08003879 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003880 return processKeyEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08003881 } else {
Dianne Hackborn021d2432013-10-13 15:20:09 -07003882 // If delivering a new non-key event, make sure the window is
3883 // now allowed to start updating.
3884 handleDispatchDoneAnimating();
Jeff Brown29c0ed22013-01-14 13:50:37 -08003885 final int source = q.mEvent.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07003886 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
3887 return processPointerEvent(q);
3888 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
3889 return processTrackballEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08003890 } else {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003891 return processGenericMotionEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08003892 }
3893 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08003894 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08003895
Michael Wright9d744c72014-02-18 21:27:42 -08003896 @Override
3897 protected void onDeliverToNext(QueuedInputEvent q) {
3898 if (mUnbufferedInputDispatch
3899 && q.mEvent instanceof MotionEvent
3900 && ((MotionEvent)q.mEvent).isTouchEvent()
3901 && isTerminalInputEvent(q.mEvent)) {
3902 mUnbufferedInputDispatch = false;
3903 scheduleConsumeBatchedInput();
3904 }
3905 super.onDeliverToNext(q);
3906 }
3907
Jeff Brownf9e989d2013-04-04 23:04:03 -07003908 private int processKeyEvent(QueuedInputEvent q) {
3909 final KeyEvent event = (KeyEvent)q.mEvent;
3910
Dianne Hackborn021d2432013-10-13 15:20:09 -07003911 if (event.getAction() != KeyEvent.ACTION_UP) {
3912 // If delivering a new key event, make sure the window is
3913 // now allowed to start updating.
3914 handleDispatchDoneAnimating();
3915 }
3916
Jeff Brownf9e989d2013-04-04 23:04:03 -07003917 // Deliver the key to the view hierarchy.
3918 if (mView.dispatchKeyEvent(event)) {
3919 return FINISH_HANDLED;
Jeff Brown21bc5c92011-02-28 18:27:14 -08003920 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003921
Michael Wright17d28ca2013-10-31 17:47:45 -07003922 if (shouldDropInputEvent(q)) {
3923 return FINISH_NOT_HANDLED;
3924 }
3925
Jeff Brownf9e989d2013-04-04 23:04:03 -07003926 // If the Control modifier is held, try to interpret the key as a shortcut.
3927 if (event.getAction() == KeyEvent.ACTION_DOWN
3928 && event.isCtrlPressed()
3929 && event.getRepeatCount() == 0
3930 && !KeyEvent.isModifierKey(event.getKeyCode())) {
3931 if (mView.dispatchKeyShortcutEvent(event)) {
3932 return FINISH_HANDLED;
3933 }
Michael Wright17d28ca2013-10-31 17:47:45 -07003934 if (shouldDropInputEvent(q)) {
3935 return FINISH_NOT_HANDLED;
3936 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003937 }
3938
3939 // Apply the fallback event policy.
3940 if (mFallbackEventHandler.dispatchKeyEvent(event)) {
3941 return FINISH_HANDLED;
3942 }
Michael Wright17d28ca2013-10-31 17:47:45 -07003943 if (shouldDropInputEvent(q)) {
3944 return FINISH_NOT_HANDLED;
3945 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003946
3947 // Handle automatic focus changes.
3948 if (event.getAction() == KeyEvent.ACTION_DOWN) {
3949 int direction = 0;
3950 switch (event.getKeyCode()) {
3951 case KeyEvent.KEYCODE_DPAD_LEFT:
3952 if (event.hasNoModifiers()) {
3953 direction = View.FOCUS_LEFT;
3954 }
3955 break;
3956 case KeyEvent.KEYCODE_DPAD_RIGHT:
3957 if (event.hasNoModifiers()) {
3958 direction = View.FOCUS_RIGHT;
3959 }
3960 break;
3961 case KeyEvent.KEYCODE_DPAD_UP:
3962 if (event.hasNoModifiers()) {
3963 direction = View.FOCUS_UP;
3964 }
3965 break;
3966 case KeyEvent.KEYCODE_DPAD_DOWN:
3967 if (event.hasNoModifiers()) {
3968 direction = View.FOCUS_DOWN;
3969 }
3970 break;
3971 case KeyEvent.KEYCODE_TAB:
3972 if (event.hasNoModifiers()) {
3973 direction = View.FOCUS_FORWARD;
3974 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
3975 direction = View.FOCUS_BACKWARD;
3976 }
3977 break;
3978 }
3979 if (direction != 0) {
3980 View focused = mView.findFocus();
3981 if (focused != null) {
3982 View v = focused.focusSearch(direction);
3983 if (v != null && v != focused) {
3984 // do the math the get the interesting rect
3985 // of previous focused into the coord system of
3986 // newly focused view
3987 focused.getFocusedRect(mTempRect);
3988 if (mView instanceof ViewGroup) {
3989 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
3990 focused, mTempRect);
3991 ((ViewGroup) mView).offsetRectIntoDescendantCoords(
3992 v, mTempRect);
3993 }
3994 if (v.requestFocus(direction, mTempRect)) {
3995 playSoundEffect(SoundEffectConstants
3996 .getContantForFocusDirection(direction));
3997 return FINISH_HANDLED;
3998 }
3999 }
4000
4001 // Give the focused view a last chance to handle the dpad key.
4002 if (mView.dispatchUnhandledMove(focused, direction)) {
4003 return FINISH_HANDLED;
4004 }
4005 } else {
4006 // find the best view to give focus to in this non-touch-mode with no-focus
4007 View v = focusSearch(null, direction);
4008 if (v != null && v.requestFocus(direction)) {
4009 return FINISH_HANDLED;
4010 }
4011 }
4012 }
4013 }
4014 return FORWARD;
Jeff Brown21bc5c92011-02-28 18:27:14 -08004015 }
4016
Jeff Brownf9e989d2013-04-04 23:04:03 -07004017 private int processPointerEvent(QueuedInputEvent q) {
4018 final MotionEvent event = (MotionEvent)q.mEvent;
4019
Michael Wright9d744c72014-02-18 21:27:42 -08004020 mAttachInfo.mUnbufferedDispatchRequested = false;
4021 boolean handled = mView.dispatchPointerEvent(event);
4022 if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
4023 mUnbufferedInputDispatch = true;
4024 if (mConsumeBatchedInputScheduled) {
4025 scheduleConsumeBatchedInputImmediately();
4026 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004027 }
Michael Wright9d744c72014-02-18 21:27:42 -08004028 return handled ? FINISH_HANDLED : FORWARD;
Jeff Brown3915bb82010-11-05 15:02:16 -07004029 }
4030
Jeff Brownf9e989d2013-04-04 23:04:03 -07004031 private int processTrackballEvent(QueuedInputEvent q) {
4032 final MotionEvent event = (MotionEvent)q.mEvent;
4033
4034 if (mView.dispatchTrackballEvent(event)) {
4035 return FINISH_HANDLED;
4036 }
4037 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004038 }
4039
Jeff Brownf9e989d2013-04-04 23:04:03 -07004040 private int processGenericMotionEvent(QueuedInputEvent q) {
4041 final MotionEvent event = (MotionEvent)q.mEvent;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07004042
Jeff Brownf9e989d2013-04-04 23:04:03 -07004043 // Deliver the event to the view.
4044 if (mView.dispatchGenericMotionEvent(event)) {
4045 return FINISH_HANDLED;
4046 }
4047 return FORWARD;
Jeff Brown3915bb82010-11-05 15:02:16 -07004048 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07004049 }
4050
Jeff Brownf9e989d2013-04-04 23:04:03 -07004051 /**
Jeff Brown678a1252013-04-09 17:46:25 -07004052 * Performs synthesis of new input events from unhandled input events.
Jeff Brownf9e989d2013-04-04 23:04:03 -07004053 */
4054 final class SyntheticInputStage extends InputStage {
Jeff Brown678a1252013-04-09 17:46:25 -07004055 private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler();
4056 private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
4057 private final SyntheticTouchNavigationHandler mTouchNavigation =
4058 new SyntheticTouchNavigationHandler();
Michael Wright899d7052014-04-23 17:23:39 -07004059 private final SyntheticKeyboardHandler mKeyboard = new SyntheticKeyboardHandler();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004060
4061 public SyntheticInputStage() {
4062 super(null);
Jeff Brown21bc5c92011-02-28 18:27:14 -08004063 }
4064
Jeff Brownf9e989d2013-04-04 23:04:03 -07004065 @Override
4066 protected int onProcess(QueuedInputEvent q) {
4067 q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED;
4068 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07004069 final MotionEvent event = (MotionEvent)q.mEvent;
4070 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004071 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004072 mTrackball.process(event);
4073 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004074 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004075 mJoystick.process(event);
4076 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004077 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
4078 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07004079 mTouchNavigation.process(event);
4080 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004081 }
Michael Wright899d7052014-04-23 17:23:39 -07004082 } else if ((q.mFlags & QueuedInputEvent.FLAG_UNHANDLED) != 0) {
4083 mKeyboard.process((KeyEvent)q.mEvent);
4084 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004085 }
Michael Wright899d7052014-04-23 17:23:39 -07004086
Jeff Brownf9e989d2013-04-04 23:04:03 -07004087 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004088 }
4089
Jeff Brownf9e989d2013-04-04 23:04:03 -07004090 @Override
4091 protected void onDeliverToNext(QueuedInputEvent q) {
4092 if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) {
4093 // Cancel related synthetic events if any prior stage has handled the event.
4094 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07004095 final MotionEvent event = (MotionEvent)q.mEvent;
4096 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004097 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004098 mTrackball.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004099 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004100 mJoystick.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004101 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
4102 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07004103 mTouchNavigation.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004104 }
4105 }
4106 }
4107 super.onDeliverToNext(q);
4108 }
Jeff Brown678a1252013-04-09 17:46:25 -07004109 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004110
Jeff Brown678a1252013-04-09 17:46:25 -07004111 /**
4112 * Creates dpad events from unhandled trackball movements.
4113 */
4114 final class SyntheticTrackballHandler {
4115 private final TrackballAxis mX = new TrackballAxis();
4116 private final TrackballAxis mY = new TrackballAxis();
4117 private long mLastTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004118
Jeff Brown678a1252013-04-09 17:46:25 -07004119 public void process(MotionEvent event) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004120 // Translate the trackball event into DPAD keys and try to deliver those.
Jeff Brownf9e989d2013-04-04 23:04:03 -07004121 long curTime = SystemClock.uptimeMillis();
Jeff Brown678a1252013-04-09 17:46:25 -07004122 if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004123 // It has been too long since the last movement,
4124 // so restart at the beginning.
Jeff Brown678a1252013-04-09 17:46:25 -07004125 mX.reset(0);
4126 mY.reset(0);
4127 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004128 }
4129
4130 final int action = event.getAction();
4131 final int metaState = event.getMetaState();
4132 switch (action) {
4133 case MotionEvent.ACTION_DOWN:
Jeff Brown678a1252013-04-09 17:46:25 -07004134 mX.reset(2);
4135 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004136 enqueueInputEvent(new KeyEvent(curTime, curTime,
4137 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
4138 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4139 InputDevice.SOURCE_KEYBOARD));
4140 break;
4141 case MotionEvent.ACTION_UP:
Jeff Brown678a1252013-04-09 17:46:25 -07004142 mX.reset(2);
4143 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004144 enqueueInputEvent(new KeyEvent(curTime, curTime,
4145 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
4146 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4147 InputDevice.SOURCE_KEYBOARD));
4148 break;
4149 }
4150
Jeff Brown678a1252013-04-09 17:46:25 -07004151 if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + mX.position + " step="
4152 + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07004153 + " move=" + event.getX()
Jeff Brown678a1252013-04-09 17:46:25 -07004154 + " / Y=" + mY.position + " step="
4155 + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07004156 + " move=" + event.getY());
Jeff Brown678a1252013-04-09 17:46:25 -07004157 final float xOff = mX.collect(event.getX(), event.getEventTime(), "X");
4158 final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y");
Jeff Brownf9e989d2013-04-04 23:04:03 -07004159
4160 // Generate DPAD events based on the trackball movement.
4161 // We pick the axis that has moved the most as the direction of
4162 // the DPAD. When we generate DPAD events for one axis, then the
4163 // other axis is reset -- we don't want to perform DPAD jumps due
4164 // to slight movements in the trackball when making major movements
4165 // along the other axis.
4166 int keycode = 0;
4167 int movement = 0;
4168 float accel = 1;
4169 if (xOff > yOff) {
Jeff Brown678a1252013-04-09 17:46:25 -07004170 movement = mX.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004171 if (movement != 0) {
4172 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
4173 : KeyEvent.KEYCODE_DPAD_LEFT;
Jeff Brown678a1252013-04-09 17:46:25 -07004174 accel = mX.acceleration;
4175 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004176 }
4177 } else if (yOff > 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004178 movement = mY.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004179 if (movement != 0) {
4180 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
4181 : KeyEvent.KEYCODE_DPAD_UP;
Jeff Brown678a1252013-04-09 17:46:25 -07004182 accel = mY.acceleration;
4183 mX.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004184 }
4185 }
4186
4187 if (keycode != 0) {
4188 if (movement < 0) movement = -movement;
4189 int accelMovement = (int)(movement * accel);
4190 if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
4191 + " accelMovement=" + accelMovement
4192 + " accel=" + accel);
4193 if (accelMovement > movement) {
4194 if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
4195 + keycode);
4196 movement--;
4197 int repeatCount = accelMovement - movement;
4198 enqueueInputEvent(new KeyEvent(curTime, curTime,
4199 KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
4200 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4201 InputDevice.SOURCE_KEYBOARD));
4202 }
4203 while (movement > 0) {
4204 if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
4205 + keycode);
4206 movement--;
4207 curTime = SystemClock.uptimeMillis();
4208 enqueueInputEvent(new KeyEvent(curTime, curTime,
4209 KeyEvent.ACTION_DOWN, keycode, 0, metaState,
4210 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4211 InputDevice.SOURCE_KEYBOARD));
4212 enqueueInputEvent(new KeyEvent(curTime, curTime,
4213 KeyEvent.ACTION_UP, keycode, 0, metaState,
4214 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4215 InputDevice.SOURCE_KEYBOARD));
4216 }
Jeff Brown678a1252013-04-09 17:46:25 -07004217 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004218 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004219 }
4220
Jeff Brown678a1252013-04-09 17:46:25 -07004221 public void cancel(MotionEvent event) {
4222 mLastTime = Integer.MIN_VALUE;
Jeff Brown3915bb82010-11-05 15:02:16 -07004223
Jeff Brownf9e989d2013-04-04 23:04:03 -07004224 // If we reach this, we consumed a trackball event.
4225 // Because we will not translate the trackball event into a key event,
4226 // touch mode will not exit, so we exit touch mode here.
4227 if (mView != null && mAdded) {
4228 ensureTouchMode(false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07004229 }
4230 }
Jeff Brown678a1252013-04-09 17:46:25 -07004231 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004232
Jeff Brown678a1252013-04-09 17:46:25 -07004233 /**
4234 * Maintains state information for a single trackball axis, generating
4235 * discrete (DPAD) movements based on raw trackball motion.
4236 */
4237 static final class TrackballAxis {
4238 /**
4239 * The maximum amount of acceleration we will apply.
4240 */
4241 static final float MAX_ACCELERATION = 20;
4242
4243 /**
4244 * The maximum amount of time (in milliseconds) between events in order
4245 * for us to consider the user to be doing fast trackball movements,
4246 * and thus apply an acceleration.
4247 */
4248 static final long FAST_MOVE_TIME = 150;
4249
4250 /**
4251 * Scaling factor to the time (in milliseconds) between events to how
4252 * much to multiple/divide the current acceleration. When movement
4253 * is < FAST_MOVE_TIME this multiplies the acceleration; when >
4254 * FAST_MOVE_TIME it divides it.
4255 */
4256 static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
4257
4258 static final float FIRST_MOVEMENT_THRESHOLD = 0.5f;
4259 static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f;
4260 static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f;
4261
4262 float position;
4263 float acceleration = 1;
4264 long lastMoveTime = 0;
4265 int step;
4266 int dir;
4267 int nonAccelMovement;
4268
4269 void reset(int _step) {
4270 position = 0;
4271 acceleration = 1;
4272 lastMoveTime = 0;
4273 step = _step;
4274 dir = 0;
Jeff Brown6f2fba42011-02-19 01:08:02 -08004275 }
4276
Jeff Brown678a1252013-04-09 17:46:25 -07004277 /**
4278 * Add trackball movement into the state. If the direction of movement
4279 * has been reversed, the state is reset before adding the
4280 * movement (so that you don't have to compensate for any previously
4281 * collected movement before see the result of the movement in the
4282 * new direction).
4283 *
4284 * @return Returns the absolute value of the amount of movement
4285 * collected so far.
4286 */
4287 float collect(float off, long time, String axis) {
4288 long normTime;
4289 if (off > 0) {
4290 normTime = (long)(off * FAST_MOVE_TIME);
4291 if (dir < 0) {
4292 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
4293 position = 0;
4294 step = 0;
4295 acceleration = 1;
4296 lastMoveTime = 0;
4297 }
4298 dir = 1;
4299 } else if (off < 0) {
4300 normTime = (long)((-off) * FAST_MOVE_TIME);
4301 if (dir > 0) {
4302 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
4303 position = 0;
4304 step = 0;
4305 acceleration = 1;
4306 lastMoveTime = 0;
4307 }
4308 dir = -1;
4309 } else {
4310 normTime = 0;
4311 }
4312
4313 // The number of milliseconds between each movement that is
4314 // considered "normal" and will not result in any acceleration
4315 // or deceleration, scaled by the offset we have here.
4316 if (normTime > 0) {
4317 long delta = time - lastMoveTime;
4318 lastMoveTime = time;
4319 float acc = acceleration;
4320 if (delta < normTime) {
4321 // The user is scrolling rapidly, so increase acceleration.
4322 float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
4323 if (scale > 1) acc *= scale;
4324 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
4325 + off + " normTime=" + normTime + " delta=" + delta
4326 + " scale=" + scale + " acc=" + acc);
4327 acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
4328 } else {
4329 // The user is scrolling slowly, so decrease acceleration.
4330 float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
4331 if (scale > 1) acc /= scale;
4332 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
4333 + off + " normTime=" + normTime + " delta=" + delta
4334 + " scale=" + scale + " acc=" + acc);
4335 acceleration = acc > 1 ? acc : 1;
4336 }
4337 }
4338 position += off;
4339 return Math.abs(position);
Jeff Brown6f2fba42011-02-19 01:08:02 -08004340 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004341
Jeff Brown678a1252013-04-09 17:46:25 -07004342 /**
4343 * Generate the number of discrete movement events appropriate for
4344 * the currently collected trackball movement.
4345 *
4346 * @return Returns the number of discrete movements, either positive
4347 * or negative, or 0 if there is not enough trackball movement yet
4348 * for a discrete movement.
4349 */
4350 int generate() {
4351 int movement = 0;
4352 nonAccelMovement = 0;
4353 do {
4354 final int dir = position >= 0 ? 1 : -1;
4355 switch (step) {
4356 // If we are going to execute the first step, then we want
4357 // to do this as soon as possible instead of waiting for
4358 // a full movement, in order to make things look responsive.
4359 case 0:
4360 if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) {
4361 return movement;
4362 }
4363 movement += dir;
4364 nonAccelMovement += dir;
4365 step = 1;
4366 break;
4367 // If we have generated the first movement, then we need
4368 // to wait for the second complete trackball motion before
4369 // generating the second discrete movement.
4370 case 1:
4371 if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) {
4372 return movement;
4373 }
4374 movement += dir;
4375 nonAccelMovement += dir;
4376 position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir;
4377 step = 2;
4378 break;
4379 // After the first two, we generate discrete movements
4380 // consistently with the trackball, applying an acceleration
4381 // if the trackball is moving quickly. This is a simple
4382 // acceleration on top of what we already compute based
4383 // on how quickly the wheel is being turned, to apply
4384 // a longer increasing acceleration to continuous movement
4385 // in one direction.
4386 default:
4387 if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) {
4388 return movement;
4389 }
4390 movement += dir;
4391 position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD;
4392 float acc = acceleration;
4393 acc *= 1.1f;
4394 acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
4395 break;
4396 }
4397 } while (true);
4398 }
4399 }
4400
4401 /**
4402 * Creates dpad events from unhandled joystick movements.
4403 */
4404 final class SyntheticJoystickHandler extends Handler {
Michael Wright9adca062014-03-19 11:51:26 -07004405 private final static String TAG = "SyntheticJoystickHandler";
Jeff Brown678a1252013-04-09 17:46:25 -07004406 private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
4407 private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
4408
4409 private int mLastXDirection;
4410 private int mLastYDirection;
4411 private int mLastXKeyCode;
4412 private int mLastYKeyCode;
4413
4414 public SyntheticJoystickHandler() {
4415 super(true);
4416 }
4417
4418 @Override
4419 public void handleMessage(Message msg) {
4420 switch (msg.what) {
4421 case MSG_ENQUEUE_X_AXIS_KEY_REPEAT:
4422 case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: {
4423 KeyEvent oldEvent = (KeyEvent)msg.obj;
4424 KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent,
4425 SystemClock.uptimeMillis(),
4426 oldEvent.getRepeatCount() + 1);
4427 if (mAttachInfo.mHasWindowFocus) {
4428 enqueueInputEvent(e);
4429 Message m = obtainMessage(msg.what, e);
4430 m.setAsynchronous(true);
4431 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay());
4432 }
4433 } break;
4434 }
4435 }
4436
4437 public void process(MotionEvent event) {
Michael Wright9adca062014-03-19 11:51:26 -07004438 switch(event.getActionMasked()) {
4439 case MotionEvent.ACTION_CANCEL:
4440 cancel(event);
4441 break;
4442 case MotionEvent.ACTION_MOVE:
4443 update(event, true);
4444 break;
4445 default:
4446 Log.w(TAG, "Unexpected action: " + event.getActionMasked());
4447 }
Jeff Brown678a1252013-04-09 17:46:25 -07004448 }
4449
Michael Wright9adca062014-03-19 11:51:26 -07004450 private void cancel(MotionEvent event) {
4451 removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
4452 removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
Jeff Brown678a1252013-04-09 17:46:25 -07004453 update(event, false);
4454 }
4455
4456 private void update(MotionEvent event, boolean synthesizeNewKeys) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004457 final long time = event.getEventTime();
4458 final int metaState = event.getMetaState();
4459 final int deviceId = event.getDeviceId();
4460 final int source = event.getSource();
4461
4462 int xDirection = joystickAxisValueToDirection(
4463 event.getAxisValue(MotionEvent.AXIS_HAT_X));
4464 if (xDirection == 0) {
4465 xDirection = joystickAxisValueToDirection(event.getX());
Jeff Browncb1404e2011-01-15 18:14:15 -08004466 }
4467
Jeff Brownf9e989d2013-04-04 23:04:03 -07004468 int yDirection = joystickAxisValueToDirection(
4469 event.getAxisValue(MotionEvent.AXIS_HAT_Y));
4470 if (yDirection == 0) {
4471 yDirection = joystickAxisValueToDirection(event.getY());
4472 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004473
Jeff Brown678a1252013-04-09 17:46:25 -07004474 if (xDirection != mLastXDirection) {
4475 if (mLastXKeyCode != 0) {
4476 removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004477 enqueueInputEvent(new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004478 KeyEvent.ACTION_UP, mLastXKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004479 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Brown678a1252013-04-09 17:46:25 -07004480 mLastXKeyCode = 0;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004481 }
4482
Jeff Brown678a1252013-04-09 17:46:25 -07004483 mLastXDirection = xDirection;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004484
4485 if (xDirection != 0 && synthesizeNewKeys) {
Jeff Brown678a1252013-04-09 17:46:25 -07004486 mLastXKeyCode = xDirection > 0
Jeff Brownf9e989d2013-04-04 23:04:03 -07004487 ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
4488 final KeyEvent e = new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004489 KeyEvent.ACTION_DOWN, mLastXKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004490 deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
4491 enqueueInputEvent(e);
Jeff Brown678a1252013-04-09 17:46:25 -07004492 Message m = obtainMessage(MSG_ENQUEUE_X_AXIS_KEY_REPEAT, e);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004493 m.setAsynchronous(true);
Michael Wrightb9618522013-04-10 15:20:56 -07004494 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
Jeff Brownf9e989d2013-04-04 23:04:03 -07004495 }
4496 }
4497
Jeff Brown678a1252013-04-09 17:46:25 -07004498 if (yDirection != mLastYDirection) {
4499 if (mLastYKeyCode != 0) {
4500 removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004501 enqueueInputEvent(new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004502 KeyEvent.ACTION_UP, mLastYKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004503 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Brown678a1252013-04-09 17:46:25 -07004504 mLastYKeyCode = 0;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004505 }
4506
Jeff Brown678a1252013-04-09 17:46:25 -07004507 mLastYDirection = yDirection;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004508
4509 if (yDirection != 0 && synthesizeNewKeys) {
Jeff Brown678a1252013-04-09 17:46:25 -07004510 mLastYKeyCode = yDirection > 0
Jeff Brownf9e989d2013-04-04 23:04:03 -07004511 ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
4512 final KeyEvent e = new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004513 KeyEvent.ACTION_DOWN, mLastYKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004514 deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
4515 enqueueInputEvent(e);
Jeff Brown678a1252013-04-09 17:46:25 -07004516 Message m = obtainMessage(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT, e);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004517 m.setAsynchronous(true);
Jeff Brown678a1252013-04-09 17:46:25 -07004518 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
Jeff Brownf9e989d2013-04-04 23:04:03 -07004519 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004520 }
4521 }
4522
Jeff Brownf9e989d2013-04-04 23:04:03 -07004523 private int joystickAxisValueToDirection(float value) {
4524 if (value >= 0.5f) {
4525 return 1;
4526 } else if (value <= -0.5f) {
4527 return -1;
4528 } else {
4529 return 0;
Jeff Browncb1404e2011-01-15 18:14:15 -08004530 }
4531 }
Jeff Brown678a1252013-04-09 17:46:25 -07004532 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004533
Jeff Brown678a1252013-04-09 17:46:25 -07004534 /**
4535 * Creates dpad events from unhandled touch navigation movements.
4536 */
4537 final class SyntheticTouchNavigationHandler extends Handler {
Jeff Brown4dac9012013-04-10 01:03:19 -07004538 private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler";
4539 private static final boolean LOCAL_DEBUG = false;
Jeff Brown678a1252013-04-09 17:46:25 -07004540
Jeff Brown4dac9012013-04-10 01:03:19 -07004541 // Assumed nominal width and height in millimeters of a touch navigation pad,
4542 // if no resolution information is available from the input system.
4543 private static final float DEFAULT_WIDTH_MILLIMETERS = 48;
4544 private static final float DEFAULT_HEIGHT_MILLIMETERS = 48;
Jeff Brown678a1252013-04-09 17:46:25 -07004545
Jeff Brown4dac9012013-04-10 01:03:19 -07004546 /* TODO: These constants should eventually be moved to ViewConfiguration. */
Jeff Brown678a1252013-04-09 17:46:25 -07004547
Jeff Brown4dac9012013-04-10 01:03:19 -07004548 // The nominal distance traveled to move by one unit.
4549 private static final int TICK_DISTANCE_MILLIMETERS = 12;
4550
4551 // Minimum and maximum fling velocity in ticks per second.
4552 // The minimum velocity should be set such that we perform enough ticks per
4553 // second that the fling appears to be fluid. For example, if we set the minimum
4554 // to 2 ticks per second, then there may be up to half a second delay between the next
4555 // to last and last ticks which is noticeably discrete and jerky. This value should
4556 // probably not be set to anything less than about 4.
4557 // If fling accuracy is a problem then consider tuning the tick distance instead.
4558 private static final float MIN_FLING_VELOCITY_TICKS_PER_SECOND = 6f;
4559 private static final float MAX_FLING_VELOCITY_TICKS_PER_SECOND = 20f;
4560
4561 // Fling velocity decay factor applied after each new key is emitted.
4562 // This parameter controls the deceleration and overall duration of the fling.
4563 // The fling stops automatically when its velocity drops below the minimum
4564 // fling velocity defined above.
4565 private static final float FLING_TICK_DECAY = 0.8f;
4566
4567 /* The input device that we are tracking. */
4568
4569 private int mCurrentDeviceId = -1;
4570 private int mCurrentSource;
4571 private boolean mCurrentDeviceSupported;
4572
4573 /* Configuration for the current input device. */
4574
Jeff Brown4dac9012013-04-10 01:03:19 -07004575 // The scaled tick distance. A movement of this amount should generally translate
4576 // into a single dpad event in a given direction.
4577 private float mConfigTickDistance;
4578
4579 // The minimum and maximum scaled fling velocity.
4580 private float mConfigMinFlingVelocity;
4581 private float mConfigMaxFlingVelocity;
4582
4583 /* Tracking state. */
4584
4585 // The velocity tracker for detecting flings.
4586 private VelocityTracker mVelocityTracker;
4587
4588 // The active pointer id, or -1 if none.
4589 private int mActivePointerId = -1;
4590
John Reck79d81e62013-11-05 13:26:57 -08004591 // Location where tracking started.
Jeff Brown4dac9012013-04-10 01:03:19 -07004592 private float mStartX;
4593 private float mStartY;
4594
4595 // Most recently observed position.
4596 private float mLastX;
4597 private float mLastY;
4598
4599 // Accumulated movement delta since the last direction key was sent.
Jeff Brown678a1252013-04-09 17:46:25 -07004600 private float mAccumulatedX;
4601 private float mAccumulatedY;
4602
Jeff Brown4dac9012013-04-10 01:03:19 -07004603 // Set to true if any movement was delivered to the app.
4604 // Implies that tap slop was exceeded.
4605 private boolean mConsumedMovement;
Jeff Brown678a1252013-04-09 17:46:25 -07004606
Jeff Brown4dac9012013-04-10 01:03:19 -07004607 // The most recently sent key down event.
4608 // The keycode remains set until the direction changes or a fling ends
4609 // so that repeated key events may be generated as required.
4610 private long mPendingKeyDownTime;
4611 private int mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
4612 private int mPendingKeyRepeatCount;
4613 private int mPendingKeyMetaState;
Jeff Brown678a1252013-04-09 17:46:25 -07004614
Jeff Brown4dac9012013-04-10 01:03:19 -07004615 // The current fling velocity while a fling is in progress.
4616 private boolean mFlinging;
4617 private float mFlingVelocity;
Jeff Brown678a1252013-04-09 17:46:25 -07004618
4619 public SyntheticTouchNavigationHandler() {
4620 super(true);
Jeff Brown678a1252013-04-09 17:46:25 -07004621 }
4622
4623 public void process(MotionEvent event) {
Jeff Brown4dac9012013-04-10 01:03:19 -07004624 // Update the current device information.
4625 final long time = event.getEventTime();
4626 final int deviceId = event.getDeviceId();
4627 final int source = event.getSource();
4628 if (mCurrentDeviceId != deviceId || mCurrentSource != source) {
4629 finishKeys(time);
4630 finishTracking(time);
4631 mCurrentDeviceId = deviceId;
4632 mCurrentSource = source;
4633 mCurrentDeviceSupported = false;
4634 InputDevice device = event.getDevice();
4635 if (device != null) {
4636 // In order to support an input device, we must know certain
4637 // characteristics about it, such as its size and resolution.
4638 InputDevice.MotionRange xRange = device.getMotionRange(MotionEvent.AXIS_X);
4639 InputDevice.MotionRange yRange = device.getMotionRange(MotionEvent.AXIS_Y);
4640 if (xRange != null && yRange != null) {
4641 mCurrentDeviceSupported = true;
Jeff Brown678a1252013-04-09 17:46:25 -07004642
Jeff Brown4dac9012013-04-10 01:03:19 -07004643 // Infer the resolution if it not actually known.
4644 float xRes = xRange.getResolution();
4645 if (xRes <= 0) {
4646 xRes = xRange.getRange() / DEFAULT_WIDTH_MILLIMETERS;
4647 }
4648 float yRes = yRange.getResolution();
4649 if (yRes <= 0) {
4650 yRes = yRange.getRange() / DEFAULT_HEIGHT_MILLIMETERS;
4651 }
4652 float nominalRes = (xRes + yRes) * 0.5f;
Jeff Brown678a1252013-04-09 17:46:25 -07004653
Jeff Brown4dac9012013-04-10 01:03:19 -07004654 // Precompute all of the configuration thresholds we will need.
Jeff Brown4dac9012013-04-10 01:03:19 -07004655 mConfigTickDistance = TICK_DISTANCE_MILLIMETERS * nominalRes;
4656 mConfigMinFlingVelocity =
4657 MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
4658 mConfigMaxFlingVelocity =
4659 MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
4660
4661 if (LOCAL_DEBUG) {
4662 Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId
4663 + " (" + Integer.toHexString(mCurrentSource) + "): "
Jeff Brown4dac9012013-04-10 01:03:19 -07004664 + ", mConfigTickDistance=" + mConfigTickDistance
4665 + ", mConfigMinFlingVelocity=" + mConfigMinFlingVelocity
4666 + ", mConfigMaxFlingVelocity=" + mConfigMaxFlingVelocity);
4667 }
4668 }
4669 }
Jeff Brown678a1252013-04-09 17:46:25 -07004670 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004671 if (!mCurrentDeviceSupported) {
Jeff Brown678a1252013-04-09 17:46:25 -07004672 return;
4673 }
4674
Jeff Brown4dac9012013-04-10 01:03:19 -07004675 // Handle the event.
4676 final int action = event.getActionMasked();
4677 switch (action) {
Jeff Brown678a1252013-04-09 17:46:25 -07004678 case MotionEvent.ACTION_DOWN: {
Jeff Brown4dac9012013-04-10 01:03:19 -07004679 boolean caughtFling = mFlinging;
4680 finishKeys(time);
4681 finishTracking(time);
4682 mActivePointerId = event.getPointerId(0);
4683 mVelocityTracker = VelocityTracker.obtain();
4684 mVelocityTracker.addMovement(event);
Jeff Brown4dac9012013-04-10 01:03:19 -07004685 mStartX = event.getX();
4686 mStartY = event.getY();
4687 mLastX = mStartX;
4688 mLastY = mStartY;
Jeff Brown678a1252013-04-09 17:46:25 -07004689 mAccumulatedX = 0;
4690 mAccumulatedY = 0;
Jeff Brown4dac9012013-04-10 01:03:19 -07004691
4692 // If we caught a fling, then pretend that the tap slop has already
4693 // been exceeded to suppress taps whose only purpose is to stop the fling.
4694 mConsumedMovement = caughtFling;
Jeff Brown678a1252013-04-09 17:46:25 -07004695 break;
4696 }
4697
Jeff Brown4dac9012013-04-10 01:03:19 -07004698 case MotionEvent.ACTION_MOVE:
Jeff Brown678a1252013-04-09 17:46:25 -07004699 case MotionEvent.ACTION_UP: {
Jeff Brown4dac9012013-04-10 01:03:19 -07004700 if (mActivePointerId < 0) {
4701 break;
4702 }
4703 final int index = event.findPointerIndex(mActivePointerId);
4704 if (index < 0) {
4705 finishKeys(time);
4706 finishTracking(time);
4707 break;
4708 }
Jeff Brown678a1252013-04-09 17:46:25 -07004709
Jeff Brown4dac9012013-04-10 01:03:19 -07004710 mVelocityTracker.addMovement(event);
4711 final float x = event.getX(index);
4712 final float y = event.getY(index);
4713 mAccumulatedX += x - mLastX;
4714 mAccumulatedY += y - mLastY;
4715 mLastX = x;
4716 mLastY = y;
4717
4718 // Consume any accumulated movement so far.
4719 final int metaState = event.getMetaState();
4720 consumeAccumulatedMovement(time, metaState);
4721
4722 // Detect taps and flings.
4723 if (action == MotionEvent.ACTION_UP) {
Michael Wright88d7f792013-08-27 15:45:42 -07004724 if (mConsumedMovement && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
Jeff Brown4dac9012013-04-10 01:03:19 -07004725 // It might be a fling.
4726 mVelocityTracker.computeCurrentVelocity(1000, mConfigMaxFlingVelocity);
4727 final float vx = mVelocityTracker.getXVelocity(mActivePointerId);
4728 final float vy = mVelocityTracker.getYVelocity(mActivePointerId);
4729 if (!startFling(time, vx, vy)) {
4730 finishKeys(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004731 }
4732 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004733 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004734 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004735 break;
4736 }
4737
4738 case MotionEvent.ACTION_CANCEL: {
4739 finishKeys(time);
4740 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004741 break;
4742 }
4743 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004744 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004745
4746 public void cancel(MotionEvent event) {
4747 if (mCurrentDeviceId == event.getDeviceId()
4748 && mCurrentSource == event.getSource()) {
4749 final long time = event.getEventTime();
4750 finishKeys(time);
4751 finishTracking(time);
4752 }
4753 }
4754
4755 private void finishKeys(long time) {
4756 cancelFling();
4757 sendKeyUp(time);
4758 }
4759
4760 private void finishTracking(long time) {
4761 if (mActivePointerId >= 0) {
4762 mActivePointerId = -1;
4763 mVelocityTracker.recycle();
4764 mVelocityTracker = null;
4765 }
4766 }
4767
4768 private void consumeAccumulatedMovement(long time, int metaState) {
4769 final float absX = Math.abs(mAccumulatedX);
4770 final float absY = Math.abs(mAccumulatedY);
4771 if (absX >= absY) {
4772 if (absX >= mConfigTickDistance) {
4773 mAccumulatedX = consumeAccumulatedMovement(time, metaState, mAccumulatedX,
4774 KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT);
4775 mAccumulatedY = 0;
4776 mConsumedMovement = true;
4777 }
4778 } else {
4779 if (absY >= mConfigTickDistance) {
4780 mAccumulatedY = consumeAccumulatedMovement(time, metaState, mAccumulatedY,
4781 KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN);
4782 mAccumulatedX = 0;
4783 mConsumedMovement = true;
4784 }
4785 }
4786 }
4787
4788 private float consumeAccumulatedMovement(long time, int metaState,
4789 float accumulator, int negativeKeyCode, int positiveKeyCode) {
4790 while (accumulator <= -mConfigTickDistance) {
4791 sendKeyDownOrRepeat(time, negativeKeyCode, metaState);
4792 accumulator += mConfigTickDistance;
4793 }
4794 while (accumulator >= mConfigTickDistance) {
4795 sendKeyDownOrRepeat(time, positiveKeyCode, metaState);
4796 accumulator -= mConfigTickDistance;
4797 }
4798 return accumulator;
4799 }
4800
4801 private void sendKeyDownOrRepeat(long time, int keyCode, int metaState) {
4802 if (mPendingKeyCode != keyCode) {
4803 sendKeyUp(time);
4804 mPendingKeyDownTime = time;
4805 mPendingKeyCode = keyCode;
4806 mPendingKeyRepeatCount = 0;
4807 } else {
4808 mPendingKeyRepeatCount += 1;
4809 }
4810 mPendingKeyMetaState = metaState;
4811
4812 // Note: Normally we would pass FLAG_LONG_PRESS when the repeat count is 1
4813 // but it doesn't quite make sense when simulating the events in this way.
4814 if (LOCAL_DEBUG) {
4815 Log.d(LOCAL_TAG, "Sending key down: keyCode=" + mPendingKeyCode
4816 + ", repeatCount=" + mPendingKeyRepeatCount
4817 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
4818 }
4819 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
4820 KeyEvent.ACTION_DOWN, mPendingKeyCode, mPendingKeyRepeatCount,
4821 mPendingKeyMetaState, mCurrentDeviceId,
4822 KeyEvent.FLAG_FALLBACK, mCurrentSource));
4823 }
4824
4825 private void sendKeyUp(long time) {
4826 if (mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
4827 if (LOCAL_DEBUG) {
4828 Log.d(LOCAL_TAG, "Sending key up: keyCode=" + mPendingKeyCode
4829 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
4830 }
4831 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
4832 KeyEvent.ACTION_UP, mPendingKeyCode, 0, mPendingKeyMetaState,
4833 mCurrentDeviceId, 0, KeyEvent.FLAG_FALLBACK,
4834 mCurrentSource));
4835 mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
4836 }
4837 }
4838
4839 private boolean startFling(long time, float vx, float vy) {
4840 if (LOCAL_DEBUG) {
4841 Log.d(LOCAL_TAG, "Considering fling: vx=" + vx + ", vy=" + vy
4842 + ", min=" + mConfigMinFlingVelocity);
4843 }
4844
4845 // Flings must be oriented in the same direction as the preceding movements.
4846 switch (mPendingKeyCode) {
4847 case KeyEvent.KEYCODE_DPAD_LEFT:
4848 if (-vx >= mConfigMinFlingVelocity
4849 && Math.abs(vy) < mConfigMinFlingVelocity) {
4850 mFlingVelocity = -vx;
4851 break;
4852 }
4853 return false;
4854
4855 case KeyEvent.KEYCODE_DPAD_RIGHT:
4856 if (vx >= mConfigMinFlingVelocity
4857 && Math.abs(vy) < mConfigMinFlingVelocity) {
4858 mFlingVelocity = vx;
4859 break;
4860 }
4861 return false;
4862
4863 case KeyEvent.KEYCODE_DPAD_UP:
4864 if (-vy >= mConfigMinFlingVelocity
4865 && Math.abs(vx) < mConfigMinFlingVelocity) {
4866 mFlingVelocity = -vy;
4867 break;
4868 }
4869 return false;
4870
4871 case KeyEvent.KEYCODE_DPAD_DOWN:
4872 if (vy >= mConfigMinFlingVelocity
4873 && Math.abs(vx) < mConfigMinFlingVelocity) {
4874 mFlingVelocity = vy;
4875 break;
4876 }
4877 return false;
4878 }
4879
4880 // Post the first fling event.
4881 mFlinging = postFling(time);
4882 return mFlinging;
4883 }
4884
4885 private boolean postFling(long time) {
4886 // The idea here is to estimate the time when the pointer would have
4887 // traveled one tick distance unit given the current fling velocity.
4888 // This effect creates continuity of motion.
4889 if (mFlingVelocity >= mConfigMinFlingVelocity) {
4890 long delay = (long)(mConfigTickDistance / mFlingVelocity * 1000);
4891 postAtTime(mFlingRunnable, time + delay);
4892 if (LOCAL_DEBUG) {
4893 Log.d(LOCAL_TAG, "Posted fling: velocity="
4894 + mFlingVelocity + ", delay=" + delay
4895 + ", keyCode=" + mPendingKeyCode);
4896 }
4897 return true;
4898 }
4899 return false;
4900 }
4901
4902 private void cancelFling() {
4903 if (mFlinging) {
4904 removeCallbacks(mFlingRunnable);
4905 mFlinging = false;
4906 }
4907 }
4908
4909 private final Runnable mFlingRunnable = new Runnable() {
4910 @Override
4911 public void run() {
4912 final long time = SystemClock.uptimeMillis();
4913 sendKeyDownOrRepeat(time, mPendingKeyCode, mPendingKeyMetaState);
4914 mFlingVelocity *= FLING_TICK_DECAY;
4915 if (!postFling(time)) {
4916 mFlinging = false;
4917 finishKeys(time);
4918 }
4919 }
4920 };
Jeff Browncb1404e2011-01-15 18:14:15 -08004921 }
4922
Michael Wright899d7052014-04-23 17:23:39 -07004923 final class SyntheticKeyboardHandler {
4924 public void process(KeyEvent event) {
4925 if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
4926 return;
4927 }
4928
4929 final KeyCharacterMap kcm = event.getKeyCharacterMap();
4930 final int keyCode = event.getKeyCode();
4931 final int metaState = event.getMetaState();
4932
4933 // Check for fallback actions specified by the key character map.
4934 KeyCharacterMap.FallbackAction fallbackAction =
4935 kcm.getFallbackAction(keyCode, metaState);
4936 if (fallbackAction != null) {
4937 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
4938 KeyEvent fallbackEvent = KeyEvent.obtain(
4939 event.getDownTime(), event.getEventTime(),
4940 event.getAction(), fallbackAction.keyCode,
4941 event.getRepeatCount(), fallbackAction.metaState,
4942 event.getDeviceId(), event.getScanCode(),
4943 flags, event.getSource(), null);
4944 fallbackAction.recycle();
4945 enqueueInputEvent(fallbackEvent);
4946 }
4947 }
4948 }
4949
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004950 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004951 * Returns true if the key is used for keyboard navigation.
4952 * @param keyEvent The key event.
4953 * @return True if the key is used for keyboard navigation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004954 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08004955 private static boolean isNavigationKey(KeyEvent keyEvent) {
4956 switch (keyEvent.getKeyCode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004957 case KeyEvent.KEYCODE_DPAD_LEFT:
4958 case KeyEvent.KEYCODE_DPAD_RIGHT:
4959 case KeyEvent.KEYCODE_DPAD_UP:
4960 case KeyEvent.KEYCODE_DPAD_DOWN:
Jeff Brown4e6319b2010-12-13 10:36:51 -08004961 case KeyEvent.KEYCODE_DPAD_CENTER:
4962 case KeyEvent.KEYCODE_PAGE_UP:
4963 case KeyEvent.KEYCODE_PAGE_DOWN:
4964 case KeyEvent.KEYCODE_MOVE_HOME:
4965 case KeyEvent.KEYCODE_MOVE_END:
4966 case KeyEvent.KEYCODE_TAB:
4967 case KeyEvent.KEYCODE_SPACE:
4968 case KeyEvent.KEYCODE_ENTER:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004969 return true;
4970 }
4971 return false;
4972 }
4973
4974 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004975 * Returns true if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004976 * @param keyEvent The key event.
Jeff Brown4e6319b2010-12-13 10:36:51 -08004977 * @return True if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004978 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08004979 private static boolean isTypingKey(KeyEvent keyEvent) {
4980 return keyEvent.getUnicodeChar() > 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004981 }
4982
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004983 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08004984 * See if the key event means we should leave touch mode (and leave touch mode if so).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004985 * @param event The key event.
4986 * @return Whether this key event should be consumed (meaning the act of
4987 * leaving touch mode alone is considered the event).
4988 */
4989 private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08004990 // Only relevant in touch mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004991 if (!mAttachInfo.mInTouchMode) {
4992 return false;
4993 }
4994
Jeff Brown4e6319b2010-12-13 10:36:51 -08004995 // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
4996 final int action = event.getAction();
4997 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004998 return false;
4999 }
5000
Jeff Brown4e6319b2010-12-13 10:36:51 -08005001 // Don't leave touch mode if the IME told us not to.
5002 if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
5003 return false;
5004 }
5005
5006 // If the key can be used for keyboard navigation then leave touch mode
5007 // and select a focused view if needed (in ensureTouchMode).
5008 // When a new focused view is selected, we consume the navigation key because
5009 // navigation doesn't make much sense unless a view already has focus so
5010 // the key's purpose is to set focus.
5011 if (isNavigationKey(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005012 return ensureTouchMode(false);
5013 }
Jeff Brown4e6319b2010-12-13 10:36:51 -08005014
5015 // If the key can be used for typing then leave touch mode
5016 // and select a focused view if needed (in ensureTouchMode).
5017 // Always allow the view to process the typing key.
5018 if (isTypingKey(event)) {
5019 ensureTouchMode(false);
5020 return false;
5021 }
5022
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005023 return false;
5024 }
5025
Christopher Tatea53146c2010-09-07 11:57:52 -07005026 /* drag/drop */
Christopher Tate407b4e92010-11-30 17:14:08 -08005027 void setLocalDragState(Object obj) {
5028 mLocalDragState = obj;
5029 }
5030
Christopher Tatea53146c2010-09-07 11:57:52 -07005031 private void handleDragEvent(DragEvent event) {
5032 // From the root, only drag start/end/location are dispatched. entered/exited
5033 // are determined and dispatched by the viewgroup hierarchy, who then report
5034 // that back here for ultimate reporting back to the framework.
5035 if (mView != null && mAdded) {
5036 final int what = event.mAction;
5037
5038 if (what == DragEvent.ACTION_DRAG_EXITED) {
5039 // A direct EXITED event means that the window manager knows we've just crossed
5040 // a window boundary, so the current drag target within this one must have
5041 // just been exited. Send it the usual notifications and then we're done
5042 // for now.
Chris Tate9d1ab882010-11-02 15:55:39 -07005043 mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07005044 } else {
5045 // Cache the drag description when the operation starts, then fill it in
5046 // on subsequent calls as a convenience
5047 if (what == DragEvent.ACTION_DRAG_STARTED) {
Chris Tate9d1ab882010-11-02 15:55:39 -07005048 mCurrentDragView = null; // Start the current-recipient tracking
Christopher Tatea53146c2010-09-07 11:57:52 -07005049 mDragDescription = event.mClipDescription;
5050 } else {
5051 event.mClipDescription = mDragDescription;
5052 }
5053
5054 // For events with a [screen] location, translate into window coordinates
5055 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
5056 mDragPoint.set(event.mX, event.mY);
5057 if (mTranslator != null) {
5058 mTranslator.translatePointInScreenToAppWindow(mDragPoint);
5059 }
5060
5061 if (mCurScrollY != 0) {
5062 mDragPoint.offset(0, mCurScrollY);
5063 }
5064
5065 event.mX = mDragPoint.x;
5066 event.mY = mDragPoint.y;
5067 }
5068
5069 // Remember who the current drag target is pre-dispatch
5070 final View prevDragView = mCurrentDragView;
5071
5072 // Now dispatch the drag/drop event
Chris Tated4533f12010-10-19 15:15:08 -07005073 boolean result = mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07005074
5075 // If we changed apparent drag target, tell the OS about it
5076 if (prevDragView != mCurrentDragView) {
5077 try {
5078 if (prevDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07005079 mWindowSession.dragRecipientExited(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07005080 }
5081 if (mCurrentDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07005082 mWindowSession.dragRecipientEntered(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07005083 }
5084 } catch (RemoteException e) {
5085 Slog.e(TAG, "Unable to note drag target change");
5086 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005087 }
Chris Tated4533f12010-10-19 15:15:08 -07005088
Christopher Tate407b4e92010-11-30 17:14:08 -08005089 // Report the drop result when we're done
Chris Tated4533f12010-10-19 15:15:08 -07005090 if (what == DragEvent.ACTION_DROP) {
Christopher Tate1fc014f2011-01-19 12:56:26 -08005091 mDragDescription = null;
Chris Tated4533f12010-10-19 15:15:08 -07005092 try {
5093 Log.i(TAG, "Reporting drop result: " + result);
Jeff Brown98365d72012-08-19 20:30:52 -07005094 mWindowSession.reportDropResult(mWindow, result);
Chris Tated4533f12010-10-19 15:15:08 -07005095 } catch (RemoteException e) {
5096 Log.e(TAG, "Unable to report drop result");
5097 }
5098 }
Christopher Tate407b4e92010-11-30 17:14:08 -08005099
5100 // When the drag operation ends, release any local state object
5101 // that may have been in use
5102 if (what == DragEvent.ACTION_DRAG_ENDED) {
5103 setLocalDragState(null);
5104 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005105 }
5106 }
5107 event.recycle();
5108 }
5109
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005110 public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
5111 if (mSeq != args.seq) {
5112 // The sequence has changed, so we need to update our value and make
5113 // sure to do a traversal afterward so the window manager is given our
5114 // most recent data.
5115 mSeq = args.seq;
5116 mAttachInfo.mForceReportNewAttributes = true;
Igor Murashkina86ab6402013-08-30 12:58:36 -07005117 scheduleTraversals();
Joe Onorato14782f72011-01-25 19:53:17 -08005118 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005119 if (mView == null) return;
5120 if (args.localChanges != 0) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005121 mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005122 }
Chris Craikd36a81f2014-07-17 10:16:51 -07005123
5124 int visibility = args.globalVisibility&View.SYSTEM_UI_CLEARABLE_FLAGS;
5125 if (visibility != mAttachInfo.mGlobalSystemUiVisibility) {
5126 mAttachInfo.mGlobalSystemUiVisibility = visibility;
5127 mView.dispatchSystemUiVisibilityChanged(visibility);
Dianne Hackborncf675782012-05-10 15:07:24 -07005128 }
Joe Onorato664644d2011-01-23 17:53:23 -08005129 }
5130
Dianne Hackborn12d3a942012-04-27 14:16:30 -07005131 public void handleDispatchDoneAnimating() {
5132 if (mWindowsAnimating) {
5133 mWindowsAnimating = false;
Mathias Agopian54e3d3842013-04-12 15:13:12 -07005134 if (!mDirty.isEmpty() || mIsAnimating || mFullRedrawNeeded) {
Dianne Hackborn12d3a942012-04-27 14:16:30 -07005135 scheduleTraversals();
5136 }
5137 }
5138 }
5139
Christopher Tate2c095f32010-10-04 14:13:40 -07005140 public void getLastTouchPoint(Point outLocation) {
5141 outLocation.x = (int) mLastTouchPoint.x;
5142 outLocation.y = (int) mLastTouchPoint.y;
5143 }
5144
Chris Tate9d1ab882010-11-02 15:55:39 -07005145 public void setDragFocus(View newDragTarget) {
Christopher Tatea53146c2010-09-07 11:57:52 -07005146 if (mCurrentDragView != newDragTarget) {
Chris Tate048691c2010-10-12 17:39:18 -07005147 mCurrentDragView = newDragTarget;
Christopher Tatea53146c2010-09-07 11:57:52 -07005148 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005149 }
5150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005151 private AudioManager getAudioManager() {
5152 if (mView == null) {
5153 throw new IllegalStateException("getAudioManager called when there is no mView");
5154 }
5155 if (mAudioManager == null) {
5156 mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
5157 }
5158 return mAudioManager;
5159 }
5160
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005161 public AccessibilityInteractionController getAccessibilityInteractionController() {
5162 if (mView == null) {
5163 throw new IllegalStateException("getAccessibilityInteractionController"
5164 + " called when there is no mView");
5165 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07005166 if (mAccessibilityInteractionController == null) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005167 mAccessibilityInteractionController = new AccessibilityInteractionController(this);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005168 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07005169 return mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005170 }
5171
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07005172 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
5173 boolean insetsPending) throws RemoteException {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005174
5175 float appScale = mAttachInfo.mApplicationScale;
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005176 boolean restore = false;
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005177 if (params != null && mTranslator != null) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005178 restore = true;
5179 params.backup();
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005180 mTranslator.translateWindowLayout(params);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005181 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005182 if (params != null) {
5183 if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params);
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005184 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07005185 mPendingConfiguration.seq = 0;
Dianne Hackbornf123e492010-09-24 11:16:23 -07005186 //Log.d(TAG, ">>>>>> CALLING relayout");
Dianne Hackborn180c4842011-09-13 12:39:25 -07005187 if (params != null && mOrigWindowType != params.type) {
5188 // For compatibility with old apps, don't crash here.
5189 if (mTargetSdkVersion < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
5190 Slog.w(TAG, "Window type can not be changed after "
5191 + "the window is added; ignoring change of " + mView);
5192 params.type = mOrigWindowType;
5193 }
5194 }
Jeff Brown98365d72012-08-19 20:30:52 -07005195 int relayoutResult = mWindowSession.relayout(
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005196 mWindow, mSeq, params,
Dianne Hackborn189ee182010-12-02 21:48:53 -08005197 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
5198 (int) (mView.getMeasuredHeight() * appScale + 0.5f),
Jeff Brown98365d72012-08-19 20:30:52 -07005199 viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005200 mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
Adrian Roosfa104232014-06-20 16:10:14 -07005201 mPendingStableInsets, mPendingConfiguration, mSurface);
Dianne Hackbornf123e492010-09-24 11:16:23 -07005202 //Log.d(TAG, "<<<<<< BACK FROM relayout");
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005203 if (restore) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005204 params.restore();
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005205 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07005206
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005207 if (mTranslator != null) {
5208 mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005209 mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005210 mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
5211 mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
Adrian Roosfa104232014-06-20 16:10:14 -07005212 mTranslator.translateRectInScreenToAppWindow(mPendingStableInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005213 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07005214 return relayoutResult;
5215 }
Romain Guy8506ab42009-06-11 17:35:47 -07005216
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005217 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005218 * {@inheritDoc}
5219 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005220 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005221 public void playSoundEffect(int effectId) {
5222 checkThread();
5223
Dan Morrille4d9a012013-03-28 18:10:43 -07005224 if (mMediaDisabled) {
5225 return;
5226 }
5227
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005228 try {
5229 final AudioManager audioManager = getAudioManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005230
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005231 switch (effectId) {
5232 case SoundEffectConstants.CLICK:
5233 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
5234 return;
5235 case SoundEffectConstants.NAVIGATION_DOWN:
5236 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
5237 return;
5238 case SoundEffectConstants.NAVIGATION_LEFT:
5239 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
5240 return;
5241 case SoundEffectConstants.NAVIGATION_RIGHT:
5242 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
5243 return;
5244 case SoundEffectConstants.NAVIGATION_UP:
5245 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
5246 return;
5247 default:
5248 throw new IllegalArgumentException("unknown effect id " + effectId +
5249 " not defined in " + SoundEffectConstants.class.getCanonicalName());
5250 }
5251 } catch (IllegalStateException e) {
5252 // Exception thrown by getAudioManager() when mView is null
5253 Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e);
5254 e.printStackTrace();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005255 }
5256 }
5257
5258 /**
5259 * {@inheritDoc}
5260 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005261 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005262 public boolean performHapticFeedback(int effectId, boolean always) {
5263 try {
Jeff Brown98365d72012-08-19 20:30:52 -07005264 return mWindowSession.performHapticFeedback(mWindow, effectId, always);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005265 } catch (RemoteException e) {
5266 return false;
5267 }
5268 }
5269
5270 /**
5271 * {@inheritDoc}
5272 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005273 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005274 public View focusSearch(View focused, int direction) {
5275 checkThread();
5276 if (!(mView instanceof ViewGroup)) {
5277 return null;
5278 }
5279 return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
5280 }
5281
5282 public void debug() {
5283 mView.debug();
5284 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07005285
Jeff Brown5182c782013-10-15 20:31:52 -07005286 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
5287 String innerPrefix = prefix + " ";
5288 writer.print(prefix); writer.println("ViewRoot:");
5289 writer.print(innerPrefix); writer.print("mAdded="); writer.print(mAdded);
5290 writer.print(" mRemoved="); writer.println(mRemoved);
5291 writer.print(innerPrefix); writer.print("mConsumeBatchedInputScheduled=");
5292 writer.println(mConsumeBatchedInputScheduled);
Michael Wright9d744c72014-02-18 21:27:42 -08005293 writer.print(innerPrefix); writer.print("mConsumeBatchedInputImmediatelyScheduled=");
5294 writer.println(mConsumeBatchedInputImmediatelyScheduled);
Jeff Brown5182c782013-10-15 20:31:52 -07005295 writer.print(innerPrefix); writer.print("mPendingInputEventCount=");
5296 writer.println(mPendingInputEventCount);
5297 writer.print(innerPrefix); writer.print("mProcessInputEventsScheduled=");
5298 writer.println(mProcessInputEventsScheduled);
5299 writer.print(innerPrefix); writer.print("mTraversalScheduled=");
5300 writer.print(mTraversalScheduled);
5301 if (mTraversalScheduled) {
5302 writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
5303 } else {
5304 writer.println();
5305 }
5306 mFirstInputStage.dump(innerPrefix, writer);
5307
5308 mChoreographer.dump(prefix, writer);
5309
5310 writer.print(prefix); writer.println("View Hierarchy:");
5311 dumpViewHierarchy(innerPrefix, writer, mView);
5312 }
5313
5314 private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) {
5315 writer.print(prefix);
5316 if (view == null) {
5317 writer.println("null");
5318 return;
5319 }
5320 writer.println(view.toString());
5321 if (!(view instanceof ViewGroup)) {
5322 return;
5323 }
5324 ViewGroup grp = (ViewGroup)view;
5325 final int N = grp.getChildCount();
5326 if (N <= 0) {
5327 return;
5328 }
5329 prefix = prefix + " ";
5330 for (int i=0; i<N; i++) {
5331 dumpViewHierarchy(prefix, writer, grp.getChildAt(i));
5332 }
5333 }
5334
Romain Guy211370f2012-02-01 16:10:55 -08005335 public void dumpGfxInfo(int[] info) {
Romain Guy54ab3472012-06-14 12:52:53 -07005336 info[0] = info[1] = 0;
Romain Guy65b345f2011-07-27 18:51:50 -07005337 if (mView != null) {
5338 getGfxInfo(mView, info);
Romain Guy65b345f2011-07-27 18:51:50 -07005339 }
5340 }
5341
Romain Guya998dff2012-03-23 18:58:36 -07005342 private static void getGfxInfo(View view, int[] info) {
Chris Craik64a12e12014-03-28 18:12:12 -07005343 RenderNode renderNode = view.mRenderNode;
Romain Guy65b345f2011-07-27 18:51:50 -07005344 info[0]++;
Chris Craik64a12e12014-03-28 18:12:12 -07005345 if (renderNode != null) {
John Reckfe5e7b72014-05-23 17:42:28 -07005346 info[1] += renderNode.getDebugSize();
Romain Guy65b345f2011-07-27 18:51:50 -07005347 }
5348
5349 if (view instanceof ViewGroup) {
5350 ViewGroup group = (ViewGroup) view;
5351
5352 int count = group.getChildCount();
5353 for (int i = 0; i < count; i++) {
5354 getGfxInfo(group.getChildAt(i), info);
5355 }
5356 }
5357 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005358
Craig Mautner8f303ad2013-06-14 11:32:22 -07005359 /**
5360 * @param immediate True, do now if not in traversal. False, put on queue and do later.
5361 * @return True, request has been queued. False, request has been completed.
5362 */
5363 boolean die(boolean immediate) {
Craig Mautnerdf2390a2012-08-29 20:59:22 -07005364 // Make sure we do execute immediately if we are in the middle of a traversal or the damage
5365 // done by dispatchDetachedFromWindow will cause havoc on return.
5366 if (immediate && !mIsInTraversal) {
Dianne Hackborn94d69142009-09-28 22:14:42 -07005367 doDie();
Craig Mautner8f303ad2013-06-14 11:32:22 -07005368 return false;
Dianne Hackborn94d69142009-09-28 22:14:42 -07005369 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07005370
5371 if (!mIsDrawing) {
5372 destroyHardwareRenderer();
5373 } else {
5374 Log.e(TAG, "Attempting to destroy the window while drawing!\n" +
5375 " window=" + this + ", title=" + mWindowAttributes.getTitle());
5376 }
5377 mHandler.sendEmptyMessage(MSG_DIE);
5378 return true;
Dianne Hackborn94d69142009-09-28 22:14:42 -07005379 }
5380
5381 void doDie() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005382 checkThread();
Jeff Brownb75fa302010-07-15 23:47:29 -07005383 if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005384 synchronized (this) {
Craig Mautner8f303ad2013-06-14 11:32:22 -07005385 if (mRemoved) {
5386 return;
5387 }
5388 mRemoved = true;
Romain Guy16260e72011-09-01 14:26:11 -07005389 if (mAdded) {
Romain Guy16260e72011-09-01 14:26:11 -07005390 dispatchDetachedFromWindow();
5391 }
5392
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005393 if (mAdded && !mFirst) {
Romain Guy29d89972010-09-22 16:10:57 -07005394 destroyHardwareRenderer();
5395
Romain Guyedbca122012-04-04 18:25:53 -07005396 if (mView != null) {
5397 int viewVisibility = mView.getVisibility();
5398 boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
5399 if (mWindowAttributesChanged || viewVisibilityChanged) {
5400 // If layout params have been changed, first give them
5401 // to the window manager to make sure it has the correct
5402 // animation info.
5403 try {
5404 if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
Jeff Brown98365d72012-08-19 20:30:52 -07005405 & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
5406 mWindowSession.finishDrawing(mWindow);
Romain Guyedbca122012-04-04 18:25:53 -07005407 }
5408 } catch (RemoteException e) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005409 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005410 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07005411
Romain Guyedbca122012-04-04 18:25:53 -07005412 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005413 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005414 }
Romain Guyedbca122012-04-04 18:25:53 -07005415
5416 mAdded = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005417 }
Craig Mautner05eb7302013-06-03 17:24:21 -07005418 WindowManagerGlobal.getInstance().doRemoveView(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005419 }
5420
Dianne Hackborn5fd21692011-06-07 14:09:47 -07005421 public void requestUpdateConfiguration(Configuration config) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005422 Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
5423 mHandler.sendMessage(msg);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07005424 }
5425
Dianne Hackborna53de062012-05-08 18:53:51 -07005426 public void loadSystemProperties() {
Romain Guy5bb3c732012-11-29 17:52:58 -08005427 mHandler.post(new Runnable() {
5428 @Override
5429 public void run() {
5430 // Profiling
5431 mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false);
5432 profileRendering(mAttachInfo.mHasWindowFocus);
5433
Dan Morrille4d9a012013-03-28 18:10:43 -07005434 // Media (used by sound effects)
5435 mMediaDisabled = SystemProperties.getBoolean(PROPERTY_MEDIA_DISABLED, false);
5436
Romain Guy5bb3c732012-11-29 17:52:58 -08005437 // Hardware rendering
5438 if (mAttachInfo.mHardwareRenderer != null) {
John Reckcec24ae2013-11-05 13:27:50 -08005439 if (mAttachInfo.mHardwareRenderer.loadSystemProperties()) {
Romain Guy5bb3c732012-11-29 17:52:58 -08005440 invalidate();
5441 }
5442 }
5443
5444 // Layout debugging
5445 boolean layout = SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false);
5446 if (layout != mAttachInfo.mDebugLayout) {
5447 mAttachInfo.mDebugLayout = layout;
5448 if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
5449 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
5450 }
5451 }
Michael Kolb22dfdcb2014-06-20 15:39:04 -07005452
5453 // detect emulator
5454 mIsEmulator = Build.HARDWARE.contains("goldfish");
Filip Gruszczynskif14d9242014-08-25 17:05:11 -07005455 mIsCircularEmulator =
5456 SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false);
Dianne Hackborna53de062012-05-08 18:53:51 -07005457 }
Romain Guy5bb3c732012-11-29 17:52:58 -08005458 });
Dianne Hackborna53de062012-05-08 18:53:51 -07005459 }
5460
Romain Guy29d89972010-09-22 16:10:57 -07005461 private void destroyHardwareRenderer() {
Chris Craikd36a81f2014-07-17 10:16:51 -07005462 HardwareRenderer hardwareRenderer = mAttachInfo.mHardwareRenderer;
Romain Guya998dff2012-03-23 18:58:36 -07005463
5464 if (hardwareRenderer != null) {
5465 if (mView != null) {
5466 hardwareRenderer.destroyHardwareResources(mView);
5467 }
John Reckf47a5942014-06-30 16:20:04 -07005468 hardwareRenderer.destroy();
Romain Guya998dff2012-03-23 18:58:36 -07005469 hardwareRenderer.setRequested(false);
5470
Chris Craikd36a81f2014-07-17 10:16:51 -07005471 mAttachInfo.mHardwareRenderer = null;
5472 mAttachInfo.mHardwareAccelerated = false;
Romain Guy29d89972010-09-22 16:10:57 -07005473 }
5474 }
5475
Jeff Browna175a5b2012-02-15 19:18:31 -08005476 public void dispatchFinishInputConnection(InputConnection connection) {
5477 Message msg = mHandler.obtainMessage(MSG_FINISH_INPUT_CONNECTION, connection);
5478 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005479 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005480
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005481 public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Adrian Roosfa104232014-06-20 16:10:14 -07005482 Rect visibleInsets, Rect stableInsets, boolean reportDraw, Configuration newConfig) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005483 if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": frame=" + frame.toShortString()
5484 + " contentInsets=" + contentInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005485 + " visibleInsets=" + visibleInsets.toShortString()
5486 + " reportDraw=" + reportDraw);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005487 Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005488 if (mTranslator != null) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005489 mTranslator.translateRectInScreenToAppWindow(frame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005490 mTranslator.translateRectInScreenToAppWindow(overscanInsets);
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07005491 mTranslator.translateRectInScreenToAppWindow(contentInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005492 mTranslator.translateRectInScreenToAppWindow(visibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005493 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005494 SomeArgs args = SomeArgs.obtain();
5495 final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
5496 args.arg1 = sameProcessCall ? new Rect(frame) : frame;
5497 args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets;
5498 args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
5499 args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005500 args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
Adrian Roosfa104232014-06-20 16:10:14 -07005501 args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005502 msg.obj = args;
Jeff Browna175a5b2012-02-15 19:18:31 -08005503 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005504 }
Chet Haase1f4786b2011-11-02 10:51:52 -07005505
Craig Mautner5702d4d2012-06-30 14:10:16 -07005506 public void dispatchMoved(int newX, int newY) {
5507 if (DEBUG_LAYOUT) Log.v(TAG, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
5508 if (mTranslator != null) {
5509 PointF point = new PointF(newX, newY);
5510 mTranslator.translatePointInScreenToAppWindow(point);
5511 newX = (int) (point.x + 0.5);
5512 newY = (int) (point.y + 0.5);
5513 }
5514 Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY);
5515 mHandler.sendMessage(msg);
5516 }
5517
Jeff Brown4952dfd2011-11-30 19:23:22 -08005518 /**
5519 * Represents a pending input event that is waiting in a queue.
5520 *
5521 * Input events are processed in serial order by the timestamp specified by
Romain Guy211370f2012-02-01 16:10:55 -08005522 * {@link InputEvent#getEventTimeNano()}. In general, the input dispatcher delivers
Jeff Brown4952dfd2011-11-30 19:23:22 -08005523 * one input event to the application at a time and waits for the application
5524 * to finish handling it before delivering the next one.
5525 *
5526 * However, because the application or IME can synthesize and inject multiple
5527 * key events at a time without going through the input dispatcher, we end up
5528 * needing a queue on the application's side.
5529 */
5530 private static final class QueuedInputEvent {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005531 public static final int FLAG_DELIVER_POST_IME = 1 << 0;
5532 public static final int FLAG_DEFERRED = 1 << 1;
5533 public static final int FLAG_FINISHED = 1 << 2;
5534 public static final int FLAG_FINISHED_HANDLED = 1 << 3;
5535 public static final int FLAG_RESYNTHESIZED = 1 << 4;
Michael Wright899d7052014-04-23 17:23:39 -07005536 public static final int FLAG_UNHANDLED = 1 << 5;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005537
5538 public QueuedInputEvent mNext;
5539
5540 public InputEvent mEvent;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005541 public InputEventReceiver mReceiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005542 public int mFlags;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005543
5544 public boolean shouldSkipIme() {
5545 if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
5546 return true;
5547 }
5548 return mEvent instanceof MotionEvent
5549 && mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER);
5550 }
Michael Wright899d7052014-04-23 17:23:39 -07005551
5552 public boolean shouldSendToSynthesizer() {
5553 if ((mFlags & FLAG_UNHANDLED) != 0) {
5554 return true;
5555 }
5556
5557 return false;
5558 }
Michael Wright06a79252014-05-05 17:45:29 -07005559
5560 @Override
5561 public String toString() {
5562 StringBuilder sb = new StringBuilder("QueuedInputEvent{flags=");
5563 boolean hasPrevious = false;
5564 hasPrevious = flagToString("DELIVER_POST_IME", FLAG_DELIVER_POST_IME, hasPrevious, sb);
5565 hasPrevious = flagToString("DEFERRED", FLAG_DEFERRED, hasPrevious, sb);
5566 hasPrevious = flagToString("FINISHED", FLAG_FINISHED, hasPrevious, sb);
5567 hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb);
5568 hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb);
5569 hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb);
5570 if (!hasPrevious) {
5571 sb.append("0");
5572 }
5573 sb.append(", hasNextQueuedEvent=" + (mEvent != null ? "true" : "false"));
5574 sb.append(", hasInputEventReceiver=" + (mReceiver != null ? "true" : "false"));
5575 sb.append(", mEvent=" + mEvent + "}");
5576 return sb.toString();
5577 }
5578
5579 private boolean flagToString(String name, int flag,
5580 boolean hasPrevious, StringBuilder sb) {
5581 if ((mFlags & flag) != 0) {
5582 if (hasPrevious) {
5583 sb.append("|");
5584 }
5585 sb.append(name);
5586 return true;
5587 }
5588 return hasPrevious;
5589 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005590 }
5591
5592 private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
Jeff Brown32cbc38552011-12-01 14:01:49 -08005593 InputEventReceiver receiver, int flags) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08005594 QueuedInputEvent q = mQueuedInputEventPool;
5595 if (q != null) {
5596 mQueuedInputEventPoolSize -= 1;
5597 mQueuedInputEventPool = q.mNext;
5598 q.mNext = null;
5599 } else {
5600 q = new QueuedInputEvent();
Jeff Brown46b9ac02010-04-22 18:58:52 -07005601 }
5602
Jeff Brown4952dfd2011-11-30 19:23:22 -08005603 q.mEvent = event;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005604 q.mReceiver = receiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005605 q.mFlags = flags;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005606 return q;
5607 }
5608
5609 private void recycleQueuedInputEvent(QueuedInputEvent q) {
5610 q.mEvent = null;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005611 q.mReceiver = null;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005612
5613 if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
5614 mQueuedInputEventPoolSize += 1;
5615 q.mNext = mQueuedInputEventPool;
5616 mQueuedInputEventPool = q;
5617 }
5618 }
5619
Jeff Brownf9261d22012-02-03 13:49:15 -08005620 void enqueueInputEvent(InputEvent event) {
5621 enqueueInputEvent(event, null, 0, false);
5622 }
5623
Jeff Brown4952dfd2011-11-30 19:23:22 -08005624 void enqueueInputEvent(InputEvent event,
Jeff Brownf9261d22012-02-03 13:49:15 -08005625 InputEventReceiver receiver, int flags, boolean processImmediately) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08005626 QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005627
Jeff Brown4952dfd2011-11-30 19:23:22 -08005628 // Always enqueue the input event in order, regardless of its time stamp.
5629 // We do this because the application or the IME may inject key events
5630 // in response to touch events and we want to ensure that the injected keys
5631 // are processed in the order they were received and we cannot trust that
5632 // the time stamp of injected events are monotonic.
Michael Wrightc8a7e542013-03-20 17:58:33 -07005633 QueuedInputEvent last = mPendingInputEventTail;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005634 if (last == null) {
Michael Wrightc8a7e542013-03-20 17:58:33 -07005635 mPendingInputEventHead = q;
5636 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005637 } else {
Jeff Brown4952dfd2011-11-30 19:23:22 -08005638 last.mNext = q;
Michael Wrightc8a7e542013-03-20 17:58:33 -07005639 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005640 }
Michael Wright95ae9422013-03-14 10:58:50 -07005641 mPendingInputEventCount += 1;
5642 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
5643 mPendingInputEventCount);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005644
Jeff Brownf9261d22012-02-03 13:49:15 -08005645 if (processImmediately) {
5646 doProcessInputEvents();
5647 } else {
5648 scheduleProcessInputEvents();
5649 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005650 }
5651
5652 private void scheduleProcessInputEvents() {
Jeff Brown96e942d2011-11-30 19:55:01 -08005653 if (!mProcessInputEventsScheduled) {
5654 mProcessInputEventsScheduled = true;
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005655 Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
5656 msg.setAsynchronous(true);
5657 mHandler.sendMessage(msg);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005658 }
5659 }
5660
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005661 void doProcessInputEvents() {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005662 // Deliver all pending input events in the queue.
Michael Wrightc8a7e542013-03-20 17:58:33 -07005663 while (mPendingInputEventHead != null) {
5664 QueuedInputEvent q = mPendingInputEventHead;
5665 mPendingInputEventHead = q.mNext;
5666 if (mPendingInputEventHead == null) {
5667 mPendingInputEventTail = null;
5668 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005669 q.mNext = null;
Jeff Brown29c0ed22013-01-14 13:50:37 -08005670
Michael Wright95ae9422013-03-14 10:58:50 -07005671 mPendingInputEventCount -= 1;
5672 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
5673 mPendingInputEventCount);
5674
Jeff Brownf9e989d2013-04-04 23:04:03 -07005675 deliverInputEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005676 }
5677
5678 // We are done processing all input events that we can process right now
5679 // so we can clear the pending flag immediately.
Jeff Brown96e942d2011-11-30 19:55:01 -08005680 if (mProcessInputEventsScheduled) {
5681 mProcessInputEventsScheduled = false;
Jeff Browna175a5b2012-02-15 19:18:31 -08005682 mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005683 }
5684 }
5685
Jeff Brownf9e989d2013-04-04 23:04:03 -07005686 private void deliverInputEvent(QueuedInputEvent q) {
Michael Wrightd2c3adc2014-02-18 22:50:50 -08005687 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
5688 q.mEvent.getSequenceNumber());
5689 if (mInputEventConsistencyVerifier != null) {
5690 mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
5691 }
Michael Wrightc8a7e542013-03-20 17:58:33 -07005692
Michael Wright899d7052014-04-23 17:23:39 -07005693 InputStage stage;
5694 if (q.shouldSendToSynthesizer()) {
5695 stage = mSyntheticInputStage;
5696 } else {
5697 stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
5698 }
5699
Michael Wrightd2c3adc2014-02-18 22:50:50 -08005700 if (stage != null) {
5701 stage.deliver(q);
5702 } else {
5703 finishInputEvent(q);
Michael Wrightbf020962013-03-28 17:27:50 -07005704 }
Michael Wrightbf020962013-03-28 17:27:50 -07005705 }
5706
Jeff Brownf9e989d2013-04-04 23:04:03 -07005707 private void finishInputEvent(QueuedInputEvent q) {
Michael Wrightd2c3adc2014-02-18 22:50:50 -08005708 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
5709 q.mEvent.getSequenceNumber());
Michael Wright9d744c72014-02-18 21:27:42 -08005710
Jeff Brown32cbc38552011-12-01 14:01:49 -08005711 if (q.mReceiver != null) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005712 boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005713 q.mReceiver.finishInputEvent(q.mEvent, handled);
Jeff Brown92cc2d82011-12-02 01:19:47 -08005714 } else {
5715 q.mEvent.recycleIfNeededAfterDispatch();
Jeff Brown4952dfd2011-11-30 19:23:22 -08005716 }
5717
5718 recycleQueuedInputEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08005719 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005720
Jeff Brownf9e989d2013-04-04 23:04:03 -07005721 static boolean isTerminalInputEvent(InputEvent event) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08005722 if (event instanceof KeyEvent) {
5723 final KeyEvent keyEvent = (KeyEvent)event;
5724 return keyEvent.getAction() == KeyEvent.ACTION_UP;
5725 } else {
5726 final MotionEvent motionEvent = (MotionEvent)event;
5727 final int action = motionEvent.getAction();
5728 return action == MotionEvent.ACTION_UP
5729 || action == MotionEvent.ACTION_CANCEL
5730 || action == MotionEvent.ACTION_HOVER_EXIT;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005731 }
5732 }
5733
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005734 void scheduleConsumeBatchedInput() {
5735 if (!mConsumeBatchedInputScheduled) {
5736 mConsumeBatchedInputScheduled = true;
5737 mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
5738 mConsumedBatchedInputRunnable, null);
Jeff Brown4a06c802012-02-15 15:06:01 -08005739 }
5740 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005741
5742 void unscheduleConsumeBatchedInput() {
5743 if (mConsumeBatchedInputScheduled) {
5744 mConsumeBatchedInputScheduled = false;
5745 mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT,
5746 mConsumedBatchedInputRunnable, null);
5747 }
5748 }
5749
Michael Wright9d744c72014-02-18 21:27:42 -08005750 void scheduleConsumeBatchedInputImmediately() {
5751 if (!mConsumeBatchedInputImmediatelyScheduled) {
5752 unscheduleConsumeBatchedInput();
5753 mConsumeBatchedInputImmediatelyScheduled = true;
5754 mHandler.post(mConsumeBatchedInputImmediatelyRunnable);
5755 }
5756 }
5757
Jeff Brown771526c2012-04-27 15:13:25 -07005758 void doConsumeBatchedInput(long frameTimeNanos) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005759 if (mConsumeBatchedInputScheduled) {
5760 mConsumeBatchedInputScheduled = false;
Jeff Brown330314c2012-04-27 02:20:22 -07005761 if (mInputEventReceiver != null) {
Michael Wright9d744c72014-02-18 21:27:42 -08005762 if (mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos)
5763 && frameTimeNanos != -1) {
Michael Wright62ce65d2013-10-25 14:50:36 -07005764 // If we consumed a batch here, we want to go ahead and schedule the
5765 // consumption of batched input events on the next frame. Otherwise, we would
5766 // wait until we have more input events pending and might get starved by other
Michael Wright9d744c72014-02-18 21:27:42 -08005767 // things occurring in the process. If the frame time is -1, however, then
5768 // we're in a non-batching mode, so there's no need to schedule this.
Michael Wright62ce65d2013-10-25 14:50:36 -07005769 scheduleConsumeBatchedInput();
5770 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005771 }
Jeff Brown330314c2012-04-27 02:20:22 -07005772 doProcessInputEvents();
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005773 }
5774 }
5775
5776 final class TraversalRunnable implements Runnable {
5777 @Override
5778 public void run() {
5779 doTraversal();
5780 }
5781 }
5782 final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
Jeff Brown4a06c802012-02-15 15:06:01 -08005783
Jeff Brown32cbc38552011-12-01 14:01:49 -08005784 final class WindowInputEventReceiver extends InputEventReceiver {
5785 public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
5786 super(inputChannel, looper);
Jeff Brown46b9ac02010-04-22 18:58:52 -07005787 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08005788
5789 @Override
5790 public void onInputEvent(InputEvent event) {
Jeff Brownf9261d22012-02-03 13:49:15 -08005791 enqueueInputEvent(event, this, 0, true);
Jeff Brown32cbc38552011-12-01 14:01:49 -08005792 }
Jeff Brown072ec962012-02-07 14:46:57 -08005793
5794 @Override
5795 public void onBatchedInputEventPending() {
Michael Wright9d744c72014-02-18 21:27:42 -08005796 if (mUnbufferedInputDispatch) {
5797 super.onBatchedInputEventPending();
5798 } else {
5799 scheduleConsumeBatchedInput();
5800 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005801 }
5802
5803 @Override
5804 public void dispose() {
5805 unscheduleConsumeBatchedInput();
5806 super.dispose();
Jeff Brown072ec962012-02-07 14:46:57 -08005807 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08005808 }
5809 WindowInputEventReceiver mInputEventReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005810
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005811 final class ConsumeBatchedInputRunnable implements Runnable {
5812 @Override
5813 public void run() {
Jeff Brown771526c2012-04-27 15:13:25 -07005814 doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005815 }
5816 }
5817 final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =
5818 new ConsumeBatchedInputRunnable();
5819 boolean mConsumeBatchedInputScheduled;
5820
Michael Wright9d744c72014-02-18 21:27:42 -08005821 final class ConsumeBatchedInputImmediatelyRunnable implements Runnable {
5822 @Override
5823 public void run() {
5824 doConsumeBatchedInput(-1);
5825 }
5826 }
5827 final ConsumeBatchedInputImmediatelyRunnable mConsumeBatchedInputImmediatelyRunnable =
5828 new ConsumeBatchedInputImmediatelyRunnable();
5829 boolean mConsumeBatchedInputImmediatelyScheduled;
5830
Jeff Brown6cb7b462012-03-05 13:21:17 -08005831 final class InvalidateOnAnimationRunnable implements Runnable {
5832 private boolean mPosted;
Igor Murashkina86ab6402013-08-30 12:58:36 -07005833 private final ArrayList<View> mViews = new ArrayList<View>();
5834 private final ArrayList<AttachInfo.InvalidateInfo> mViewRects =
Jeff Brown6cb7b462012-03-05 13:21:17 -08005835 new ArrayList<AttachInfo.InvalidateInfo>();
5836 private View[] mTempViews;
5837 private AttachInfo.InvalidateInfo[] mTempViewRects;
5838
5839 public void addView(View view) {
5840 synchronized (this) {
5841 mViews.add(view);
5842 postIfNeededLocked();
5843 }
5844 }
5845
5846 public void addViewRect(AttachInfo.InvalidateInfo info) {
5847 synchronized (this) {
5848 mViewRects.add(info);
5849 postIfNeededLocked();
5850 }
5851 }
5852
5853 public void removeView(View view) {
5854 synchronized (this) {
5855 mViews.remove(view);
5856
5857 for (int i = mViewRects.size(); i-- > 0; ) {
5858 AttachInfo.InvalidateInfo info = mViewRects.get(i);
5859 if (info.target == view) {
5860 mViewRects.remove(i);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08005861 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08005862 }
5863 }
5864
5865 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005866 mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08005867 mPosted = false;
5868 }
5869 }
5870 }
5871
5872 @Override
5873 public void run() {
5874 final int viewCount;
5875 final int viewRectCount;
5876 synchronized (this) {
5877 mPosted = false;
5878
5879 viewCount = mViews.size();
5880 if (viewCount != 0) {
5881 mTempViews = mViews.toArray(mTempViews != null
5882 ? mTempViews : new View[viewCount]);
5883 mViews.clear();
5884 }
5885
5886 viewRectCount = mViewRects.size();
5887 if (viewRectCount != 0) {
5888 mTempViewRects = mViewRects.toArray(mTempViewRects != null
5889 ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]);
5890 mViewRects.clear();
5891 }
5892 }
5893
5894 for (int i = 0; i < viewCount; i++) {
5895 mTempViews[i].invalidate();
Adam Powell3e3c4ee2012-05-16 17:34:21 -07005896 mTempViews[i] = null;
Jeff Brown6cb7b462012-03-05 13:21:17 -08005897 }
5898
5899 for (int i = 0; i < viewRectCount; i++) {
5900 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
5901 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08005902 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08005903 }
5904 }
5905
5906 private void postIfNeededLocked() {
5907 if (!mPosted) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005908 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08005909 mPosted = true;
5910 }
5911 }
5912 }
5913 final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
5914 new InvalidateOnAnimationRunnable();
5915
Jeff Browna175a5b2012-02-15 19:18:31 -08005916 public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
5917 Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
5918 mHandler.sendMessageDelayed(msg, delayMilliseconds);
5919 }
5920
Jeff Browna175a5b2012-02-15 19:18:31 -08005921 public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
5922 long delayMilliseconds) {
5923 final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
5924 mHandler.sendMessageDelayed(msg, delayMilliseconds);
5925 }
5926
Jeff Brown6cb7b462012-03-05 13:21:17 -08005927 public void dispatchInvalidateOnAnimation(View view) {
5928 mInvalidateOnAnimationRunnable.addView(view);
5929 }
5930
5931 public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) {
5932 mInvalidateOnAnimationRunnable.addViewRect(info);
5933 }
5934
5935 public void cancelInvalidate(View view) {
5936 mHandler.removeMessages(MSG_INVALIDATE, view);
5937 // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning
5938 // them to the pool
5939 mHandler.removeMessages(MSG_INVALIDATE_RECT, view);
5940 mInvalidateOnAnimationRunnable.removeView(view);
5941 }
5942
keunyoung30f420f2013-08-02 14:23:10 -07005943 public void dispatchInputEvent(InputEvent event) {
Jae Seo6a6059a2014-04-17 21:35:29 -07005944 dispatchInputEvent(event, null);
5945 }
5946
5947 public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
5948 SomeArgs args = SomeArgs.obtain();
5949 args.arg1 = event;
5950 args.arg2 = receiver;
5951 Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
Jeff Browne0dbd002012-02-15 19:34:58 -08005952 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08005953 mHandler.sendMessage(msg);
5954 }
5955
Michael Wright899d7052014-04-23 17:23:39 -07005956 public void synthesizeInputEvent(InputEvent event) {
5957 Message msg = mHandler.obtainMessage(MSG_SYNTHESIZE_INPUT_EVENT, event);
5958 msg.setAsynchronous(true);
5959 mHandler.sendMessage(msg);
5960 }
5961
Jeff Browna175a5b2012-02-15 19:18:31 -08005962 public void dispatchKeyFromIme(KeyEvent event) {
5963 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
Jeff Browne0dbd002012-02-15 19:34:58 -08005964 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08005965 mHandler.sendMessage(msg);
Jeff Browncb1404e2011-01-15 18:14:15 -08005966 }
5967
Michael Wright899d7052014-04-23 17:23:39 -07005968 /**
5969 * Reinject unhandled {@link InputEvent}s in order to synthesize fallbacks events.
5970 *
5971 * Note that it is the responsibility of the caller of this API to recycle the InputEvent it
5972 * passes in.
5973 */
Michael Wright3da28342014-04-22 17:00:11 -07005974 public void dispatchUnhandledInputEvent(InputEvent event) {
Michael Wright899d7052014-04-23 17:23:39 -07005975 if (event instanceof MotionEvent) {
5976 event = MotionEvent.obtain((MotionEvent) event);
Michael Wright3da28342014-04-22 17:00:11 -07005977 }
Michael Wright899d7052014-04-23 17:23:39 -07005978 synthesizeInputEvent(event);
Michael Wright3da28342014-04-22 17:00:11 -07005979 }
5980
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005981 public void dispatchAppVisibility(boolean visible) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005982 Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005983 msg.arg1 = visible ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08005984 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005985 }
5986
5987 public void dispatchGetNewSurface() {
Jeff Browna175a5b2012-02-15 19:18:31 -08005988 Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
5989 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005990 }
5991
5992 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
5993 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08005994 msg.what = MSG_WINDOW_FOCUS_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005995 msg.arg1 = hasFocus ? 1 : 0;
5996 msg.arg2 = inTouchMode ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08005997 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005998 }
5999
Dianne Hackbornffa42482009-09-23 22:20:11 -07006000 public void dispatchCloseSystemDialogs(String reason) {
6001 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08006002 msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
Dianne Hackbornffa42482009-09-23 22:20:11 -07006003 msg.obj = reason;
Jeff Browna175a5b2012-02-15 19:18:31 -08006004 mHandler.sendMessage(msg);
Dianne Hackbornffa42482009-09-23 22:20:11 -07006005 }
Christopher Tatea53146c2010-09-07 11:57:52 -07006006
6007 public void dispatchDragEvent(DragEvent event) {
Chris Tate91e9bb32010-10-12 12:58:43 -07006008 final int what;
6009 if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
Jeff Browna175a5b2012-02-15 19:18:31 -08006010 what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
6011 mHandler.removeMessages(what);
Chris Tate91e9bb32010-10-12 12:58:43 -07006012 } else {
Jeff Browna175a5b2012-02-15 19:18:31 -08006013 what = MSG_DISPATCH_DRAG_EVENT;
Chris Tate91e9bb32010-10-12 12:58:43 -07006014 }
Jeff Browna175a5b2012-02-15 19:18:31 -08006015 Message msg = mHandler.obtainMessage(what, event);
6016 mHandler.sendMessage(msg);
Christopher Tatea53146c2010-09-07 11:57:52 -07006017 }
6018
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006019 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
6020 int localValue, int localChanges) {
6021 SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
6022 args.seq = seq;
6023 args.globalVisibility = globalVisibility;
6024 args.localValue = localValue;
6025 args.localChanges = localChanges;
Jeff Browna175a5b2012-02-15 19:18:31 -08006026 mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
6027 }
6028
Dianne Hackborn12d3a942012-04-27 14:16:30 -07006029 public void dispatchDoneAnimating() {
6030 mHandler.sendEmptyMessage(MSG_DISPATCH_DONE_ANIMATING);
6031 }
6032
Jeff Browna175a5b2012-02-15 19:18:31 -08006033 public void dispatchCheckFocus() {
6034 if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
6035 // This will result in a call to checkFocus() below.
6036 mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
6037 }
Joe Onorato664644d2011-01-23 17:53:23 -08006038 }
6039
svetoslavganov75986cf2009-05-14 22:28:01 -07006040 /**
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006041 * Post a callback to send a
6042 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
Svetoslav Ganova0156172011-06-26 17:55:44 -07006043 * This event is send at most once every
6044 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006045 */
Alan Viverette77e9a282013-09-12 17:16:09 -07006046 private void postSendWindowContentChangedCallback(View source, int changeType) {
Svetoslav Ganova0156172011-06-26 17:55:44 -07006047 if (mSendWindowContentChangedAccessibilityEvent == null) {
6048 mSendWindowContentChangedAccessibilityEvent =
6049 new SendWindowContentChangedAccessibilityEvent();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006050 }
Alan Viverette77e9a282013-09-12 17:16:09 -07006051 mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006052 }
6053
6054 /**
6055 * Remove a posted callback to send a
6056 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
6057 */
6058 private void removeSendWindowContentChangedCallback() {
Svetoslav Ganova0156172011-06-26 17:55:44 -07006059 if (mSendWindowContentChangedAccessibilityEvent != null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08006060 mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006061 }
6062 }
6063
Igor Murashkina86ab6402013-08-30 12:58:36 -07006064 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006065 public boolean showContextMenuForChild(View originalView) {
6066 return false;
6067 }
6068
Igor Murashkina86ab6402013-08-30 12:58:36 -07006069 @Override
Adam Powell6e346362010-07-23 10:18:23 -07006070 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
6071 return null;
6072 }
6073
Igor Murashkina86ab6402013-08-30 12:58:36 -07006074 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006075 public void createContextMenu(ContextMenu menu) {
6076 }
6077
Igor Murashkina86ab6402013-08-30 12:58:36 -07006078 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006079 public void childDrawableStateChanged(View child) {
6080 }
6081
Igor Murashkina86ab6402013-08-30 12:58:36 -07006082 @Override
Svetoslav Ganov736c2752011-04-22 18:30:36 -07006083 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
6084 if (mView == null) {
6085 return false;
6086 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006087 // Intercept accessibility focus events fired by virtual nodes to keep
6088 // track of accessibility focus position in such nodes.
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006089 final int eventType = event.getEventType();
6090 switch (eventType) {
6091 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006092 final long sourceNodeId = event.getSourceNodeId();
6093 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
6094 sourceNodeId);
6095 View source = mView.findViewByAccessibilityId(accessibilityViewId);
6096 if (source != null) {
6097 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
6098 if (provider != null) {
6099 AccessibilityNodeInfo node = provider.createAccessibilityNodeInfo(
6100 AccessibilityNodeInfo.getVirtualDescendantId(sourceNodeId));
6101 setAccessibilityFocus(source, node);
6102 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006103 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006104 } break;
6105 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006106 final long sourceNodeId = event.getSourceNodeId();
6107 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
6108 sourceNodeId);
6109 View source = mView.findViewByAccessibilityId(accessibilityViewId);
6110 if (source != null) {
6111 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
6112 if (provider != null) {
6113 setAccessibilityFocus(null, null);
6114 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006115 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006116 } break;
Svetoslavf0c758b2014-09-03 17:47:37 -07006117
6118
6119 case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: {
6120 if (mAccessibilityFocusedHost != null && mAccessibilityFocusedVirtualView != null) {
6121 // We care only for changes rooted in the focused host.
6122 final long eventSourceId = event.getSourceNodeId();
6123 final int hostViewId = AccessibilityNodeInfo.getAccessibilityViewId(
6124 eventSourceId);
6125 if (hostViewId != mAccessibilityFocusedHost.getAccessibilityViewId()) {
6126 break;
6127 }
6128
6129 // We only care about changes that may change the virtual focused view bounds.
6130 final int changes = event.getContentChangeTypes();
6131 if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) != 0
6132 || changes == AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) {
6133 AccessibilityNodeProvider provider = mAccessibilityFocusedHost
6134 .getAccessibilityNodeProvider();
6135 if (provider != null) {
6136 final int virtualChildId = AccessibilityNodeInfo.getVirtualDescendantId(
6137 mAccessibilityFocusedVirtualView.getSourceNodeId());
6138 mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo(
6139 virtualChildId);
6140 }
6141 }
6142 }
6143 } break;
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006144 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006145 mAccessibilityManager.sendAccessibilityEvent(event);
Svetoslav Ganov736c2752011-04-22 18:30:36 -07006146 return true;
6147 }
6148
Svetoslav Ganov42138042012-03-20 11:51:39 -07006149 @Override
Alan Viverette77e9a282013-09-12 17:16:09 -07006150 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
6151 postSendWindowContentChangedCallback(source, changeType);
Svetoslav Ganov42138042012-03-20 11:51:39 -07006152 }
6153
Fabrice Di Meglio9dd4c5c2013-02-08 18:15:07 -08006154 @Override
6155 public boolean canResolveLayoutDirection() {
6156 return true;
6157 }
6158
6159 @Override
6160 public boolean isLayoutDirectionResolved() {
6161 return true;
6162 }
6163
6164 @Override
6165 public int getLayoutDirection() {
6166 return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT;
6167 }
6168
6169 @Override
6170 public boolean canResolveTextDirection() {
6171 return true;
6172 }
6173
6174 @Override
6175 public boolean isTextDirectionResolved() {
6176 return true;
6177 }
6178
6179 @Override
6180 public int getTextDirection() {
6181 return View.TEXT_DIRECTION_RESOLVED_DEFAULT;
6182 }
6183
6184 @Override
6185 public boolean canResolveTextAlignment() {
6186 return true;
6187 }
6188
6189 @Override
6190 public boolean isTextAlignmentResolved() {
6191 return true;
6192 }
6193
6194 @Override
6195 public int getTextAlignment() {
6196 return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT;
6197 }
6198
Svetoslav Ganov42138042012-03-20 11:51:39 -07006199 private View getCommonPredecessor(View first, View second) {
Chris Craikd36a81f2014-07-17 10:16:51 -07006200 if (mTempHashSet == null) {
6201 mTempHashSet = new HashSet<View>();
Svetoslav Ganov42138042012-03-20 11:51:39 -07006202 }
Chris Craikd36a81f2014-07-17 10:16:51 -07006203 HashSet<View> seen = mTempHashSet;
6204 seen.clear();
6205 View firstCurrent = first;
6206 while (firstCurrent != null) {
6207 seen.add(firstCurrent);
6208 ViewParent firstCurrentParent = firstCurrent.mParent;
6209 if (firstCurrentParent instanceof View) {
6210 firstCurrent = (View) firstCurrentParent;
6211 } else {
6212 firstCurrent = null;
6213 }
6214 }
6215 View secondCurrent = second;
6216 while (secondCurrent != null) {
6217 if (seen.contains(secondCurrent)) {
6218 seen.clear();
6219 return secondCurrent;
6220 }
6221 ViewParent secondCurrentParent = secondCurrent.mParent;
6222 if (secondCurrentParent instanceof View) {
6223 secondCurrent = (View) secondCurrentParent;
6224 } else {
6225 secondCurrent = null;
6226 }
6227 }
6228 seen.clear();
Svetoslav Ganov42138042012-03-20 11:51:39 -07006229 return null;
6230 }
6231
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006232 void checkThread() {
6233 if (mThread != Thread.currentThread()) {
6234 throw new CalledFromWrongThreadException(
6235 "Only the original thread that created a view hierarchy can touch its views.");
6236 }
6237 }
6238
Igor Murashkina86ab6402013-08-30 12:58:36 -07006239 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006240 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Joe Onoratoc6cc0f82011-04-12 11:53:13 -07006241 // ViewAncestor never intercepts touch event, so this can be a no-op
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006242 }
6243
Igor Murashkina86ab6402013-08-30 12:58:36 -07006244 @Override
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07006245 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
6246 final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
6247 if (rectangle != null) {
6248 mTempRect.set(rectangle);
6249 mTempRect.offset(0, -mCurScrollY);
6250 mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
6251 try {
Svetoslavf7174e82014-06-12 11:29:35 -07006252 mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect);
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07006253 } catch (RemoteException re) {
6254 /* ignore */
6255 }
6256 }
6257 return scrolled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006258 }
Romain Guy8506ab42009-06-11 17:35:47 -07006259
Igor Murashkina86ab6402013-08-30 12:58:36 -07006260 @Override
Adam Powell539ee872012-02-03 19:00:49 -08006261 public void childHasTransientStateChanged(View child, boolean hasTransientState) {
6262 // Do nothing.
6263 }
6264
Adam Powell10ba2772014-04-15 09:46:51 -07006265 @Override
6266 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
6267 return false;
6268 }
6269
6270 @Override
6271 public void onStopNestedScroll(View target) {
6272 }
6273
6274 @Override
6275 public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
6276 }
6277
6278 @Override
6279 public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
6280 int dxUnconsumed, int dyUnconsumed) {
6281 }
6282
6283 @Override
6284 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
6285 }
6286
6287 @Override
Adam Powellb36e4f92014-05-01 10:23:33 -07006288 public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
Adam Powell10ba2772014-04-15 09:46:51 -07006289 return false;
6290 }
6291
Adam Powellb72be592014-07-16 21:41:31 -07006292 @Override
6293 public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
6294 return false;
6295 }
6296
Craig Mautnerbc57cd12013-08-19 15:47:42 -07006297 void changeCanvasOpacity(boolean opaque) {
Craig Mautnerbc57cd12013-08-19 15:47:42 -07006298 Log.d(TAG, "changeCanvasOpacity: opaque=" + opaque);
John Reck63a06672014-05-07 13:45:54 -07006299 if (mAttachInfo.mHardwareRenderer != null) {
6300 mAttachInfo.mHardwareRenderer.setOpaque(opaque);
6301 }
Craig Mautnerbc57cd12013-08-19 15:47:42 -07006302 }
6303
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006304 class TakenSurfaceHolder extends BaseSurfaceHolder {
6305 @Override
6306 public boolean onAllowLockCanvas() {
6307 return mDrawingAllowed;
6308 }
6309
6310 @Override
6311 public void onRelayoutContainer() {
6312 // Not currently interesting -- from changing between fixed and layout size.
6313 }
6314
Igor Murashkina86ab6402013-08-30 12:58:36 -07006315 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006316 public void setFormat(int format) {
6317 ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
6318 }
6319
Igor Murashkina86ab6402013-08-30 12:58:36 -07006320 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006321 public void setType(int type) {
6322 ((RootViewSurfaceTaker)mView).setSurfaceType(type);
6323 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006324
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006325 @Override
6326 public void onUpdateSurface() {
6327 // We take care of format and type changes on our own.
6328 throw new IllegalStateException("Shouldn't be here");
6329 }
6330
Igor Murashkina86ab6402013-08-30 12:58:36 -07006331 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006332 public boolean isCreating() {
6333 return mIsCreating;
6334 }
6335
6336 @Override
6337 public void setFixedSize(int width, int height) {
6338 throw new UnsupportedOperationException(
6339 "Currently only support sizing from layout");
6340 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006341
6342 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006343 public void setKeepScreenOn(boolean screenOn) {
6344 ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
6345 }
6346 }
Romain Guy8506ab42009-06-11 17:35:47 -07006347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006348 static class W extends IWindow.Stub {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006349 private final WeakReference<ViewRootImpl> mViewAncestor;
Jeff Brown98365d72012-08-19 20:30:52 -07006350 private final IWindowSession mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006351
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006352 W(ViewRootImpl viewAncestor) {
6353 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
Jeff Brown98365d72012-08-19 20:30:52 -07006354 mWindowSession = viewAncestor.mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006355 }
6356
Igor Murashkina86ab6402013-08-30 12:58:36 -07006357 @Override
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006358 public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Adrian Roosfa104232014-06-20 16:10:14 -07006359 Rect visibleInsets, Rect stableInsets, boolean reportDraw,
6360 Configuration newConfig) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006361 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006362 if (viewAncestor != null) {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006363 viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
Adrian Roosfa104232014-06-20 16:10:14 -07006364 visibleInsets, stableInsets, reportDraw, newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006365 }
6366 }
6367
Craig Mautner5702d4d2012-06-30 14:10:16 -07006368 @Override
6369 public void moved(int newX, int newY) {
6370 final ViewRootImpl viewAncestor = mViewAncestor.get();
6371 if (viewAncestor != null) {
6372 viewAncestor.dispatchMoved(newX, newY);
6373 }
6374 }
6375
Igor Murashkina86ab6402013-08-30 12:58:36 -07006376 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006377 public void dispatchAppVisibility(boolean visible) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006378 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006379 if (viewAncestor != null) {
6380 viewAncestor.dispatchAppVisibility(visible);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006381 }
6382 }
6383
Igor Murashkina86ab6402013-08-30 12:58:36 -07006384 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006385 public void dispatchGetNewSurface() {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006386 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006387 if (viewAncestor != null) {
6388 viewAncestor.dispatchGetNewSurface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006389 }
6390 }
6391
Igor Murashkina86ab6402013-08-30 12:58:36 -07006392 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006393 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006394 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006395 if (viewAncestor != null) {
6396 viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006397 }
6398 }
6399
6400 private static int checkCallingPermission(String permission) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006401 try {
6402 return ActivityManagerNative.getDefault().checkPermission(
6403 permission, Binder.getCallingPid(), Binder.getCallingUid());
6404 } catch (RemoteException e) {
6405 return PackageManager.PERMISSION_DENIED;
6406 }
6407 }
6408
Igor Murashkina86ab6402013-08-30 12:58:36 -07006409 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006410 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006411 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006412 if (viewAncestor != null) {
6413 final View view = viewAncestor.mView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006414 if (view != null) {
6415 if (checkCallingPermission(Manifest.permission.DUMP) !=
6416 PackageManager.PERMISSION_GRANTED) {
6417 throw new SecurityException("Insufficient permissions to invoke"
6418 + " executeCommand() from pid=" + Binder.getCallingPid()
6419 + ", uid=" + Binder.getCallingUid());
6420 }
6421
6422 OutputStream clientStream = null;
6423 try {
6424 clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
6425 ViewDebug.dispatchCommand(view, command, parameters, clientStream);
6426 } catch (IOException e) {
6427 e.printStackTrace();
6428 } finally {
6429 if (clientStream != null) {
6430 try {
6431 clientStream.close();
6432 } catch (IOException e) {
6433 e.printStackTrace();
6434 }
6435 }
6436 }
6437 }
6438 }
6439 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006440
6441 @Override
Dianne Hackbornffa42482009-09-23 22:20:11 -07006442 public void closeSystemDialogs(String reason) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006443 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006444 if (viewAncestor != null) {
6445 viewAncestor.dispatchCloseSystemDialogs(reason);
Dianne Hackbornffa42482009-09-23 22:20:11 -07006446 }
6447 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006448
6449 @Override
Marco Nelissenbf6956b2009-11-09 15:21:13 -08006450 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
6451 boolean sync) {
Dianne Hackborn19382ac2009-09-11 21:13:37 -07006452 if (sync) {
6453 try {
Jeff Brown98365d72012-08-19 20:30:52 -07006454 mWindowSession.wallpaperOffsetsComplete(asBinder());
Dianne Hackborn19382ac2009-09-11 21:13:37 -07006455 } catch (RemoteException e) {
6456 }
6457 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07006458 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006459
Igor Murashkina86ab6402013-08-30 12:58:36 -07006460 @Override
Dianne Hackborn75804932009-10-20 20:15:20 -07006461 public void dispatchWallpaperCommand(String action, int x, int y,
6462 int z, Bundle extras, boolean sync) {
6463 if (sync) {
6464 try {
Jeff Brown98365d72012-08-19 20:30:52 -07006465 mWindowSession.wallpaperCommandComplete(asBinder(), null);
Dianne Hackborn75804932009-10-20 20:15:20 -07006466 } catch (RemoteException e) {
6467 }
6468 }
6469 }
Christopher Tatea53146c2010-09-07 11:57:52 -07006470
6471 /* Drag/drop */
Igor Murashkina86ab6402013-08-30 12:58:36 -07006472 @Override
Christopher Tatea53146c2010-09-07 11:57:52 -07006473 public void dispatchDragEvent(DragEvent event) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006474 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006475 if (viewAncestor != null) {
6476 viewAncestor.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07006477 }
6478 }
Joe Onorato664644d2011-01-23 17:53:23 -08006479
Igor Murashkina86ab6402013-08-30 12:58:36 -07006480 @Override
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006481 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
6482 int localValue, int localChanges) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006483 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006484 if (viewAncestor != null) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006485 viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility,
6486 localValue, localChanges);
Joe Onorato664644d2011-01-23 17:53:23 -08006487 }
6488 }
Dianne Hackborn12d3a942012-04-27 14:16:30 -07006489
Igor Murashkina86ab6402013-08-30 12:58:36 -07006490 @Override
Dianne Hackborn12d3a942012-04-27 14:16:30 -07006491 public void doneAnimating() {
6492 final ViewRootImpl viewAncestor = mViewAncestor.get();
6493 if (viewAncestor != null) {
6494 viewAncestor.dispatchDoneAnimating();
6495 }
6496 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006497 }
6498
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006499 public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
6500 public CalledFromWrongThreadException(String msg) {
6501 super(msg);
6502 }
6503 }
6504
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006505 static RunQueue getRunQueue() {
6506 RunQueue rq = sRunQueues.get();
6507 if (rq != null) {
6508 return rq;
6509 }
6510 rq = new RunQueue();
6511 sRunQueues.set(rq);
6512 return rq;
6513 }
Romain Guy8506ab42009-06-11 17:35:47 -07006514
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006515 /**
Jeff Browna175a5b2012-02-15 19:18:31 -08006516 * The run queue is used to enqueue pending work from Views when no Handler is
6517 * attached. The work is executed during the next call to performTraversals on
6518 * the thread.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006519 * @hide
6520 */
6521 static final class RunQueue {
6522 private final ArrayList<HandlerAction> mActions = new ArrayList<HandlerAction>();
6523
6524 void post(Runnable action) {
6525 postDelayed(action, 0);
6526 }
6527
6528 void postDelayed(Runnable action, long delayMillis) {
6529 HandlerAction handlerAction = new HandlerAction();
6530 handlerAction.action = action;
6531 handlerAction.delay = delayMillis;
6532
6533 synchronized (mActions) {
6534 mActions.add(handlerAction);
6535 }
6536 }
6537
6538 void removeCallbacks(Runnable action) {
6539 final HandlerAction handlerAction = new HandlerAction();
6540 handlerAction.action = action;
6541
6542 synchronized (mActions) {
6543 final ArrayList<HandlerAction> actions = mActions;
6544
6545 while (actions.remove(handlerAction)) {
6546 // Keep going
6547 }
6548 }
6549 }
6550
6551 void executeActions(Handler handler) {
6552 synchronized (mActions) {
6553 final ArrayList<HandlerAction> actions = mActions;
6554 final int count = actions.size();
6555
6556 for (int i = 0; i < count; i++) {
6557 final HandlerAction handlerAction = actions.get(i);
6558 handler.postDelayed(handlerAction.action, handlerAction.delay);
6559 }
6560
Romain Guy15df6702009-08-17 20:17:30 -07006561 actions.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006562 }
6563 }
6564
6565 private static class HandlerAction {
6566 Runnable action;
6567 long delay;
6568
6569 @Override
6570 public boolean equals(Object o) {
6571 if (this == o) return true;
6572 if (o == null || getClass() != o.getClass()) return false;
6573
6574 HandlerAction that = (HandlerAction) o;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006575 return !(action != null ? !action.equals(that.action) : that.action != null);
6576
6577 }
6578
6579 @Override
6580 public int hashCode() {
6581 int result = action != null ? action.hashCode() : 0;
6582 result = 31 * result + (int) (delay ^ (delay >>> 32));
6583 return result;
6584 }
6585 }
6586 }
6587
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006588 /**
6589 * Class for managing the accessibility interaction connection
6590 * based on the global accessibility state.
6591 */
6592 final class AccessibilityInteractionConnectionManager
6593 implements AccessibilityStateChangeListener {
Igor Murashkina86ab6402013-08-30 12:58:36 -07006594 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006595 public void onAccessibilityStateChanged(boolean enabled) {
6596 if (enabled) {
6597 ensureConnection();
Chris Craikcce47eb2014-07-16 15:12:15 -07006598 if (mAttachInfo.mHasWindowFocus) {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006599 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
6600 View focusedView = mView.findFocus();
6601 if (focusedView != null && focusedView != mView) {
6602 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
6603 }
6604 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006605 } else {
6606 ensureNoConnection();
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07006607 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006608 }
6609 }
6610
6611 public void ensureConnection() {
Chris Craikcce47eb2014-07-16 15:12:15 -07006612 final boolean registered =
Svetoslav8e3feb12014-02-24 13:46:47 -08006613 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
Chris Craikcce47eb2014-07-16 15:12:15 -07006614 if (!registered) {
6615 mAttachInfo.mAccessibilityWindowId =
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006616 mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
6617 new AccessibilityInteractionConnection(ViewRootImpl.this));
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006618 }
6619 }
6620
6621 public void ensureNoConnection() {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006622 final boolean registered =
Svetoslav8e3feb12014-02-24 13:46:47 -08006623 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006624 if (registered) {
Svetoslav8e3feb12014-02-24 13:46:47 -08006625 mAttachInfo.mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006626 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
6627 }
6628 }
6629 }
6630
Chris Craikcce47eb2014-07-16 15:12:15 -07006631 final class HighContrastTextManager implements HighTextContrastChangeListener {
6632 HighContrastTextManager() {
6633 mAttachInfo.mHighContrastText = mAccessibilityManager.isHighTextContrastEnabled();
6634 }
6635 @Override
6636 public void onHighTextContrastStateChanged(boolean enabled) {
6637 mAttachInfo.mHighContrastText = enabled;
6638
6639 // Destroy Displaylists so they can be recreated with high contrast recordings
6640 destroyHardwareResources();
Chris Craikd36a81f2014-07-17 10:16:51 -07006641
6642 // Schedule redraw, which will rerecord + redraw all text
6643 invalidate();
Chris Craikcce47eb2014-07-16 15:12:15 -07006644 }
6645 }
6646
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006647 /**
6648 * This class is an interface this ViewAncestor provides to the
6649 * AccessibilityManagerService to the latter can interact with
6650 * the view hierarchy in this ViewAncestor.
6651 */
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006652 static final class AccessibilityInteractionConnection
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006653 extends IAccessibilityInteractionConnection.Stub {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006654 private final WeakReference<ViewRootImpl> mViewRootImpl;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006655
Svetoslav Ganovf79f4762011-10-28 15:40:32 -07006656 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) {
6657 mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006658 }
6659
Svetoslav Ganov42138042012-03-20 11:51:39 -07006660 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07006661 public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07006662 Region interactiveRegion, int interactionId,
6663 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006664 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006665 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6666 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006667 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov02107852011-10-03 17:06:56 -07006668 .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07006669 interactiveRegion, interactionId, callback, flags, interrogatingPid,
6670 interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006671 } else {
6672 // We cannot make the call and notify the caller so it does not wait.
6673 try {
6674 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
6675 } catch (RemoteException re) {
6676 /* best effort - ignore */
6677 }
Svetoslav Ganov601ad802011-06-09 14:47:38 -07006678 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006679 }
6680
Svetoslav Ganov42138042012-03-20 11:51:39 -07006681 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07006682 public void performAccessibilityAction(long accessibilityNodeId, int action,
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07006683 Bundle arguments, int interactionId,
6684 IAccessibilityInteractionConnectionCallback callback, int flags,
Svet Ganov7498efd2014-09-03 21:33:00 -07006685 int interrogatingPid, long interrogatingTid) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006686 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6687 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006688 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07006689 .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
Svet Ganov7498efd2014-09-03 21:33:00 -07006690 interactionId, callback, flags, interrogatingPid, interrogatingTid);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006691 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006692 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006693 try {
6694 callback.setPerformAccessibilityActionResult(false, interactionId);
6695 } catch (RemoteException re) {
6696 /* best effort - ignore */
6697 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006698 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006699 }
6700
Svetoslav Ganov42138042012-03-20 11:51:39 -07006701 @Override
Svet Ganov7498efd2014-09-03 21:33:00 -07006702 public void computeClickPointInScreen(long accessibilityNodeId, Region interactiveRegion,
6703 int interactionId, IAccessibilityInteractionConnectionCallback callback,
6704 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
6705 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6706 if (viewRootImpl != null && viewRootImpl.mView != null) {
6707 viewRootImpl.getAccessibilityInteractionController()
6708 .computeClickPointInScreenClientThread(accessibilityNodeId,
6709 interactiveRegion, interactionId, callback, interrogatingPid,
6710 interrogatingTid, spec);
6711 } else {
6712 // We cannot make the call and notify the caller so it does not wait.
6713 try {
6714 callback.setComputeClickPointInScreenActionResult(null, interactionId);
6715 } catch (RemoteException re) {
6716 /* best effort - ignore */
6717 }
6718 }
6719 }
6720
6721 @Override
Svetoslav Ganov80943d82013-01-02 10:25:37 -08006722 public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07006723 String viewId, Region interactiveRegion, int interactionId,
Svetoslav Ganov80943d82013-01-02 10:25:37 -08006724 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006725 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006726 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6727 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006728 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov80943d82013-01-02 10:25:37 -08006729 .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07006730 viewId, interactiveRegion, interactionId, callback, flags,
6731 interrogatingPid, interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006732 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006733 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006734 try {
6735 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
6736 } catch (RemoteException re) {
6737 /* best effort - ignore */
6738 }
6739 }
6740 }
6741
Svetoslav Ganov42138042012-03-20 11:51:39 -07006742 @Override
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006743 public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
Svetoslav9ae9ed22014-09-02 16:36:35 -07006744 Region interactiveRegion, int interactionId,
6745 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006746 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006747 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6748 if (viewRootImpl != null && viewRootImpl.mView != null) {
6749 viewRootImpl.getAccessibilityInteractionController()
6750 .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
Svetoslav9ae9ed22014-09-02 16:36:35 -07006751 interactiveRegion, interactionId, callback, flags, interrogatingPid,
6752 interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006753 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006754 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006755 try {
6756 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
6757 } catch (RemoteException re) {
6758 /* best effort - ignore */
6759 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006760 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006761 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006762
Svetoslav Ganov42138042012-03-20 11:51:39 -07006763 @Override
Svetoslav9ae9ed22014-09-02 16:36:35 -07006764 public void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion,
6765 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006766 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006767 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6768 if (viewRootImpl != null && viewRootImpl.mView != null) {
6769 viewRootImpl.getAccessibilityInteractionController()
Svetoslav9ae9ed22014-09-02 16:36:35 -07006770 .findFocusClientThread(accessibilityNodeId, focusType, interactiveRegion,
6771 interactionId, callback, flags, interrogatingPid, interrogatingTid,
6772 spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07006773 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006774 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006775 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006776 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006777 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006778 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006779 }
6780 }
6781 }
6782
Svetoslav Ganov42138042012-03-20 11:51:39 -07006783 @Override
Svetoslav9ae9ed22014-09-02 16:36:35 -07006784 public void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion,
6785 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006786 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006787 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6788 if (viewRootImpl != null && viewRootImpl.mView != null) {
6789 viewRootImpl.getAccessibilityInteractionController()
Svetoslav9ae9ed22014-09-02 16:36:35 -07006790 .focusSearchClientThread(accessibilityNodeId, direction, interactiveRegion,
6791 interactionId, callback, flags, interrogatingPid, interrogatingTid,
6792 spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07006793 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006794 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006795 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006796 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006797 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006798 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006799 }
6800 }
6801 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006802 }
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006803
Svetoslav Ganova0156172011-06-26 17:55:44 -07006804 private class SendWindowContentChangedAccessibilityEvent implements Runnable {
Alan Viverette77e9a282013-09-12 17:16:09 -07006805 private int mChangeTypes = 0;
6806
Svetoslav Ganov42138042012-03-20 11:51:39 -07006807 public View mSource;
Svetoslav6254f482013-06-04 17:22:14 -07006808 public long mLastEventTimeMillis;
Svetoslav Ganova0156172011-06-26 17:55:44 -07006809
Igor Murashkina86ab6402013-08-30 12:58:36 -07006810 @Override
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006811 public void run() {
Svetoslav8d820ecf2013-07-15 17:12:41 -07006812 // The accessibility may be turned off while we were waiting so check again.
6813 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
6814 mLastEventTimeMillis = SystemClock.uptimeMillis();
6815 AccessibilityEvent event = AccessibilityEvent.obtain();
6816 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
Alan Viverette77e9a282013-09-12 17:16:09 -07006817 event.setContentChangeTypes(mChangeTypes);
Svetoslav8d820ecf2013-07-15 17:12:41 -07006818 mSource.sendAccessibilityEventUnchecked(event);
6819 } else {
6820 mLastEventTimeMillis = 0;
6821 }
6822 // In any case reset to initial state.
Svetoslav6254f482013-06-04 17:22:14 -07006823 mSource.resetSubtreeAccessibilityStateChanged();
6824 mSource = null;
Alan Viverette77e9a282013-09-12 17:16:09 -07006825 mChangeTypes = 0;
Svetoslav6254f482013-06-04 17:22:14 -07006826 }
6827
Alan Viverette77e9a282013-09-12 17:16:09 -07006828 public void runOrPost(View source, int changeType) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006829 if (mSource != null) {
Svetoslav9dafebb2013-06-18 16:29:25 -07006830 // If there is no common predecessor, then mSource points to
6831 // a removed view, hence in this case always prefer the source.
6832 View predecessor = getCommonPredecessor(mSource, source);
6833 mSource = (predecessor != null) ? predecessor : source;
Alan Viverette77e9a282013-09-12 17:16:09 -07006834 mChangeTypes |= changeType;
Svetoslav6254f482013-06-04 17:22:14 -07006835 return;
6836 }
6837 mSource = source;
Alan Viverette77e9a282013-09-12 17:16:09 -07006838 mChangeTypes = changeType;
Svetoslav6254f482013-06-04 17:22:14 -07006839 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
6840 final long minEventIntevalMillis =
6841 ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
6842 if (timeSinceLastMillis >= minEventIntevalMillis) {
Svetoslav9dafebb2013-06-18 16:29:25 -07006843 mSource.removeCallbacks(this);
Svetoslav6254f482013-06-04 17:22:14 -07006844 run();
6845 } else {
6846 mSource.postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08006847 }
6848 }
6849 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006850}