blob: afe2f1061f3abde5949425058519393930ac7acf [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
Jorim Jaggia4a58ef2016-01-27 02:10:08 -080019import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -080020import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
Jorim Jaggi2e95a482016-01-14 17:36:55 -080021import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
Chong Zhangf6525ce2016-01-14 17:09:56 -080022import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
23import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
24import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -080025
Romain Guy6b7bd242010-10-06 19:49:23 -070026import android.Manifest;
Chet Haasecca2c982011-05-20 14:34:18 -070027import android.animation.LayoutTransition;
Romain Guy6b7bd242010-10-06 19:49:23 -070028import android.app.ActivityManagerNative;
29import android.content.ClipDescription;
30import android.content.ComponentCallbacks;
31import android.content.Context;
32import android.content.pm.PackageManager;
33import android.content.res.CompatibilityInfo;
34import android.content.res.Configuration;
35import android.content.res.Resources;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.graphics.Canvas;
Alan Viverettefed3f722013-11-14 14:48:20 -080037import android.graphics.Matrix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.graphics.PixelFormat;
Christopher Tate2c095f32010-10-04 14:13:40 -070039import android.graphics.Point;
Christopher Tatea53146c2010-09-07 11:57:52 -070040import android.graphics.PointF;
Romain Guy6b7bd242010-10-06 19:49:23 -070041import android.graphics.PorterDuff;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.graphics.Rect;
43import android.graphics.Region;
Svetoslav Ganov42138042012-03-20 11:51:39 -070044import android.graphics.drawable.Drawable;
Jeff Brownd912e1f2014-04-11 18:46:22 -070045import android.hardware.display.DisplayManager;
46import android.hardware.display.DisplayManager.DisplayListener;
Jun Mukai347e5d42015-12-03 01:13:31 -080047import android.hardware.input.InputManager;
Romain Guy6b7bd242010-10-06 19:49:23 -070048import android.media.AudioManager;
49import android.os.Binder;
Michael Wright5bd69e62015-05-14 14:48:08 +010050import android.os.Build;
Romain Guy6b7bd242010-10-06 19:49:23 -070051import android.os.Bundle;
52import android.os.Debug;
53import android.os.Handler;
Romain Guy6b7bd242010-10-06 19:49:23 -070054import android.os.Looper;
55import android.os.Message;
56import android.os.ParcelFileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import android.os.Process;
Romain Guy6b7bd242010-10-06 19:49:23 -070058import android.os.RemoteException;
Romain Guy6b7bd242010-10-06 19:49:23 -070059import android.os.SystemClock;
Romain Guy59a12ca2011-06-09 17:48:21 -070060import android.os.SystemProperties;
Jeff Brown481c1572012-03-09 14:41:15 -080061import android.os.Trace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.util.AndroidRuntimeException;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070063import android.util.DisplayMetrics;
Romain Guy6b7bd242010-10-06 19:49:23 -070064import android.util.Log;
Chet Haase949dbf72010-08-11 18:41:06 -070065import android.util.Slog;
John Reckba6adf62015-02-19 14:36:50 -080066import android.util.TimeUtils;
Dianne Hackborn711e62a2010-11-29 16:38:22 -080067import android.util.TypedValue;
John Reck44fd8d22014-02-26 11:00:11 -080068import android.view.Surface.OutOfResourcesException;
Jeff Browna175a5b2012-02-15 19:18:31 -080069import android.view.View.AttachInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070import android.view.View.MeasureSpec;
svetoslavganov75986cf2009-05-14 22:28:01 -070071import android.view.accessibility.AccessibilityEvent;
72import android.view.accessibility.AccessibilityManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070073import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
Chris Craikcce47eb2014-07-16 15:12:15 -070074import android.view.accessibility.AccessibilityManager.HighTextContrastChangeListener;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070075import android.view.accessibility.AccessibilityNodeInfo;
Alan Viverette25acc7e2015-05-19 11:32:08 -070076import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
Svetoslav Ganov02107852011-10-03 17:06:56 -070077import android.view.accessibility.AccessibilityNodeProvider;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070078import android.view.accessibility.IAccessibilityInteractionConnection;
79import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
Dianne Hackborn0f761d62010-11-30 22:06:10 -080080import android.view.animation.AccelerateDecelerateInterpolator;
81import android.view.animation.Interpolator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082import android.view.inputmethod.InputConnection;
83import android.view.inputmethod.InputMethodManager;
84import android.widget.Scroller;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070085
Svetoslav Ganov42138042012-03-20 11:51:39 -070086import com.android.internal.R;
Clara Bayarri75e09792015-07-29 16:20:40 +010087import com.android.internal.os.IResultReceiver;
Svetoslav Ganov758143e2012-08-06 16:40:27 -070088import com.android.internal.os.SomeArgs;
Adam Powell6711f3b2015-05-06 15:57:09 -070089import com.android.internal.policy.PhoneFallbackEventHandler;
Romain Guy6b7bd242010-10-06 19:49:23 -070090import com.android.internal.view.BaseSurfaceHolder;
Romain Guy6b7bd242010-10-06 19:49:23 -070091import com.android.internal.view.RootViewSurfaceTaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092
Jeff Brown5182c782013-10-15 20:31:52 -070093import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094import java.io.IOException;
95import java.io.OutputStream;
Jeff Brown5182c782013-10-15 20:31:52 -070096import java.io.PrintWriter;
Romain Guy6b7bd242010-10-06 19:49:23 -070097import java.lang.ref.WeakReference;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098import java.util.ArrayList;
Chong Zhang8dbd9ad2015-10-09 10:06:11 -070099import java.util.concurrent.CountDownLatch;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700100import java.util.HashSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102/**
103 * The top of a view hierarchy, implementing the needed protocol between View
104 * and the WindowManager. This is for the most part an internal implementation
Jeff Brown98365d72012-08-19 20:30:52 -0700105 * detail of {@link WindowManagerGlobal}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 *
107 * {@hide}
108 */
Romain Guy812ccbe2010-06-01 14:07:24 -0700109@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
Jeff Browna175a5b2012-02-15 19:18:31 -0800110public final class ViewRootImpl implements ViewParent,
John Reck51aaf902015-12-02 15:08:07 -0800111 View.AttachInfo.Callbacks, ThreadedRenderer.HardwareDrawCallbacks {
Dianne Hackborn70a3f672011-08-08 14:32:41 -0700112 private static final String TAG = "ViewRootImpl";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113 private static final boolean DBG = false;
Romain Guy812ccbe2010-06-01 14:07:24 -0700114 private static final boolean LOCAL_LOGV = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 /** @noinspection PointlessBooleanExpression*/
116 private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
117 private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800118 private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
120 private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
121 private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
122 private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700123 private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
Chet Haase2f2022a2011-10-11 06:41:59 -0700124 private static final boolean DEBUG_FPS = false;
Michael Wright06a79252014-05-05 17:45:29 -0700125 private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126
Romain Guy59a12ca2011-06-09 17:48:21 -0700127 /**
Skuhneb8160872015-09-22 09:51:39 -0700128 * Set to false if we do not want to use the multi threaded renderer. Note that by disabling
129 * this, WindowCallbacks will not fire.
130 */
131 private static final boolean USE_MT_RENDERER = true;
132
133 /**
Romain Guy59a12ca2011-06-09 17:48:21 -0700134 * Set this system property to true to force the view hierarchy to render
135 * at 60 Hz. This can be used to measure the potential framerate.
136 */
Romain Guye9bc11f2013-05-23 12:47:26 -0700137 private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering";
Michael Chan53071d62009-05-13 17:29:48 -0700138
Griff Hazena0938022015-03-13 10:01:41 -0700139 // properties used by emulator to determine display shape
Griff Hazena0938022015-03-13 10:01:41 -0700140 public static final String PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX =
141 "ro.emu.win_outset_bottom_px";
Michael Kolb437d3132014-06-20 13:28:44 -0700142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 /**
144 * Maximum time we allow the user to roll the trackball enough to generate
145 * a key event, before resetting the counters.
146 */
147 static final int MAX_TRACKBALL_DELAY = 250;
148
Jorim Jaggi4846ee32016-01-07 17:39:12 +0100149 private static final int RESIZE_MODE_FREEFORM = 0;
150 private static final int RESIZE_MODE_DOCKED_DIVIDER = 1;
151
Alan Viverettebea0c7da2015-09-01 16:00:20 -0400152 static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153
Skuhneb8160872015-09-22 09:51:39 -0700154 static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList();
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800155 static boolean sFirstDrawComplete = false;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700156
Skuhneb8160872015-09-22 09:51:39 -0700157 static final ArrayList<ComponentCallbacks> sConfigCallbacks = new ArrayList();
Romain Guy59a12ca2011-06-09 17:48:21 -0700158
Chong Zhangdcee1de2015-10-06 10:26:00 -0700159 final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList();
Jeff Brownf9e989d2013-04-04 23:04:03 -0700160 final Context mContext;
Jeff Brown98365d72012-08-19 20:30:52 -0700161 final IWindowSession mWindowSession;
162 final Display mDisplay;
Jeff Brownd912e1f2014-04-11 18:46:22 -0700163 final DisplayManager mDisplayManager;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800164 final String mBasePackageName;
Jeff Brown98365d72012-08-19 20:30:52 -0700165
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 final int[] mTmpLocation = new int[2];
Romain Guy8506ab42009-06-11 17:35:47 -0700167
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800168 final TypedValue mTmpValue = new TypedValue();
Jeff Brownf9e989d2013-04-04 23:04:03 -0700169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 final Thread mThread;
171
172 final WindowLeaked mLocation;
173
174 final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
175
176 final W mWindow;
177
Dianne Hackborn180c4842011-09-13 12:39:25 -0700178 final int mTargetSdkVersion;
179
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700180 int mSeq;
181
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 View mView;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700183
184 View mAccessibilityFocusedHost;
185 AccessibilityNodeInfo mAccessibilityFocusedVirtualView;
186
Jun Mukai347e5d42015-12-03 01:13:31 -0800187 // The view which captures mouse input, or null when no one is capturing.
188 View mCapturingView;
189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 int mViewVisibility;
191 boolean mAppVisible = true;
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800192 // For recents to freeform transition we need to keep drawing after the app receives information
193 // that it became invisible. This will ignore that information and depend on the decor view
194 // visibility to control drawing. The decor view visibility will get adjusted when the app get
195 // stopped and that's when the app will stop drawing further frames.
196 private boolean mForceDecorViewVisibility = false;
Dianne Hackborn180c4842011-09-13 12:39:25 -0700197 int mOrigWindowType = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198
Alan Viverette64bf97a2015-09-18 16:42:00 -0400199 /** Whether the window had focus during the most recent traversal. */
200 boolean mHadWindowFocus;
201
202 /**
203 * Whether the window lost focus during a previous traversal and has not
204 * yet gained it back. Used to determine whether a WINDOW_STATE_CHANGE
205 * accessibility events should be sent during traversal.
206 */
207 boolean mLostWindowFocus;
208
Dianne Hackbornce418e62011-03-01 14:31:38 -0800209 // Set to true if the owner of this window is in the stopped state,
210 // so the window should no longer be active.
211 boolean mStopped = false;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700212
Daniel Koulomzin087ae472015-12-16 17:52:25 -0500213 // Set to true if the owner of this window is in ambient mode,
214 // which means it won't receive input events.
215 boolean mIsAmbientMode = false;
216
George Mount41725de2015-04-09 08:23:05 -0700217 // Set to true to stop input during an Activity Transition.
218 boolean mPausedForTransition = false;
219
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700220 boolean mLastInCompatMode = false;
221
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700222 SurfaceHolder.Callback2 mSurfaceHolderCallback;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700223 BaseSurfaceHolder mSurfaceHolder;
224 boolean mIsCreating;
225 boolean mDrawingAllowed;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227 final Region mTransparentRegion;
228 final Region mPreviousTransparentRegion;
229
230 int mWidth;
231 int mHeight;
Romain Guy7d7b5492011-01-24 16:33:45 -0800232 Rect mDirty;
Romain Guybb93d552009-03-24 21:04:15 -0700233 boolean mIsAnimating;
Romain Guy8506ab42009-06-11 17:35:47 -0700234
Chong Zhang0275e392015-09-17 10:41:44 -0700235 private boolean mDragResizing;
Jorim Jaggi4846ee32016-01-07 17:39:12 +0100236 private int mResizeMode;
Chong Zhang0275e392015-09-17 10:41:44 -0700237 private int mCanvasOffsetX;
238 private int mCanvasOffsetY;
Jorim Jaggi4846ee32016-01-07 17:39:12 +0100239 private boolean mActivityRelaunched;
Chong Zhang0275e392015-09-17 10:41:44 -0700240
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700241 CompatibilityInfo.Translator mTranslator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242
243 final View.AttachInfo mAttachInfo;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700244 InputChannel mInputChannel;
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -0700245 InputQueue.Callback mInputQueueCallback;
246 InputQueue mInputQueue;
Joe Onorato86f67862010-11-05 18:57:34 -0700247 FallbackEventHandler mFallbackEventHandler;
Jeff Brown96e942d2011-11-30 19:55:01 -0800248 Choreographer mChoreographer;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 final Rect mTempRect; // used in the transaction to not thrash the heap.
251 final Rect mVisRect; // used to retrieve visible rect of focused view.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252
253 boolean mTraversalScheduled;
Jeff Browne0dbd002012-02-15 19:34:58 -0800254 int mTraversalBarrier;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 boolean mWillDrawSoon;
Craig Mautnerdf2390a2012-08-29 20:59:22 -0700256 /** Set to true while in performTraversals for detecting when die(true) is called from internal
257 * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */
258 boolean mIsInTraversal;
Adrian Roosfa104232014-06-20 16:10:14 -0700259 boolean mApplyInsetsRequested;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 boolean mLayoutRequested;
261 boolean mFirst;
262 boolean mReportNextDraw;
263 boolean mFullRedrawNeeded;
264 boolean mNewSurfaceNeeded;
265 boolean mHasHadWindowFocus;
266 boolean mLastWasImTarget;
Jorim Jaggia4a58ef2016-01-27 02:10:08 -0800267 boolean mForceNextWindowRelayout;
Chong Zhang8dbd9ad2015-10-09 10:06:11 -0700268 CountDownLatch mWindowDrawCountDown;
Jorim Jaggi827e0fa2015-05-07 11:41:41 -0700269
Romain Guy1f59e5c2012-05-06 14:11:16 -0700270 boolean mIsDrawing;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700271 int mLastSystemUiVisibility;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700272 int mClientWindowLayoutFlags;
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800273 boolean mLastOverscanRequested;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800274
275 // Pool of queued input events.
276 private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
277 private QueuedInputEvent mQueuedInputEventPool;
278 private int mQueuedInputEventPoolSize;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800279
Michael Wrightc8a7e542013-03-20 17:58:33 -0700280 /* Input event queue.
Jeff Brownf9e989d2013-04-04 23:04:03 -0700281 * Pending input events are input events waiting to be delivered to the input stages
282 * and handled by the application.
Michael Wrightc8a7e542013-03-20 17:58:33 -0700283 */
284 QueuedInputEvent mPendingInputEventHead;
285 QueuedInputEvent mPendingInputEventTail;
Michael Wright95ae9422013-03-14 10:58:50 -0700286 int mPendingInputEventCount;
Jeff Brown96e942d2011-11-30 19:55:01 -0800287 boolean mProcessInputEventsScheduled;
Michael Wright9d744c72014-02-18 21:27:42 -0800288 boolean mUnbufferedInputDispatch;
Michael Wright95ae9422013-03-14 10:58:50 -0700289 String mPendingInputEventQueueLengthCounterName = "pq";
Jeff Brownf9e989d2013-04-04 23:04:03 -0700290
291 InputStage mFirstInputStage;
292 InputStage mFirstPostImeInputStage;
Michael Wright899d7052014-04-23 17:23:39 -0700293 InputStage mSyntheticInputStage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294
295 boolean mWindowAttributesChanged = false;
Romain Guyf21c9b02011-09-06 16:56:54 -0700296 int mWindowAttributesChangesFlag = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297
298 // These can be accessed by any thread, must be protected with a lock.
Mathias Agopian5583dc62009-07-09 16:28:11 -0700299 // Surface can never be reassigned or cleared (use Surface.clear()).
John Reckb13de072014-11-19 16:33:47 -0800300 final Surface mSurface = new Surface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301
302 boolean mAdded;
303 boolean mAddedTouchMode;
304
Craig Mautner48d0d182013-06-11 07:53:06 -0700305 final DisplayAdjustments mDisplayAdjustments;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700306
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307 // These are accessed by multiple threads.
308 final Rect mWinFrame; // frame given by window manager.
309
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800310 final Rect mPendingOverscanInsets = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311 final Rect mPendingVisibleInsets = new Rect();
Adrian Roosfa104232014-06-20 16:10:14 -0700312 final Rect mPendingStableInsets = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313 final Rect mPendingContentInsets = new Rect();
Filip Gruszczynski2217f612015-05-26 11:32:08 -0700314 final Rect mPendingOutsets = new Rect();
Jorim Jaggia7262a82015-11-03 15:15:40 +0100315 final Rect mPendingBackDropFrame = new Rect();
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -0800316 boolean mPendingAlwaysConsumeNavBar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317 final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
318 = new ViewTreeObserver.InternalInsetsInfo();
319
Adrian Roosfa104232014-06-20 16:10:14 -0700320 final Rect mDispatchContentInsets = new Rect();
321 final Rect mDispatchStableInsets = new Rect();
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700322
Filip Gruszczynski954289d2015-02-26 15:46:47 -0800323 private WindowInsets mLastWindowInsets;
324
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700325 final Configuration mLastConfiguration = new Configuration();
326 final Configuration mPendingConfiguration = new Configuration();
Romain Guy59a12ca2011-06-09 17:48:21 -0700327
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328 boolean mScrollMayChange;
329 int mSoftInputMode;
Svetoslav Ganov149567f2013-01-08 15:23:34 -0800330 WeakReference<View> mLastScrolledFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331 int mScrollY;
332 int mCurScrollY;
333 Scroller mScroller;
John Recke56e9df2014-02-21 15:45:10 -0800334 static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
Chet Haasecca2c982011-05-20 14:34:18 -0700335 private ArrayList<LayoutTransition> mPendingTransitions;
Romain Guy8506ab42009-06-11 17:35:47 -0700336
Romain Guy8506ab42009-06-11 17:35:47 -0700337 final ViewConfiguration mViewConfiguration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338
Christopher Tatea53146c2010-09-07 11:57:52 -0700339 /* Drag/drop */
340 ClipDescription mDragDescription;
341 View mCurrentDragView;
Christopher Tate7fb8b562011-01-20 13:46:41 -0800342 volatile Object mLocalDragState;
Christopher Tatea53146c2010-09-07 11:57:52 -0700343 final PointF mDragPoint = new PointF();
Christopher Tate2c095f32010-10-04 14:13:40 -0700344 final PointF mLastTouchPoint = new PointF();
Vladislav Kaznacheevba761122016-01-22 12:09:45 -0800345 int mLastTouchSource;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700346
347 private boolean mProfileRendering;
Romain Guyd0750312012-11-29 11:34:43 -0800348 private Choreographer.FrameCallback mRenderProfiler;
349 private boolean mRenderProfilingEnabled;
Christopher Tatea53146c2010-09-07 11:57:52 -0700350
Chet Haase2f2022a2011-10-11 06:41:59 -0700351 // Variables to track frames per second, enabled via DEBUG_FPS flag
352 private long mFpsStartTime = -1;
353 private long mFpsPrevTime = -1;
354 private int mFpsNumFrames;
355
Jun Mukai1db53972015-09-11 18:08:31 -0700356 private int mPointerIconShape = PointerIcon.STYLE_NOT_SPECIFIED;
Jun Mukaid4eaef72015-10-30 15:54:33 -0700357 private PointerIcon mCustomPointerIcon = null;
Jun Mukai1db53972015-09-11 18:08:31 -0700358
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 /**
360 * see {@link #playSoundEffect(int)}
361 */
362 AudioManager mAudioManager;
363
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700364 final AccessibilityManager mAccessibilityManager;
365
Gilles Debunne5ac84422011-10-19 09:35:58 -0700366 AccessibilityInteractionController mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700367
368 AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager;
Chris Craikcce47eb2014-07-16 15:12:15 -0700369 HighContrastTextManager mHighContrastTextManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700370
Svetoslav Ganova0156172011-06-26 17:55:44 -0700371 SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700372
Svetoslav Ganov42138042012-03-20 11:51:39 -0700373 HashSet<View> mTempHashSet;
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800374
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700375 private final int mDensity;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700376 private final int mNoncompatDensity;
Adam Powellb08013c2010-09-16 16:28:11 -0700377
Chet Haase97140572012-09-13 14:56:47 -0700378 private boolean mInLayout = false;
379 ArrayList<View> mLayoutRequesters = new ArrayList<View>();
380 boolean mHandlingLayoutInLayoutRequest = false;
381
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700382 private int mViewLayoutDirectionInitial;
Chet Haase97140572012-09-13 14:56:47 -0700383
Craig Mautner8f303ad2013-06-14 11:32:22 -0700384 /** Set to true once doDie() has been called. */
385 private boolean mRemoved;
386
Jeff Brown21bc5c92011-02-28 18:27:14 -0800387 /**
388 * Consistency verifier for debugging purposes.
389 */
390 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
391 InputEventConsistencyVerifier.isInstrumentationEnabled() ?
392 new InputEventConsistencyVerifier(this, 0) : null;
393
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700394 static final class SystemUiVisibilityInfo {
395 int seq;
396 int globalVisibility;
397 int localValue;
398 int localChanges;
399 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700400
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800401 private String mTag = TAG;
402
Jeff Brown98365d72012-08-19 20:30:52 -0700403 public ViewRootImpl(Context context, Display display) {
Jeff Brownf9e989d2013-04-04 23:04:03 -0700404 mContext = context;
405 mWindowSession = WindowManagerGlobal.getWindowSession();
Jeff Brown98365d72012-08-19 20:30:52 -0700406 mDisplay = display;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800407 mBasePackageName = context.getBasePackageName();
Jeff Brown98365d72012-08-19 20:30:52 -0700408
Craig Mautner48d0d182013-06-11 07:53:06 -0700409 mDisplayAdjustments = display.getDisplayAdjustments();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700410
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 mThread = Thread.currentThread();
412 mLocation = new WindowLeaked(null);
413 mLocation.fillInStackTrace();
414 mWidth = -1;
415 mHeight = -1;
416 mDirty = new Rect();
417 mTempRect = new Rect();
418 mVisRect = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 mWinFrame = new Rect();
Romain Guyfb8b7632010-08-23 21:05:08 -0700420 mWindow = new W(this);
Dianne Hackborn180c4842011-09-13 12:39:25 -0700421 mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 mViewVisibility = View.GONE;
423 mTransparentRegion = new Region();
424 mPreviousTransparentRegion = new Region();
425 mFirst = true; // true for the first time the view is added
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 mAdded = false;
Chris Craikcce47eb2014-07-16 15:12:15 -0700427 mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700428 mAccessibilityManager = AccessibilityManager.getInstance(context);
429 mAccessibilityInteractionConnectionManager =
430 new AccessibilityInteractionConnectionManager();
Svetoslav Ganov00d0c142012-02-24 11:30:49 -0800431 mAccessibilityManager.addAccessibilityStateChangeListener(
432 mAccessibilityInteractionConnectionManager);
Chris Craikcce47eb2014-07-16 15:12:15 -0700433 mHighContrastTextManager = new HighContrastTextManager();
434 mAccessibilityManager.addHighTextContrastStateChangeListener(
435 mHighContrastTextManager);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 mViewConfiguration = ViewConfiguration.get(context);
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700437 mDensity = context.getResources().getDisplayMetrics().densityDpi;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700438 mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
Jorim Jaggib10e33f2015-02-04 21:57:40 +0100439 mFallbackEventHandler = new PhoneFallbackEventHandler(context);
Jeff Brown96e942d2011-11-30 19:55:01 -0800440 mChoreographer = Choreographer.getInstance();
Jeff Brownd912e1f2014-04-11 18:46:22 -0700441 mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
Dianne Hackborna53de062012-05-08 18:53:51 -0700442 loadSystemProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 }
444
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800445 public static void addFirstDrawHandler(Runnable callback) {
446 synchronized (sFirstDrawHandlers) {
447 if (!sFirstDrawComplete) {
448 sFirstDrawHandlers.add(callback);
449 }
450 }
451 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700452
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800453 public static void addConfigCallback(ComponentCallbacks callback) {
454 synchronized (sConfigCallbacks) {
455 sConfigCallbacks.add(callback);
456 }
457 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700458
Chong Zhangdcee1de2015-10-06 10:26:00 -0700459 public void addWindowCallbacks(WindowCallbacks callback) {
Skuhneb8160872015-09-22 09:51:39 -0700460 if (USE_MT_RENDERER) {
Chong Zhangdcee1de2015-10-06 10:26:00 -0700461 synchronized (mWindowCallbacks) {
462 mWindowCallbacks.add(callback);
Skuhneb8160872015-09-22 09:51:39 -0700463 }
464 }
465 }
466
Chong Zhangdcee1de2015-10-06 10:26:00 -0700467 public void removeWindowCallbacks(WindowCallbacks callback) {
Skuhneb8160872015-09-22 09:51:39 -0700468 if (USE_MT_RENDERER) {
Chong Zhangdcee1de2015-10-06 10:26:00 -0700469 synchronized (mWindowCallbacks) {
470 mWindowCallbacks.remove(callback);
Skuhneb8160872015-09-22 09:51:39 -0700471 }
472 }
473 }
474
Chong Zhang8dbd9ad2015-10-09 10:06:11 -0700475 public void reportDrawFinish() {
476 if (mWindowDrawCountDown != null) {
477 mWindowDrawCountDown.countDown();
478 }
479 }
480
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800481 // FIXME for perf testing only
482 private boolean mProfile = false;
483
484 /**
485 * Call this to profile the next traversal call.
486 * FIXME for perf testing only. Remove eventually
487 */
488 public void profile() {
489 mProfile = true;
490 }
491
492 /**
493 * Indicates whether we are in touch mode. Calling this method triggers an IPC
494 * call and should be avoided whenever possible.
495 *
496 * @return True, if the device is in touch mode, false otherwise.
497 *
498 * @hide
499 */
500 static boolean isInTouchMode() {
Jeff Brown98365d72012-08-19 20:30:52 -0700501 IWindowSession windowSession = WindowManagerGlobal.peekWindowSession();
502 if (windowSession != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503 try {
Jeff Brown98365d72012-08-19 20:30:52 -0700504 return windowSession.getInTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 } catch (RemoteException e) {
506 }
507 }
508 return false;
509 }
510
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 /**
512 * We have one child
513 */
Romain Guye4d01122010-06-16 18:44:05 -0700514 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515 synchronized (this) {
516 if (mView == null) {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700517 mView = view;
Jeff Brownd912e1f2014-04-11 18:46:22 -0700518
519 mAttachInfo.mDisplayState = mDisplay.getState();
520 mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
521
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700522 mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
Joe Onorato86f67862010-11-05 18:57:34 -0700523 mFallbackEventHandler.setView(view);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700524 mWindowAttributes.copyFrom(attrs);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800525 if (mWindowAttributes.packageName == null) {
526 mWindowAttributes.packageName = mBasePackageName;
527 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700528 attrs = mWindowAttributes;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800529 setTag();
Dianne Hackborn9d090892012-06-11 18:35:41 -0700530 // Keep track of the actual window flags supplied by the client.
531 mClientWindowLayoutFlags = attrs.flags;
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700532
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700533 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700534
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700535 if (view instanceof RootViewSurfaceTaker) {
536 mSurfaceHolderCallback =
537 ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
538 if (mSurfaceHolderCallback != null) {
539 mSurfaceHolder = new TakenSurfaceHolder();
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700540 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700541 }
542 }
Romain Guy1aec9a22011-01-05 09:37:12 -0800543
Alan Viverette49a22e82014-07-12 20:01:27 -0700544 // Compute surface insets required to draw at specified Z value.
545 // TODO: Use real shadow insets for a constant max Z.
Alan Viverette5435a302015-01-29 10:25:34 -0800546 if (!attrs.hasManualSurfaceInsets) {
547 final int surfaceInset = (int) Math.ceil(view.getZ() * 2);
548 attrs.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
549 }
Alan Viverette49a22e82014-07-12 20:01:27 -0700550
Craig Mautner48d0d182013-06-11 07:53:06 -0700551 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
Romain Guy856d4e12011-10-14 15:47:55 -0700552 mTranslator = compatibilityInfo.getTranslator();
553
Romain Guy1aec9a22011-01-05 09:37:12 -0800554 // If the application owns the surface, don't enable hardware acceleration
555 if (mSurfaceHolder == null) {
Romain Guy3b748a42013-04-17 18:54:38 -0700556 enableHardwareAcceleration(attrs);
Romain Guy1aec9a22011-01-05 09:37:12 -0800557 }
558
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700559 boolean restore = false;
Romain Guy35b38ce2009-10-07 13:38:55 -0700560 if (mTranslator != null) {
Romain Guy856d4e12011-10-14 15:47:55 -0700561 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700562 restore = true;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700563 attrs.backup();
564 mTranslator.translateWindowLayout(attrs);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700565 }
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800566 if (DEBUG_LAYOUT) Log.d(mTag, "WindowLayout in setView:" + attrs);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700567
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700568 if (!compatibilityInfo.supportsScreen()) {
Adam Lesinski95c42972013-10-02 10:13:27 -0700569 attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700570 mLastInCompatMode = true;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700571 }
572
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 mSoftInputMode = attrs.softInputMode;
574 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -0700575 mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576 mAttachInfo.mRootView = view;
Romain Guy35b38ce2009-10-07 13:38:55 -0700577 mAttachInfo.mScalingRequired = mTranslator != null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700578 mAttachInfo.mApplicationScale =
579 mTranslator == null ? 1.0f : mTranslator.applicationScale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 if (panelParentView != null) {
581 mAttachInfo.mPanelParentWindowToken
582 = panelParentView.getApplicationWindowToken();
583 }
584 mAdded = true;
585 int res; /* = WindowManagerImpl.ADD_OKAY; */
Romain Guy8506ab42009-06-11 17:35:47 -0700586
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587 // Schedule the first layout -before- adding to the window
588 // manager, to make sure we do the relayout before receiving
589 // any other events from the system.
590 requestLayout();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700591 if ((mWindowAttributes.inputFeatures
592 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
593 mInputChannel = new InputChannel();
594 }
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800595 mForceDecorViewVisibility = (mWindowAttributes.privateFlags
596 & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800597 try {
Dianne Hackborn180c4842011-09-13 12:39:25 -0700598 mOrigWindowType = mWindowAttributes.type;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700599 mAttachInfo.mRecomputeGlobalAttributes = true;
600 collectViewAttributes();
Jeff Brown98365d72012-08-19 20:30:52 -0700601 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
602 getHostVisibility(), mDisplay.getDisplayId(),
Filip Gruszczynski0ec13282015-06-25 11:26:01 -0700603 mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
604 mAttachInfo.mOutsets, mInputChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605 } catch (RemoteException e) {
606 mAdded = false;
607 mView = null;
608 mAttachInfo.mRootView = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700609 mInputChannel = null;
Joe Onorato86f67862010-11-05 18:57:34 -0700610 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700612 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613 throw new RuntimeException("Adding window failed", e);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700614 } finally {
615 if (restore) {
616 attrs.restore();
617 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700619
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700620 if (mTranslator != null) {
621 mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700622 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800623 mPendingOverscanInsets.set(0, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800624 mPendingContentInsets.set(mAttachInfo.mContentInsets);
Adrian Roosfa104232014-06-20 16:10:14 -0700625 mPendingStableInsets.set(mAttachInfo.mStableInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800626 mPendingVisibleInsets.set(0, 0, 0, 0);
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -0800627 mAttachInfo.mAlwaysConsumeNavBar =
628 (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR) != 0;
629 mPendingAlwaysConsumeNavBar = mAttachInfo.mAlwaysConsumeNavBar;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800630 if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
Jeff Brown98365d72012-08-19 20:30:52 -0700631 if (res < WindowManagerGlobal.ADD_OKAY) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632 mAttachInfo.mRootView = null;
633 mAdded = false;
Joe Onorato86f67862010-11-05 18:57:34 -0700634 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700636 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 switch (res) {
Jeff Brown98365d72012-08-19 20:30:52 -0700638 case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
639 case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
640 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800641 "Unable to add window -- token " + attrs.token
642 + " is not valid; is your activity running?");
Jeff Brown98365d72012-08-19 20:30:52 -0700643 case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
644 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800645 "Unable to add window -- token " + attrs.token
646 + " is not for an application");
Jeff Brown98365d72012-08-19 20:30:52 -0700647 case WindowManagerGlobal.ADD_APP_EXITING:
648 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800649 "Unable to add window -- app for token " + attrs.token
650 + " is exiting");
Jeff Brown98365d72012-08-19 20:30:52 -0700651 case WindowManagerGlobal.ADD_DUPLICATE_ADD:
652 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800653 "Unable to add window -- window " + mWindow
654 + " has already been added");
Jeff Brown98365d72012-08-19 20:30:52 -0700655 case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800656 // Silently ignore -- we would have just removed it
657 // right away, anyway.
658 return;
Jeff Brown98365d72012-08-19 20:30:52 -0700659 case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
Alan Viverette73f6d602015-09-14 16:01:19 -0400660 throw new WindowManager.BadTokenException("Unable to add window "
661 + mWindow + " -- another window of type "
662 + mWindowAttributes.type + " already exists");
Jeff Brown98365d72012-08-19 20:30:52 -0700663 case WindowManagerGlobal.ADD_PERMISSION_DENIED:
Alan Viverette73f6d602015-09-14 16:01:19 -0400664 throw new WindowManager.BadTokenException("Unable to add window "
665 + mWindow + " -- permission denied for window type "
666 + mWindowAttributes.type);
Craig Mautner6018aee2012-10-23 14:27:49 -0700667 case WindowManagerGlobal.ADD_INVALID_DISPLAY:
Alan Viverette73f6d602015-09-14 16:01:19 -0400668 throw new WindowManager.InvalidDisplayException("Unable to add window "
669 + mWindow + " -- the specified display can not be found");
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800670 case WindowManagerGlobal.ADD_INVALID_TYPE:
Alan Viverette73f6d602015-09-14 16:01:19 -0400671 throw new WindowManager.InvalidDisplayException("Unable to add window "
672 + mWindow + " -- the specified window type "
673 + mWindowAttributes.type + " is not valid");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674 }
675 throw new RuntimeException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800676 "Unable to add window -- unknown error code " + res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700678
Jeff Brown00fa7bd2010-07-02 15:37:36 -0700679 if (view instanceof RootViewSurfaceTaker) {
680 mInputQueueCallback =
681 ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
682 }
Jeff Browncc4f7db2011-08-30 20:34:48 -0700683 if (mInputChannel != null) {
684 if (mInputQueueCallback != null) {
Michael Wrighta44dd262013-04-10 21:12:00 -0700685 mInputQueue = new InputQueue();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700686 mInputQueueCallback.onInputQueueCreated(mInputQueue);
Jeff Browncc4f7db2011-08-30 20:34:48 -0700687 }
Michael Wrighta44dd262013-04-10 21:12:00 -0700688 mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
689 Looper.myLooper());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700690 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700691
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692 view.assignParent(this);
Jeff Brown98365d72012-08-19 20:30:52 -0700693 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
694 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700695
696 if (mAccessibilityManager.isEnabled()) {
697 mAccessibilityInteractionConnectionManager.ensureConnection();
698 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700699
700 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
701 view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
702 }
Michael Wright95ae9422013-03-14 10:58:50 -0700703
Jeff Brownf9e989d2013-04-04 23:04:03 -0700704 // Set up the input pipeline.
705 CharSequence counterSuffix = attrs.getTitle();
Michael Wright899d7052014-04-23 17:23:39 -0700706 mSyntheticInputStage = new SyntheticInputStage();
707 InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
Jeff Brownf9e989d2013-04-04 23:04:03 -0700708 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
709 "aq:native-post-ime:" + counterSuffix);
710 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
711 InputStage imeStage = new ImeInputStage(earlyPostImeStage,
712 "aq:ime:" + counterSuffix);
713 InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
714 InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
715 "aq:native-pre-ime:" + counterSuffix);
716
717 mFirstInputStage = nativePreImeStage;
718 mFirstPostImeInputStage = earlyPostImeStage;
719 mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800720 }
721 }
722 }
723
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800724 private void setTag() {
725 final String[] split = mWindowAttributes.getTitle().toString().split("\\.");
726 if (split.length > 0) {
727 mTag = TAG + "[" + split[split.length - 1] + "]";
728 }
729 }
730
keunyoung30f420f2013-08-02 14:23:10 -0700731 /** Whether the window is in local focus mode or not */
732 private boolean isInLocalFocusMode() {
733 return (mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0;
734 }
735
Dianne Hackborn49b043f2015-05-07 14:21:38 -0700736 public int getWindowFlags() {
737 return mWindowAttributes.flags;
738 }
739
Dianne Hackbornece0f4f2015-06-11 13:29:01 -0700740 public int getDisplayId() {
741 return mDisplay.getDisplayId();
742 }
743
Dianne Hackborna7bb6fb2015-02-03 18:13:40 -0800744 public CharSequence getTitle() {
745 return mWindowAttributes.getTitle();
746 }
747
Romain Guy8ff6b9e2011-11-09 20:10:18 -0800748 void destroyHardwareResources() {
Romain Guy31f2c2e2011-11-21 10:55:41 -0800749 if (mAttachInfo.mHardwareRenderer != null) {
750 mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
John Reckf47a5942014-06-30 16:20:04 -0700751 mAttachInfo.mHardwareRenderer.destroy();
Romain Guy31f2c2e2011-11-21 10:55:41 -0800752 }
753 }
754
Bo Liu845535a2014-03-21 12:06:23 -0700755 public void detachFunctor(long functor) {
John Reck44ac42a2014-05-16 14:46:07 -0700756 if (mAttachInfo.mHardwareRenderer != null) {
757 // Fence so that any pending invokeFunctor() messages will be processed
758 // before we return from detachFunctor.
John Reckf47a5942014-06-30 16:20:04 -0700759 mAttachInfo.mHardwareRenderer.stopDrawing();
John Reck44ac42a2014-05-16 14:46:07 -0700760 }
Romain Guyba6be8a2012-04-23 18:22:09 -0700761 }
762
John Reck3b202512014-06-23 13:13:08 -0700763 /**
764 * Schedules the functor for execution in either kModeProcess or
765 * kModeProcessNoContext, depending on whether or not there is an EGLContext.
766 *
767 * @param functor The native functor to invoke
768 * @param waitForCompletion If true, this will not return until the functor
769 * has invoked. If false, the functor may be invoked
770 * asynchronously.
771 */
Hui Shu9970aee2014-06-23 17:10:30 -0700772 public void invokeFunctor(long functor, boolean waitForCompletion) {
John Reck3b202512014-06-23 13:13:08 -0700773 ThreadedRenderer.invokeFunctor(functor, waitForCompletion);
Bo Liuae738a72014-04-27 16:22:04 -0700774 }
775
John Reck119907c2014-08-14 09:02:01 -0700776 public void registerAnimatingRenderNode(RenderNode animator) {
777 if (mAttachInfo.mHardwareRenderer != null) {
778 mAttachInfo.mHardwareRenderer.registerAnimatingRenderNode(animator);
779 } else {
780 if (mAttachInfo.mPendingAnimatingRenderNodes == null) {
781 mAttachInfo.mPendingAnimatingRenderNodes = new ArrayList<RenderNode>();
782 }
783 mAttachInfo.mPendingAnimatingRenderNodes.add(animator);
784 }
785 }
786
Romain Guy3b748a42013-04-17 18:54:38 -0700787 private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800788 mAttachInfo.mHardwareAccelerated = false;
789 mAttachInfo.mHardwareAccelerationRequested = false;
Romain Guy4f6aff32011-01-12 16:21:41 -0800790
Romain Guy856d4e12011-10-14 15:47:55 -0700791 // Don't enable hardware acceleration when the application is in compatibility mode
John Reckdd58e792014-04-02 16:54:28 +0000792 if (mTranslator != null) return;
Romain Guy856d4e12011-10-14 15:47:55 -0700793
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800794 // Try to enable hardware acceleration if requested
Igor Murashkina86ab6402013-08-30 12:58:36 -0700795 final boolean hardwareAccelerated =
Jim Miller1b365922011-03-09 19:38:07 -0800796 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
797
John Reckdd58e792014-04-02 16:54:28 +0000798 if (hardwareAccelerated) {
John Reck51aaf902015-12-02 15:08:07 -0800799 if (!ThreadedRenderer.isAvailable()) {
Romain Guy1af23a32011-03-24 16:03:55 -0700800 return;
801 }
802
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700803 // Persistent processes (including the system) should not do
804 // accelerated rendering on low-end devices. In that case,
805 // sRendererDisabled will be set. In addition, the system process
806 // itself should never do accelerated rendering. In that case, both
807 // sRendererDisabled and sSystemRendererDisabled are set. When
808 // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
809 // can be used by code on the system process to escape that and enable
810 // HW accelerated drawing. (This is basically for the lock screen.)
Jim Miller1b365922011-03-09 19:38:07 -0800811
John Reck61375a82014-09-18 19:27:48 +0000812 final boolean fakeHwAccelerated = (attrs.privateFlags &
813 WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700814 final boolean forceHwAccelerated = (attrs.privateFlags &
815 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
Jim Miller1b365922011-03-09 19:38:07 -0800816
John Reck61375a82014-09-18 19:27:48 +0000817 if (fakeHwAccelerated) {
818 // This is exclusively for the preview windows the window manager
819 // shows for launching applications, so they will look more like
820 // the app being launched.
821 mAttachInfo.mHardwareAccelerationRequested = true;
John Reck51aaf902015-12-02 15:08:07 -0800822 } else if (!ThreadedRenderer.sRendererDisabled
823 || (ThreadedRenderer.sSystemRendererDisabled && forceHwAccelerated)) {
Romain Guyb051e892010-09-28 19:09:36 -0700824 if (mAttachInfo.mHardwareRenderer != null) {
John Reckf47a5942014-06-30 16:20:04 -0700825 mAttachInfo.mHardwareRenderer.destroy();
Romain Guy211370f2012-02-01 16:10:55 -0800826 }
827
Alan Viverette2b12b582014-10-29 11:11:40 -0700828 final Rect insets = attrs.surfaceInsets;
Alan Viverette2cd23e62014-11-04 17:04:02 -0800829 final boolean hasSurfaceInsets = insets.left != 0 || insets.right != 0
830 || insets.top != 0 || insets.bottom != 0;
Alan Viverette2b12b582014-10-29 11:11:40 -0700831 final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;
John Reck51aaf902015-12-02 15:08:07 -0800832 mAttachInfo.mHardwareRenderer = ThreadedRenderer.create(mContext, translucent);
Romain Guye55945e2013-04-04 15:26:04 -0700833 if (mAttachInfo.mHardwareRenderer != null) {
834 mAttachInfo.mHardwareRenderer.setName(attrs.getTitle().toString());
835 mAttachInfo.mHardwareAccelerated =
836 mAttachInfo.mHardwareAccelerationRequested = true;
837 }
Romain Guye4d01122010-06-16 18:44:05 -0700838 }
839 }
840 }
841
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800842 public View getView() {
843 return mView;
844 }
845
846 final WindowLeaked getLocation() {
847 return mLocation;
848 }
849
850 void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
851 synchronized (this) {
Alan Viverettedbed8932014-08-06 17:54:52 -0700852 final int oldInsetLeft = mWindowAttributes.surfaceInsets.left;
853 final int oldInsetTop = mWindowAttributes.surfaceInsets.top;
854 final int oldInsetRight = mWindowAttributes.surfaceInsets.right;
855 final int oldInsetBottom = mWindowAttributes.surfaceInsets.bottom;
856 final int oldSoftInputMode = mWindowAttributes.softInputMode;
Alan Viverette5435a302015-01-29 10:25:34 -0800857 final boolean oldHasManualSurfaceInsets = mWindowAttributes.hasManualSurfaceInsets;
Alan Viverettedbed8932014-08-06 17:54:52 -0700858
Dianne Hackborn9d090892012-06-11 18:35:41 -0700859 // Keep track of the actual window flags supplied by the client.
860 mClientWindowLayoutFlags = attrs.flags;
Alan Viverettedbed8932014-08-06 17:54:52 -0700861
862 // Preserve compatible window flag if exists.
863 final int compatibleWindowFlag = mWindowAttributes.privateFlags
Adam Lesinski95c42972013-10-02 10:13:27 -0700864 & WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Alan Viverettedbed8932014-08-06 17:54:52 -0700865
866 // Transfer over system UI visibility values as they carry current state.
Craig Mautner3fe38c02012-05-03 17:28:09 -0700867 attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
868 attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
Alan Viverettedbed8932014-08-06 17:54:52 -0700869
Romain Guyf21c9b02011-09-06 16:56:54 -0700870 mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
John Spurlockbd957402013-10-03 11:38:39 -0400871 if ((mWindowAttributesChangesFlag
872 & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) {
873 // Recompute system ui visibility.
874 mAttachInfo.mRecomputeGlobalAttributes = true;
875 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800876 if (mWindowAttributes.packageName == null) {
877 mWindowAttributes.packageName = mBasePackageName;
878 }
Adam Lesinski95c42972013-10-02 10:13:27 -0700879 mWindowAttributes.privateFlags |= compatibleWindowFlag;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700880
Alan Viverettedbed8932014-08-06 17:54:52 -0700881 // Restore old surface insets.
882 mWindowAttributes.surfaceInsets.set(
883 oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
Alan Viverette5435a302015-01-29 10:25:34 -0800884 mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
Alan Viverettedbed8932014-08-06 17:54:52 -0700885
Dianne Hackborn9d090892012-06-11 18:35:41 -0700886 applyKeepScreenOnFlag(mWindowAttributes);
887
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800888 if (newView) {
889 mSoftInputMode = attrs.softInputMode;
890 requestLayout();
891 }
Alan Viverettedbed8932014-08-06 17:54:52 -0700892
The Android Open Source Project10592532009-03-18 17:39:46 -0700893 // Don't lose the mode we last auto-computed.
Alan Viverettedbed8932014-08-06 17:54:52 -0700894 if ((attrs.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
The Android Open Source Project10592532009-03-18 17:39:46 -0700895 == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
896 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
897 & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
Alan Viverettedbed8932014-08-06 17:54:52 -0700898 | (oldSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
The Android Open Source Project10592532009-03-18 17:39:46 -0700899 }
Alan Viverettedbed8932014-08-06 17:54:52 -0700900
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 mWindowAttributesChanged = true;
902 scheduleTraversals();
903 }
904 }
905
906 void handleAppVisibility(boolean visible) {
907 if (mAppVisible != visible) {
908 mAppVisible = visible;
909 scheduleTraversals();
John Reck73840ea2014-09-22 07:39:18 -0700910 if (!mAppVisible) {
911 WindowManagerGlobal.trimForeground();
912 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800913 }
914 }
915
916 void handleGetNewSurface() {
917 mNewSurfaceNeeded = true;
918 mFullRedrawNeeded = true;
919 scheduleTraversals();
920 }
921
Jeff Brownd912e1f2014-04-11 18:46:22 -0700922 private final DisplayListener mDisplayListener = new DisplayListener() {
923 @Override
924 public void onDisplayChanged(int displayId) {
925 if (mView != null && mDisplay.getDisplayId() == displayId) {
926 final int oldDisplayState = mAttachInfo.mDisplayState;
927 final int newDisplayState = mDisplay.getState();
928 if (oldDisplayState != newDisplayState) {
929 mAttachInfo.mDisplayState = newDisplayState;
Jeff Brownc2932a12014-11-20 18:04:05 -0800930 pokeDrawLockIfNeeded();
Jeff Brownd912e1f2014-04-11 18:46:22 -0700931 if (oldDisplayState != Display.STATE_UNKNOWN) {
932 final int oldScreenState = toViewScreenState(oldDisplayState);
933 final int newScreenState = toViewScreenState(newDisplayState);
934 if (oldScreenState != newScreenState) {
935 mView.dispatchScreenStateChanged(newScreenState);
936 }
937 if (oldDisplayState == Display.STATE_OFF) {
938 // Draw was suppressed so we need to for it to happen here.
939 mFullRedrawNeeded = true;
940 scheduleTraversals();
941 }
942 }
943 }
Romain Guy7e4e5612012-03-05 14:37:29 -0800944 }
945 }
Jeff Brownd912e1f2014-04-11 18:46:22 -0700946
947 @Override
948 public void onDisplayRemoved(int displayId) {
949 }
950
951 @Override
952 public void onDisplayAdded(int displayId) {
953 }
954
955 private int toViewScreenState(int displayState) {
956 return displayState == Display.STATE_OFF ?
957 View.SCREEN_STATE_OFF : View.SCREEN_STATE_ON;
958 }
959 };
Romain Guy7e4e5612012-03-05 14:37:29 -0800960
Jeff Brownc2932a12014-11-20 18:04:05 -0800961 void pokeDrawLockIfNeeded() {
962 final int displayState = mAttachInfo.mDisplayState;
963 if (mView != null && mAdded && mTraversalScheduled
964 && (displayState == Display.STATE_DOZE
965 || displayState == Display.STATE_DOZE_SUSPEND)) {
966 try {
967 mWindowSession.pokeDrawLock(mWindow);
968 } catch (RemoteException ex) {
969 // System server died, oh well.
970 }
971 }
972 }
973
Craig Mautner6018aee2012-10-23 14:27:49 -0700974 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700975 public void requestFitSystemWindows() {
976 checkThread();
Adrian Roosfa104232014-06-20 16:10:14 -0700977 mApplyInsetsRequested = true;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700978 scheduleTraversals();
979 }
980
Craig Mautner6018aee2012-10-23 14:27:49 -0700981 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 public void requestLayout() {
Chet Haase3efa7b52012-12-03 08:33:17 -0800983 if (!mHandlingLayoutInLayoutRequest) {
984 checkThread();
985 mLayoutRequested = true;
986 scheduleTraversals();
987 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 }
989
Craig Mautner6018aee2012-10-23 14:27:49 -0700990 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991 public boolean isLayoutRequested() {
992 return mLayoutRequested;
993 }
994
Romain Guycfef1232012-02-23 13:50:37 -0800995 void invalidate() {
996 mDirty.set(0, 0, mWidth, mHeight);
John Recke4267ea2014-06-03 15:53:15 -0700997 if (!mWillDrawSoon) {
998 scheduleTraversals();
999 }
Romain Guycfef1232012-02-23 13:50:37 -08001000 }
1001
Dianne Hackborna53de062012-05-08 18:53:51 -07001002 void invalidateWorld(View view) {
1003 view.invalidate();
1004 if (view instanceof ViewGroup) {
Romain Guyf84208f2012-09-13 22:50:18 -07001005 ViewGroup parent = (ViewGroup) view;
1006 for (int i = 0; i < parent.getChildCount(); i++) {
Dianne Hackborna53de062012-05-08 18:53:51 -07001007 invalidateWorld(parent.getChildAt(i));
1008 }
1009 }
1010 }
1011
Craig Mautner6018aee2012-10-23 14:27:49 -07001012 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001013 public void invalidateChild(View child, Rect dirty) {
Romain Guycfef1232012-02-23 13:50:37 -08001014 invalidateChildInParent(null, dirty);
1015 }
1016
Craig Mautner8f303ad2013-06-14 11:32:22 -07001017 @Override
Romain Guycfef1232012-02-23 13:50:37 -08001018 public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 checkThread();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001020 if (DEBUG_DRAW) Log.v(mTag, "Invalidate child: " + dirty);
Romain Guycfef1232012-02-23 13:50:37 -08001021
Chet Haase70d4ba12010-10-06 09:46:45 -07001022 if (dirty == null) {
Chet Haase70d4ba12010-10-06 09:46:45 -07001023 invalidate();
Romain Guycfef1232012-02-23 13:50:37 -08001024 return null;
Chet Haase3561d062012-10-23 12:54:51 -07001025 } else if (dirty.isEmpty() && !mIsAnimating) {
Chet Haase05e91ed2012-07-03 14:17:57 -07001026 return null;
Chet Haase70d4ba12010-10-06 09:46:45 -07001027 }
Romain Guycfef1232012-02-23 13:50:37 -08001028
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001029 if (mCurScrollY != 0 || mTranslator != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001030 mTempRect.set(dirty);
Romain Guy1e095972009-07-07 11:22:45 -07001031 dirty = mTempRect;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001032 if (mCurScrollY != 0) {
Romain Guycfef1232012-02-23 13:50:37 -08001033 dirty.offset(0, -mCurScrollY);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001034 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001035 if (mTranslator != null) {
Romain Guy1e095972009-07-07 11:22:45 -07001036 mTranslator.translateRectInAppWindowToScreen(dirty);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001037 }
Romain Guy1e095972009-07-07 11:22:45 -07001038 if (mAttachInfo.mScalingRequired) {
1039 dirty.inset(-1, -1);
1040 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001041 }
Romain Guycfef1232012-02-23 13:50:37 -08001042
Alan Viverettea7ea65e2015-05-15 11:30:21 -07001043 invalidateRectOnScreen(dirty);
1044
1045 return null;
1046 }
1047
1048 private void invalidateRectOnScreen(Rect dirty) {
Romain Guycfef1232012-02-23 13:50:37 -08001049 final Rect localDirty = mDirty;
1050 if (!localDirty.isEmpty() && !localDirty.contains(dirty)) {
Romain Guy02ccac62011-06-24 13:20:23 -07001051 mAttachInfo.mSetIgnoreDirtyState = true;
Romain Guy7d695942010-12-01 17:22:29 -08001052 mAttachInfo.mIgnoreDirtyState = true;
1053 }
Romain Guycfef1232012-02-23 13:50:37 -08001054
1055 // Add the new dirty rect to the current one
1056 localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
1057 // Intersect with the bounds of the window to skip
1058 // updates that lie outside of the visible region
Romain Guy7b2f8b82012-03-19 17:18:54 -07001059 final float appScale = mAttachInfo.mApplicationScale;
Chet Haase3561d062012-10-23 12:54:51 -07001060 final boolean intersected = localDirty.intersect(0, 0,
1061 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
1062 if (!intersected) {
Chet Haaseb78ee0e2012-10-17 11:32:01 -07001063 localDirty.setEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 }
Chet Haase3561d062012-10-23 12:54:51 -07001065 if (!mWillDrawSoon && (intersected || mIsAnimating)) {
1066 scheduleTraversals();
1067 }
Romain Guy0d9275e2010-10-26 14:22:30 -07001068 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001069
Daniel Koulomzin087ae472015-12-16 17:52:25 -05001070 public void setIsAmbientMode(boolean ambient) {
1071 mIsAmbientMode = ambient;
1072 }
1073
George Mount41725de2015-04-09 08:23:05 -07001074 void setWindowStopped(boolean stopped) {
Dianne Hackbornce418e62011-03-01 14:31:38 -08001075 if (mStopped != stopped) {
1076 mStopped = stopped;
George Mount41725de2015-04-09 08:23:05 -07001077 if (!mStopped) {
Dianne Hackbornce418e62011-03-01 14:31:38 -08001078 scheduleTraversals();
John Reckd9b16072016-02-23 10:35:19 -08001079 } else {
John Reckf4db3d22016-02-26 12:58:17 -08001080 if (mAttachInfo.mHardwareRenderer != null) {
John Reckfc736862016-02-26 15:01:52 -08001081 // TODO: Temporary to help track down b/27286867
1082 Log.d(mTag, "WindowStopped on " + getTitle());
John Reckf4db3d22016-02-26 12:58:17 -08001083 mAttachInfo.mHardwareRenderer.updateSurface(null);
John Reckfc736862016-02-26 15:01:52 -08001084 mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
John Reckf4db3d22016-02-26 12:58:17 -08001085 }
Dianne Hackbornce418e62011-03-01 14:31:38 -08001086 }
1087 }
1088 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089
George Mount41725de2015-04-09 08:23:05 -07001090 /**
1091 * Block the input events during an Activity Transition. The KEYCODE_BACK event is allowed
1092 * through to allow quick reversal of the Activity Transition.
1093 *
1094 * @param paused true to pause, false to resume.
1095 */
1096 public void setPausedForTransition(boolean paused) {
1097 mPausedForTransition = paused;
1098 }
1099
Craig Mautner8f303ad2013-06-14 11:32:22 -07001100 @Override
Romain Guycfef1232012-02-23 13:50:37 -08001101 public ViewParent getParent() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001102 return null;
1103 }
1104
Craig Mautner8f303ad2013-06-14 11:32:22 -07001105 @Override
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001106 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107 if (child != mView) {
1108 throw new RuntimeException("child is not mine, honest!");
1109 }
1110 // Note: don't apply scroll offset, because we want to know its
1111 // visibility in the virtual canvas being given to the view hierarchy.
1112 return r.intersect(0, 0, mWidth, mHeight);
1113 }
1114
Igor Murashkina86ab6402013-08-30 12:58:36 -07001115 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001116 public void bringChildToFront(View child) {
1117 }
1118
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001119 int getHostVisibility() {
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08001120 return (mAppVisible || mForceDecorViewVisibility) ? mView.getVisibility() : View.GONE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001121 }
Romain Guy8506ab42009-06-11 17:35:47 -07001122
Chet Haasecca2c982011-05-20 14:34:18 -07001123 /**
1124 * Add LayoutTransition to the list of transitions to be started in the next traversal.
1125 * This list will be cleared after the transitions on the list are start()'ed. These
1126 * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
1127 * happens during the layout phase of traversal, which we want to complete before any of the
1128 * animations are started (because those animations may side-effect properties that layout
1129 * depends upon, like the bounding rectangles of the affected views). So we add the transition
1130 * to the list and it is started just prior to starting the drawing phase of traversal.
1131 *
1132 * @param transition The LayoutTransition to be started on the next traversal.
1133 *
1134 * @hide
1135 */
1136 public void requestTransitionStart(LayoutTransition transition) {
1137 if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
1138 if (mPendingTransitions == null) {
1139 mPendingTransitions = new ArrayList<LayoutTransition>();
1140 }
1141 mPendingTransitions.add(transition);
1142 }
1143 }
1144
John Recka5dda642014-05-22 15:43:54 -07001145 /**
1146 * Notifies the HardwareRenderer that a new frame will be coming soon.
1147 * Currently only {@link ThreadedRenderer} cares about this, and uses
1148 * this knowledge to adjust the scheduling of off-thread animations
1149 */
1150 void notifyRendererOfFramePending() {
1151 if (mAttachInfo.mHardwareRenderer != null) {
1152 mAttachInfo.mHardwareRenderer.notifyFramePending();
1153 }
1154 }
1155
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001156 void scheduleTraversals() {
1157 if (!mTraversalScheduled) {
1158 mTraversalScheduled = true;
Jeff Brown3d4e7efe2015-02-26 15:34:16 -08001159 mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001160 mChoreographer.postCallback(
1161 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
Michael Wright9d744c72014-02-18 21:27:42 -08001162 if (!mUnbufferedInputDispatch) {
1163 scheduleConsumeBatchedInput();
1164 }
John Recka5dda642014-05-22 15:43:54 -07001165 notifyRendererOfFramePending();
Jeff Brownc2932a12014-11-20 18:04:05 -08001166 pokeDrawLockIfNeeded();
Jeff Brown96e942d2011-11-30 19:55:01 -08001167 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001168 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001169
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001170 void unscheduleTraversals() {
1171 if (mTraversalScheduled) {
1172 mTraversalScheduled = false;
Jeff Brown3d4e7efe2015-02-26 15:34:16 -08001173 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001174 mChoreographer.removeCallbacks(
1175 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
1176 }
1177 }
1178
1179 void doTraversal() {
1180 if (mTraversalScheduled) {
1181 mTraversalScheduled = false;
Jeff Brown3d4e7efe2015-02-26 15:34:16 -08001182 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001183
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001184 if (mProfile) {
1185 Debug.startMethodTracing("ViewAncestor");
Jeff Brown96e942d2011-11-30 19:55:01 -08001186 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001187
Chris Craike22c59b2015-05-21 18:33:37 -07001188 performTraversals();
Jeff Brown96e942d2011-11-30 19:55:01 -08001189
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001190 if (mProfile) {
1191 Debug.stopMethodTracing();
1192 mProfile = false;
1193 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001194 }
1195 }
1196
Dianne Hackborn9d090892012-06-11 18:35:41 -07001197 private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) {
1198 // Update window's global keep screen on flag: if a view has requested
1199 // that the screen be kept on, then it is always set; otherwise, it is
1200 // set to whatever the client last requested for the global state.
1201 if (mAttachInfo.mKeepScreenOn) {
1202 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
1203 } else {
1204 params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
1205 | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1206 }
1207 }
1208
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001209 private boolean collectViewAttributes() {
Chris Craikd36a81f2014-07-17 10:16:51 -07001210 if (mAttachInfo.mRecomputeGlobalAttributes) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001211 //Log.i(mTag, "Computing view hierarchy attributes!");
Chris Craikd36a81f2014-07-17 10:16:51 -07001212 mAttachInfo.mRecomputeGlobalAttributes = false;
1213 boolean oldScreenOn = mAttachInfo.mKeepScreenOn;
1214 mAttachInfo.mKeepScreenOn = false;
1215 mAttachInfo.mSystemUiVisibility = 0;
1216 mAttachInfo.mHasSystemUiListeners = false;
1217 mView.dispatchCollectViewAttributes(mAttachInfo, 0);
1218 mAttachInfo.mSystemUiVisibility &= ~mAttachInfo.mDisabledSystemUiVisibility;
Craig Mautner7eac0f52012-09-13 13:14:14 -07001219 WindowManager.LayoutParams params = mWindowAttributes;
Chris Craikd36a81f2014-07-17 10:16:51 -07001220 mAttachInfo.mSystemUiVisibility |= getImpliedSystemUiVisibility(params);
1221 if (mAttachInfo.mKeepScreenOn != oldScreenOn
1222 || mAttachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
1223 || mAttachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
Dianne Hackborn9d090892012-06-11 18:35:41 -07001224 applyKeepScreenOnFlag(params);
Chris Craikd36a81f2014-07-17 10:16:51 -07001225 params.subtreeSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
1226 params.hasSystemUiListeners = mAttachInfo.mHasSystemUiListeners;
1227 mView.dispatchWindowSystemUiVisiblityChanged(mAttachInfo.mSystemUiVisibility);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001228 return true;
1229 }
1230 }
1231 return false;
1232 }
1233
John Spurlockbd957402013-10-03 11:38:39 -04001234 private int getImpliedSystemUiVisibility(WindowManager.LayoutParams params) {
1235 int vis = 0;
1236 // Translucent decor window flags imply stable system ui visibility.
1237 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) != 0) {
1238 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
1239 }
1240 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) != 0) {
1241 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
1242 }
1243 return vis;
1244 }
1245
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001246 private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
1247 final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
1248 int childWidthMeasureSpec;
1249 int childHeightMeasureSpec;
1250 boolean windowSizeMayChange = false;
1251
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001252 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(mTag,
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001253 "Measuring " + host + " in display " + desiredWindowWidth
1254 + "x" + desiredWindowHeight + "...");
1255
1256 boolean goodMeasure = false;
1257 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
1258 // On large screens, we don't want to allow dialogs to just
1259 // stretch to fill the entire width of the screen to display
1260 // one line of text. First try doing the layout at a smaller
1261 // size to see if it will fit.
1262 final DisplayMetrics packageMetrics = res.getDisplayMetrics();
1263 res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
1264 int baseSize = 0;
1265 if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
1266 baseSize = (int)mTmpValue.getDimension(packageMetrics);
1267 }
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08001268 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": baseSize=" + baseSize
1269 + ", desiredWindowWidth=" + desiredWindowWidth);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001270 if (baseSize != 0 && desiredWindowWidth > baseSize) {
1271 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
1272 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001273 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001274 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08001275 + host.getMeasuredWidth() + "," + host.getMeasuredHeight()
1276 + ") from width spec: " + MeasureSpec.toString(childWidthMeasureSpec)
1277 + " and height spec: " + MeasureSpec.toString(childHeightMeasureSpec));
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001278 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1279 goodMeasure = true;
1280 } else {
1281 // Didn't fit in that size... try expanding a bit.
1282 baseSize = (baseSize+desiredWindowWidth)/2;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001283 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": next baseSize="
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001284 + baseSize);
1285 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001286 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001287 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001288 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1289 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001290 if (DEBUG_DIALOG) Log.v(mTag, "Good!");
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001291 goodMeasure = true;
1292 }
1293 }
1294 }
1295 }
1296
1297 if (!goodMeasure) {
1298 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
1299 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001300 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001301 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
1302 windowSizeMayChange = true;
1303 }
1304 }
1305
1306 if (DBG) {
1307 System.out.println("======================================");
1308 System.out.println("performTraversals -- after measure");
1309 host.debug();
1310 }
1311
1312 return windowSizeMayChange;
1313 }
1314
Alan Viverettefed3f722013-11-14 14:48:20 -08001315 /**
1316 * Modifies the input matrix such that it maps view-local coordinates to
1317 * on-screen coordinates.
1318 *
1319 * @param m input matrix to modify
1320 */
1321 void transformMatrixToGlobal(Matrix m) {
Dake Gu7bf379c2014-07-15 16:29:38 -07001322 m.preTranslate(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
Alan Viverettefed3f722013-11-14 14:48:20 -08001323 }
1324
1325 /**
1326 * Modifies the input matrix such that it maps on-screen coordinates to
1327 * view-local coordinates.
1328 *
1329 * @param m input matrix to modify
1330 */
1331 void transformMatrixToLocal(Matrix m) {
Dake Gu7bf379c2014-07-15 16:29:38 -07001332 m.postTranslate(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
Alan Viverettefed3f722013-11-14 14:48:20 -08001333 }
1334
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001335 /* package */ WindowInsets getWindowInsets(boolean forceConstruct) {
1336 if (mLastWindowInsets == null || forceConstruct) {
1337 mDispatchContentInsets.set(mAttachInfo.mContentInsets);
1338 mDispatchStableInsets.set(mAttachInfo.mStableInsets);
1339 Rect contentInsets = mDispatchContentInsets;
1340 Rect stableInsets = mDispatchStableInsets;
1341 // For dispatch we preserve old logic, but for direct requests from Views we allow to
1342 // immediately use pending insets.
1343 if (!forceConstruct
1344 && (!mPendingContentInsets.equals(contentInsets) ||
1345 !mPendingStableInsets.equals(stableInsets))) {
1346 contentInsets = mPendingContentInsets;
1347 stableInsets = mPendingStableInsets;
1348 }
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001349 Rect outsets = mAttachInfo.mOutsets;
1350 if (outsets.left > 0 || outsets.top > 0 || outsets.right > 0 || outsets.bottom > 0) {
1351 contentInsets = new Rect(contentInsets.left + outsets.left,
1352 contentInsets.top + outsets.top, contentInsets.right + outsets.right,
1353 contentInsets.bottom + outsets.bottom);
1354 }
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001355 mLastWindowInsets = new WindowInsets(contentInsets,
Adam Powell01f280d2015-05-18 16:07:42 -07001356 null /* windowDecorInsets */, stableInsets,
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08001357 mContext.getResources().getConfiguration().isScreenRound(),
1358 mAttachInfo.mAlwaysConsumeNavBar);
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001359 }
1360 return mLastWindowInsets;
1361 }
1362
Adam Powell2accbf92014-04-16 23:14:57 +00001363 void dispatchApplyInsets(View host) {
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001364 host.dispatchApplyWindowInsets(getWindowInsets(true /* forceConstruct */));
Adam Powell2accbf92014-04-16 23:14:57 +00001365 }
1366
Chong Zhangf6525ce2016-01-14 17:09:56 -08001367 private static boolean shouldUseDisplaySize(final WindowManager.LayoutParams lp) {
1368 return lp.type == TYPE_STATUS_BAR_PANEL
1369 || lp.type == TYPE_INPUT_METHOD
1370 || lp.type == TYPE_VOLUME_OVERLAY;
1371 }
1372
1373 private int dipToPx(int dip) {
1374 final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
1375 return (int) (displayMetrics.density * dip + 0.5f);
1376 }
1377
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378 private void performTraversals() {
1379 // cache mView since it is used so much below...
1380 final View host = mView;
1381
1382 if (DBG) {
1383 System.out.println("======================================");
1384 System.out.println("performTraversals");
1385 host.debug();
1386 }
1387
1388 if (host == null || !mAdded)
1389 return;
1390
Craig Mautnerdf2390a2012-08-29 20:59:22 -07001391 mIsInTraversal = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392 mWillDrawSoon = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001393 boolean windowSizeMayChange = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001394 boolean newSurface = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001395 boolean surfaceChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001396 WindowManager.LayoutParams lp = mWindowAttributes;
1397
1398 int desiredWindowWidth;
1399 int desiredWindowHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401 final int viewVisibility = getHostVisibility();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001402 final boolean viewVisibilityChanged = !mFirst
1403 && (mViewVisibility != viewVisibility || mNewSurfaceNeeded);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404
1405 WindowManager.LayoutParams params = null;
1406 if (mWindowAttributesChanged) {
1407 mWindowAttributesChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001408 surfaceChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001409 params = lp;
1410 }
Craig Mautner48d0d182013-06-11 07:53:06 -07001411 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001412 if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
1413 params = lp;
Jeff Brown96e942d2011-11-30 19:55:01 -08001414 mFullRedrawNeeded = true;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001415 mLayoutRequested = true;
1416 if (mLastInCompatMode) {
Adam Lesinski95c42972013-10-02 10:13:27 -07001417 params.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001418 mLastInCompatMode = false;
1419 } else {
Adam Lesinski95c42972013-10-02 10:13:27 -07001420 params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001421 mLastInCompatMode = true;
1422 }
1423 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001424
Romain Guyf21c9b02011-09-06 16:56:54 -07001425 mWindowAttributesChangesFlag = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -07001426
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001427 Rect frame = mWinFrame;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001428 if (mFirst) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001429 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001430 mLayoutRequested = true;
1431
Chong Zhangf6525ce2016-01-14 17:09:56 -08001432 if (shouldUseDisplaySize(lp)) {
Dianne Hackborna239c842011-06-01 12:28:20 -07001433 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001434 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001435 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001436 desiredWindowWidth = size.x;
1437 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001438 } else {
Chong Zhangf6525ce2016-01-14 17:09:56 -08001439 Configuration config = mContext.getResources().getConfiguration();
1440 desiredWindowWidth = dipToPx(config.screenWidthDp);
1441 desiredWindowHeight = dipToPx(config.screenHeightDp);
Dianne Hackborna239c842011-06-01 12:28:20 -07001442 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001443
Romain Guyc5d55862011-01-21 19:01:46 -08001444 // We used to use the following condition to choose 32 bits drawing caches:
1445 // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
1446 // However, windows are now always 32 bits by default, so choose 32 bits
Chris Craikd36a81f2014-07-17 10:16:51 -07001447 mAttachInfo.mUse32BitDrawingCache = true;
1448 mAttachInfo.mHasWindowFocus = false;
1449 mAttachInfo.mWindowVisibility = viewVisibility;
1450 mAttachInfo.mRecomputeGlobalAttributes = false;
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001451 mLastConfiguration.setTo(host.getResources().getConfiguration());
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001452 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Fabrice Di Megliob003e282012-10-17 17:20:19 -07001453 // Set the layout direction if it has not been set before (inherit is the default)
1454 if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
1455 host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
1456 }
Chris Craikd36a81f2014-07-17 10:16:51 -07001457 host.dispatchAttachedToWindow(mAttachInfo, 0);
1458 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
Adam Powell2accbf92014-04-16 23:14:57 +00001459 dispatchApplyInsets(host);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001460 //Log.i(mTag, "Screen on initialized: " + attachInfo.mKeepScreenOn);
svetoslavganov75986cf2009-05-14 22:28:01 -07001461
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001462 } else {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001463 desiredWindowWidth = frame.width();
1464 desiredWindowHeight = frame.height();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001465 if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001466 if (DEBUG_ORIENTATION) Log.v(mTag, "View " + host + " resized to: " + frame);
Jeff Brown96e942d2011-11-30 19:55:01 -08001467 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 mLayoutRequested = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001469 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001470 }
1471 }
1472
1473 if (viewVisibilityChanged) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001474 mAttachInfo.mWindowVisibility = viewVisibility;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001475 host.dispatchWindowVisibilityChanged(viewVisibility);
1476 if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
Skuhneb8160872015-09-22 09:51:39 -07001477 endDragResizing();
Romain Guy65b345f2011-07-27 18:51:50 -07001478 destroyHardwareResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001479 }
1480 if (viewVisibility == View.GONE) {
1481 // After making a window gone, we will count it as being
1482 // shown for the first time the next time it gets focus.
1483 mHasHadWindowFocus = false;
1484 }
1485 }
1486
Alan Viverette7dbc3bf2015-01-28 16:14:36 -08001487 // Non-visible windows can't hold accessibility focus.
1488 if (mAttachInfo.mWindowVisibility != View.VISIBLE) {
1489 host.clearAccessibilityFocus();
1490 }
1491
Chet Haaseb78c2842012-04-19 13:39:50 -07001492 // Execute enqueued actions on every traversal in case a detached view enqueued an action
Chris Craikd36a81f2014-07-17 10:16:51 -07001493 getRunQueue().executeActions(mAttachInfo.mHandler);
Chet Haaseb78c2842012-04-19 13:39:50 -07001494
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001495 boolean insetsChanged = false;
Romain Guy8506ab42009-06-11 17:35:47 -07001496
Craig Mautner72d6f212015-02-19 16:33:09 -08001497 boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001498 if (layoutRequested) {
Romain Guy15df6702009-08-17 20:17:30 -07001499
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001500 final Resources res = mView.getContext().getResources();
1501
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001502 if (mFirst) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001503 // make sure touch mode code executes by setting cached value
1504 // to opposite of the added touch mode.
1505 mAttachInfo.mInTouchMode = !mAddedTouchMode;
Romain Guy2d4cff62010-04-09 15:39:00 -07001506 ensureTouchModeLocally(mAddedTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001507 } else {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001508 if (!mPendingOverscanInsets.equals(mAttachInfo.mOverscanInsets)) {
1509 insetsChanged = true;
1510 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001511 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001512 insetsChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001513 }
Adrian Roosfa104232014-06-20 16:10:14 -07001514 if (!mPendingStableInsets.equals(mAttachInfo.mStableInsets)) {
1515 insetsChanged = true;
1516 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001517 if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001518 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001519 if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001520 + mAttachInfo.mVisibleInsets);
1521 }
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001522 if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) {
1523 insetsChanged = true;
1524 }
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08001525 if (mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar) {
1526 insetsChanged = true;
1527 }
Chong Zhangf6525ce2016-01-14 17:09:56 -08001528 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
1529 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001530 windowSizeMayChange = true;
Chong Zhangf6525ce2016-01-14 17:09:56 -08001531
1532 if (shouldUseDisplaySize(lp)) {
1533 // NOTE -- system code, won't try to do compat mode.
1534 Point size = new Point();
1535 mDisplay.getRealSize(size);
1536 desiredWindowWidth = size.x;
1537 desiredWindowHeight = size.y;
1538 } else {
1539 Configuration config = res.getConfiguration();
1540 desiredWindowWidth = dipToPx(config.screenWidthDp);
1541 desiredWindowHeight = dipToPx(config.screenHeightDp);
1542 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001543 }
1544 }
1545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001546 // Ask host how big it wants to be
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001547 windowSizeMayChange |= measureHierarchy(host, lp, res,
1548 desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001549 }
1550
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001551 if (collectViewAttributes()) {
1552 params = lp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553 }
Chris Craikd36a81f2014-07-17 10:16:51 -07001554 if (mAttachInfo.mForceReportNewAttributes) {
1555 mAttachInfo.mForceReportNewAttributes = false;
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001556 params = lp;
1557 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001558
Chris Craikd36a81f2014-07-17 10:16:51 -07001559 if (mFirst || mAttachInfo.mViewVisibilityChanged) {
1560 mAttachInfo.mViewVisibilityChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001561 int resizeMode = mSoftInputMode &
1562 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
1563 // If we are in auto resize mode, then we need to determine
1564 // what mode to use now.
1565 if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001566 final int N = mAttachInfo.mScrollContainers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001567 for (int i=0; i<N; i++) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001568 if (mAttachInfo.mScrollContainers.get(i).isShown()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001569 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
1570 }
1571 }
1572 if (resizeMode == 0) {
1573 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
1574 }
1575 if ((lp.softInputMode &
1576 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
1577 lp.softInputMode = (lp.softInputMode &
1578 ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
1579 resizeMode;
1580 params = lp;
1581 }
1582 }
1583 }
Romain Guy8506ab42009-06-11 17:35:47 -07001584
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001585 if (params != null) {
1586 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
1587 if (!PixelFormat.formatHasAlpha(params.format)) {
1588 params.format = PixelFormat.TRANSLUCENT;
1589 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001590 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001591 mAttachInfo.mOverscanRequested = (params.flags
1592 & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001593 }
1594
Adrian Roosfa104232014-06-20 16:10:14 -07001595 if (mApplyInsetsRequested) {
1596 mApplyInsetsRequested = false;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001597 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Adam Powell2accbf92014-04-16 23:14:57 +00001598 dispatchApplyInsets(host);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001599 if (mLayoutRequested) {
1600 // Short-circuit catching a new layout request here, so
1601 // we don't need to go through two layout passes when things
1602 // change due to fitting system windows, which can happen a lot.
1603 windowSizeMayChange |= measureHierarchy(host, lp,
1604 mView.getContext().getResources(),
1605 desiredWindowWidth, desiredWindowHeight);
1606 }
1607 }
1608
1609 if (layoutRequested) {
1610 // Clear this now, so that if anything requests a layout in the
1611 // rest of this function we will catch it and re-run a full
1612 // layout pass.
1613 mLayoutRequested = false;
1614 }
1615
1616 boolean windowShouldResize = layoutRequested && windowSizeMayChange
Dianne Hackborn189ee182010-12-02 21:48:53 -08001617 && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
Romain Guy2e4f4262010-04-06 11:07:52 -07001618 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
1619 frame.width() < desiredWindowWidth && frame.width() != mWidth)
1620 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
1621 frame.height() < desiredWindowHeight && frame.height() != mHeight));
Jorim Jaggi4846ee32016-01-07 17:39:12 +01001622 windowShouldResize |= mDragResizing && mResizeMode == RESIZE_MODE_FREEFORM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001623
Jorim Jaggi4846ee32016-01-07 17:39:12 +01001624 // If the activity was just relaunched, it might have unfrozen the task bounds (while
1625 // relaunching), so we need to force a call into window manager to pick up the latest
1626 // bounds.
1627 windowShouldResize |= mActivityRelaunched;
1628
Jeff Brown2e05ec32013-09-30 15:57:43 -07001629 // Determine whether to compute insets.
1630 // If there are no inset listeners remaining then we may still need to compute
1631 // insets in case the old insets were non-empty and must be reset.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001632 final boolean computesInternalInsets =
Chris Craikd36a81f2014-07-17 10:16:51 -07001633 mAttachInfo.mTreeObserver.hasComputeInternalInsetsListeners()
1634 || mAttachInfo.mHasNonEmptyGivenInternalInsets;
Romain Guy812ccbe2010-06-01 14:07:24 -07001635
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001636 boolean insetsPending = false;
1637 int relayoutResult = 0;
Romain Guy812ccbe2010-06-01 14:07:24 -07001638
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08001639 final boolean isViewVisible = viewVisibility == View.VISIBLE;
Romain Guy812ccbe2010-06-01 14:07:24 -07001640 if (mFirst || windowShouldResize || insetsChanged ||
Jorim Jaggia4a58ef2016-01-27 02:10:08 -08001641 viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
1642 mForceNextWindowRelayout = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001643
Alan Viverette64bf97a2015-09-18 16:42:00 -04001644 if (isViewVisible) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001645 // If this window is giving internal insets to the window
1646 // manager, and it is being added or changing its visibility,
1647 // then we want to first give the window manager "fake"
1648 // insets to cause it to effectively ignore the content of
1649 // the window during layout. This avoids it briefly causing
1650 // other windows to resize/move based on the raw frame of the
1651 // window, waiting until we can finish laying out this window
1652 // and get back to the window manager with the ultimately
1653 // computed insets.
Romain Guy812ccbe2010-06-01 14:07:24 -07001654 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001655 }
1656
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001657 if (mSurfaceHolder != null) {
1658 mSurfaceHolder.mSurfaceLock.lock();
1659 mDrawingAllowed = true;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001660 }
Romain Guy812ccbe2010-06-01 14:07:24 -07001661
Romain Guyc361da82010-10-25 15:29:10 -07001662 boolean hwInitialized = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001663 boolean contentInsetsChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001664 boolean hadSurface = mSurface.isValid();
Romain Guy812ccbe2010-06-01 14:07:24 -07001665
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001666 try {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001667 if (DEBUG_LAYOUT) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001668 Log.i(mTag, "host=w:" + host.getMeasuredWidth() + ", h:" +
Dianne Hackborn189ee182010-12-02 21:48:53 -08001669 host.getMeasuredHeight() + ", params=" + params);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001670 }
Romain Guy2a83f002011-01-18 18:28:21 -08001671
John Reckf7d9c1d2014-04-09 10:01:03 -07001672 if (mAttachInfo.mHardwareRenderer != null) {
1673 // relayoutWindow may decide to destroy mSurface. As that decision
1674 // happens in WindowManager service, we need to be defensive here
1675 // and stop using the surface in case it gets destroyed.
John Reck01a5ea32014-12-03 13:01:07 -08001676 if (mAttachInfo.mHardwareRenderer.pauseSurface(mSurface)) {
1677 // Animations were running so we need to push a frame
1678 // to resume them
1679 mDirty.set(0, 0, mWidth, mHeight);
1680 }
John Reckba6adf62015-02-19 14:36:50 -08001681 mChoreographer.mFrameInfo.addFlags(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED);
John Reckf7d9c1d2014-04-09 10:01:03 -07001682 }
Romain Guy2a83f002011-01-18 18:28:21 -08001683 final int surfaceGenerationId = mSurface.getGenerationId();
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001684 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
1685
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001686 if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001687 + " overscan=" + mPendingOverscanInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001688 + " content=" + mPendingContentInsets.toShortString()
1689 + " visible=" + mPendingVisibleInsets.toShortString()
Adrian Roosfa104232014-06-20 16:10:14 -07001690 + " visible=" + mPendingStableInsets.toShortString()
Filip Gruszczynski0ec13282015-06-25 11:26:01 -07001691 + " outsets=" + mPendingOutsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 + " surface=" + mSurface);
Romain Guy8506ab42009-06-11 17:35:47 -07001693
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001694 if (mPendingConfiguration.seq != 0) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001695 if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: "
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001696 + mPendingConfiguration);
riddle_hsu164725c2015-11-12 14:07:12 +08001697 updateConfiguration(new Configuration(mPendingConfiguration), !mFirst);
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001698 mPendingConfiguration.seq = 0;
1699 }
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001700
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001701 final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
1702 mAttachInfo.mOverscanInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001703 contentInsetsChanged = !mPendingContentInsets.equals(
1704 mAttachInfo.mContentInsets);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001705 final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001706 mAttachInfo.mVisibleInsets);
Adrian Roosfa104232014-06-20 16:10:14 -07001707 final boolean stableInsetsChanged = !mPendingStableInsets.equals(
1708 mAttachInfo.mStableInsets);
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001709 final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets);
Chong Zhangf4abc2b2015-11-12 23:40:58 -08001710 final boolean surfaceSizeChanged = (relayoutResult
1711 & WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08001712 final boolean alwaysConsumeNavBarChanged =
1713 mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001714 if (contentInsetsChanged) {
1715 mAttachInfo.mContentInsets.set(mPendingContentInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001716 if (DEBUG_LAYOUT) Log.v(mTag, "Content insets changing to: "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 + mAttachInfo.mContentInsets);
1718 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001719 if (overscanInsetsChanged) {
1720 mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001721 if (DEBUG_LAYOUT) Log.v(mTag, "Overscan insets changing to: "
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001722 + mAttachInfo.mOverscanInsets);
1723 // Need to relayout with content insets.
1724 contentInsetsChanged = true;
1725 }
Adrian Roosfa104232014-06-20 16:10:14 -07001726 if (stableInsetsChanged) {
1727 mAttachInfo.mStableInsets.set(mPendingStableInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001728 if (DEBUG_LAYOUT) Log.v(mTag, "Decor insets changing to: "
Adrian Roosfa104232014-06-20 16:10:14 -07001729 + mAttachInfo.mStableInsets);
1730 // Need to relayout with content insets.
1731 contentInsetsChanged = true;
1732 }
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08001733 if (alwaysConsumeNavBarChanged) {
1734 mAttachInfo.mAlwaysConsumeNavBar = mPendingAlwaysConsumeNavBar;
1735 contentInsetsChanged = true;
1736 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001737 if (contentInsetsChanged || mLastSystemUiVisibility !=
Adrian Roosfa104232014-06-20 16:10:14 -07001738 mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001739 || mLastOverscanRequested != mAttachInfo.mOverscanRequested
1740 || outsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001741 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001742 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001743 mAttachInfo.mOutsets.set(mPendingOutsets);
Adrian Roosfa104232014-06-20 16:10:14 -07001744 mApplyInsetsRequested = false;
Adam Powell2accbf92014-04-16 23:14:57 +00001745 dispatchApplyInsets(host);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001746 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001747 if (visibleInsetsChanged) {
1748 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001749 if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 + mAttachInfo.mVisibleInsets);
1751 }
1752
1753 if (!hadSurface) {
1754 if (mSurface.isValid()) {
1755 // If we are creating a new surface, then we need to
1756 // completely redraw it. Also, when we get to the
1757 // point of drawing it we will hold off and schedule
1758 // a new traversal instead. This is so we can tell the
1759 // window manager about all of the windows being displayed
1760 // before actually drawing them, so it can display then
1761 // all at once.
1762 newSurface = true;
Jeff Brown96e942d2011-11-30 19:55:01 -08001763 mFullRedrawNeeded = true;
Jack Palevich61a6e682009-10-09 17:37:50 -07001764 mPreviousTransparentRegion.setEmpty();
Romain Guy8506ab42009-06-11 17:35:47 -07001765
John Reck63005e62015-05-19 15:00:13 -07001766 // Only initialize up-front if transparent regions are not
1767 // requested, otherwise defer to see if the entire window
1768 // will be transparent
Romain Guyb051e892010-09-28 19:09:36 -07001769 if (mAttachInfo.mHardwareRenderer != null) {
Dianne Hackborn64825172011-03-02 21:32:58 -08001770 try {
Romain Guy786fc932012-07-24 16:24:56 -07001771 hwInitialized = mAttachInfo.mHardwareRenderer.initialize(
John Reck79d81e62013-11-05 13:26:57 -08001772 mSurface);
John Reck63005e62015-05-19 15:00:13 -07001773 if (hwInitialized && (host.mPrivateFlags
1774 & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
1775 // Don't pre-allocate if transparent regions
1776 // are requested as they may not be needed
1777 mSurface.allocateBuffers();
1778 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001779 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08001780 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08001781 return;
1782 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001783 }
1784 }
1785 } else if (!mSurface.isValid()) {
1786 // If the surface has been removed, then reset the scroll
1787 // positions.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001788 if (mLastScrolledFocus != null) {
1789 mLastScrolledFocus.clear();
1790 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001791 mScrollY = mCurScrollY = 0;
Adrian Roos0e7ae4e2014-10-01 15:33:22 +02001792 if (mView instanceof RootViewSurfaceTaker) {
1793 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
1794 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001795 if (mScroller != null) {
1796 mScroller.abortAnimation();
1797 }
Romain Guy1d0c7082011-08-03 16:22:24 -07001798 // Our surface is gone
1799 if (mAttachInfo.mHardwareRenderer != null &&
1800 mAttachInfo.mHardwareRenderer.isEnabled()) {
John Reckf47a5942014-06-30 16:20:04 -07001801 mAttachInfo.mHardwareRenderer.destroy();
Romain Guy1d0c7082011-08-03 16:22:24 -07001802 }
Chong Zhangf4abc2b2015-11-12 23:40:58 -08001803 } else if ((surfaceGenerationId != mSurface.getGenerationId()
1804 || surfaceSizeChanged)
1805 && mSurfaceHolder == null
1806 && mAttachInfo.mHardwareRenderer != null) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001807 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08001808 try {
Chong Zhangf4abc2b2015-11-12 23:40:58 -08001809 // Need to do updateSurface (which leads to CanvasContext::setSurface and
1810 // re-create the EGLSurface) if either the Surface changed (as indicated by
1811 // generation id), or WindowManager changed the surface size. The latter is
1812 // because on some chips, changing the consumer side's BufferQueue size may
1813 // not take effect immediately unless we create a new EGLSurface.
1814 // Note that frame size change doesn't always imply surface size change (eg.
1815 // drag resizing uses fullscreen surface), need to check surfaceSizeChanged
1816 // flag from WindowManager.
John Reck79d81e62013-11-05 13:26:57 -08001817 mAttachInfo.mHardwareRenderer.updateSurface(mSurface);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001818 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08001819 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08001820 return;
1821 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001822 }
Chong Zhang0275e392015-09-17 10:41:44 -07001823
Jorim Jaggi4846ee32016-01-07 17:39:12 +01001824 final boolean freeformResizing = (relayoutResult
1825 & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFORM) != 0;
1826 final boolean dockedResizing = (relayoutResult
1827 & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_DOCKED) != 0;
1828 final boolean dragResizing = freeformResizing || dockedResizing;
Chong Zhang0275e392015-09-17 10:41:44 -07001829 if (mDragResizing != dragResizing) {
Skuhneb8160872015-09-22 09:51:39 -07001830 if (dragResizing) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08001831 startDragResizing(mPendingBackDropFrame,
1832 mWinFrame.equals(mPendingBackDropFrame), mPendingVisibleInsets,
1833 mPendingStableInsets);
Jorim Jaggi4846ee32016-01-07 17:39:12 +01001834 mResizeMode = freeformResizing
1835 ? RESIZE_MODE_FREEFORM
1836 : RESIZE_MODE_DOCKED_DIVIDER;
Skuhneb8160872015-09-22 09:51:39 -07001837 } else {
1838 // We shouldn't come here, but if we come we should end the resize.
1839 endDragResizing();
1840 }
Chong Zhang0275e392015-09-17 10:41:44 -07001841 }
Skuhneb8160872015-09-22 09:51:39 -07001842 if (!USE_MT_RENDERER) {
1843 if (dragResizing) {
1844 mCanvasOffsetX = mWinFrame.left;
1845 mCanvasOffsetY = mWinFrame.top;
1846 } else {
1847 mCanvasOffsetX = mCanvasOffsetY = 0;
1848 }
Chong Zhang0275e392015-09-17 10:41:44 -07001849 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850 } catch (RemoteException e) {
1851 }
Romain Guy1d0c7082011-08-03 16:22:24 -07001852
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001853 if (DEBUG_ORIENTATION) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07001854 TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001855
Chris Craikd36a81f2014-07-17 10:16:51 -07001856 mAttachInfo.mWindowLeft = frame.left;
1857 mAttachInfo.mWindowTop = frame.top;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001858
1859 // !!FIXME!! This next section handles the case where we did not get the
1860 // window size we asked for. We should avoid this by getting a maximum size from
1861 // the window session beforehand.
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001862 if (mWidth != frame.width() || mHeight != frame.height()) {
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001863 mWidth = frame.width();
1864 mHeight = frame.height();
1865 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001866
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001867 if (mSurfaceHolder != null) {
1868 // The app owns the surface; tell it about what is going on.
1869 if (mSurface.isValid()) {
1870 // XXX .copyFrom() doesn't work!
1871 //mSurfaceHolder.mSurface.copyFrom(mSurface);
1872 mSurfaceHolder.mSurface = mSurface;
1873 }
Jeff Brown30bc34f2011-01-25 12:56:56 -08001874 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001875 mSurfaceHolder.mSurfaceLock.unlock();
1876 if (mSurface.isValid()) {
1877 if (!hadSurface) {
1878 mSurfaceHolder.ungetCallbacks();
1879
1880 mIsCreating = true;
1881 mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder);
1882 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1883 if (callbacks != null) {
1884 for (SurfaceHolder.Callback c : callbacks) {
1885 c.surfaceCreated(mSurfaceHolder);
1886 }
1887 }
1888 surfaceChanged = true;
1889 }
1890 if (surfaceChanged) {
1891 mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
1892 lp.format, mWidth, mHeight);
1893 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1894 if (callbacks != null) {
1895 for (SurfaceHolder.Callback c : callbacks) {
1896 c.surfaceChanged(mSurfaceHolder, lp.format,
1897 mWidth, mHeight);
1898 }
1899 }
1900 }
1901 mIsCreating = false;
1902 } else if (hadSurface) {
1903 mSurfaceHolder.ungetCallbacks();
1904 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1905 mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
1906 if (callbacks != null) {
1907 for (SurfaceHolder.Callback c : callbacks) {
1908 c.surfaceDestroyed(mSurfaceHolder);
1909 }
1910 }
1911 mSurfaceHolder.mSurfaceLock.lock();
Jozef BABJAK93c5b6a2011-02-22 09:33:19 +01001912 try {
1913 mSurfaceHolder.mSurface = new Surface();
1914 } finally {
1915 mSurfaceHolder.mSurfaceLock.unlock();
1916 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001917 }
1918 }
Romain Guy53389bd2010-09-07 17:16:32 -07001919
John Reck51aaf902015-12-02 15:08:07 -08001920 final ThreadedRenderer hardwareRenderer = mAttachInfo.mHardwareRenderer;
Alan Viverette50210d92015-05-14 18:05:36 -07001921 if (hardwareRenderer != null && hardwareRenderer.isEnabled()) {
1922 if (hwInitialized
1923 || mWidth != hardwareRenderer.getWidth()
1924 || mHeight != hardwareRenderer.getHeight()) {
1925 hardwareRenderer.setup(mWidth, mHeight, mAttachInfo,
1926 mWindowAttributes.surfaceInsets);
Romain Guy03985752011-07-11 15:33:51 -07001927 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001928 }
1929
Craig Mautner72d6f212015-02-19 16:33:09 -08001930 if (!mStopped || mReportNextDraw) {
Dianne Hackbornce418e62011-03-01 14:31:38 -08001931 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
Jeff Brown98365d72012-08-19 20:30:52 -07001932 (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001933 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
1934 || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001935 int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
1936 int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001937
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001938 if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed! mWidth="
Dianne Hackbornce418e62011-03-01 14:31:38 -08001939 + mWidth + " measuredWidth=" + host.getMeasuredWidth()
1940 + " mHeight=" + mHeight
1941 + " measuredHeight=" + host.getMeasuredHeight()
1942 + " coveredInsetsChanged=" + contentInsetsChanged);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001943
Dianne Hackbornce418e62011-03-01 14:31:38 -08001944 // Ask host how big it wants to be
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001945 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001946
Dianne Hackbornce418e62011-03-01 14:31:38 -08001947 // Implementation of weights from WindowManager.LayoutParams
1948 // We just grow the dimensions as needed and re-measure if
1949 // needs be
1950 int width = host.getMeasuredWidth();
1951 int height = host.getMeasuredHeight();
1952 boolean measureAgain = false;
Igor Murashkina86ab6402013-08-30 12:58:36 -07001953
Dianne Hackbornce418e62011-03-01 14:31:38 -08001954 if (lp.horizontalWeight > 0.0f) {
1955 width += (int) ((mWidth - width) * lp.horizontalWeight);
1956 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
1957 MeasureSpec.EXACTLY);
1958 measureAgain = true;
1959 }
1960 if (lp.verticalWeight > 0.0f) {
1961 height += (int) ((mHeight - height) * lp.verticalWeight);
1962 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
1963 MeasureSpec.EXACTLY);
1964 measureAgain = true;
1965 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001966
Dianne Hackbornce418e62011-03-01 14:31:38 -08001967 if (measureAgain) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001968 if (DEBUG_LAYOUT) Log.v(mTag,
Dianne Hackbornce418e62011-03-01 14:31:38 -08001969 "And hey let's measure once more: width=" + width
1970 + " height=" + height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001971 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001972 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001973
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001974 layoutRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001975 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001976 }
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001977 } else {
1978 // Not the first pass and no window/insets/visibility change but the window
1979 // may have moved and we need check that and if so to update the left and right
1980 // in the attach info. We translate only the window frame since on window move
1981 // the window manager tells us only for the new frame but the insets are the
1982 // same and we do not want to translate them more than once.
Jorim Jaggi2e95a482016-01-14 17:36:55 -08001983 maybeHandleWindowMove(frame);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001984 }
1985
Craig Mautner72d6f212015-02-19 16:33:09 -08001986 final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001987 boolean triggerGlobalLayoutListener = didLayout
Chris Craikd36a81f2014-07-17 10:16:51 -07001988 || mAttachInfo.mRecomputeGlobalAttributes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001989 if (didLayout) {
Jorim Jaggi26d02d22016-02-24 18:37:51 -05001990 performLayout(lp, mWidth, mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001991
Mathias Agopian54e3d3842013-04-12 15:13:12 -07001992 // By this point all views have been sized and positioned
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001993 // We can compute the transparent area
1994
Dianne Hackborn4702a852012-08-17 15:18:29 -07001995 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001996 // start out transparent
1997 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
1998 host.getLocationInWindow(mTmpLocation);
1999 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
2000 mTmpLocation[0] + host.mRight - host.mLeft,
2001 mTmpLocation[1] + host.mBottom - host.mTop);
2002
2003 host.gatherTransparentRegion(mTransparentRegion);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07002004 if (mTranslator != null) {
2005 mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
2006 }
2007
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002008 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
2009 mPreviousTransparentRegion.set(mTransparentRegion);
Mathias Agopian54e3d3842013-04-12 15:13:12 -07002010 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002011 // reconfigure window manager
2012 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002013 mWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002014 } catch (RemoteException e) {
2015 }
2016 }
2017 }
2018
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002019 if (DBG) {
2020 System.out.println("======================================");
Chet Haase4610eef2015-12-03 07:38:11 -08002021 System.out.println("performTraversals -- after setFrame");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002022 host.debug();
2023 }
2024 }
2025
2026 if (triggerGlobalLayoutListener) {
Chris Craikd36a81f2014-07-17 10:16:51 -07002027 mAttachInfo.mRecomputeGlobalAttributes = false;
2028 mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002029 }
2030
2031 if (computesInternalInsets) {
Jeff Brownfbf09772011-01-16 14:06:57 -08002032 // Clear the original insets.
Chris Craikd36a81f2014-07-17 10:16:51 -07002033 final ViewTreeObserver.InternalInsetsInfo insets = mAttachInfo.mGivenInternalInsets;
Jeff Brownfbf09772011-01-16 14:06:57 -08002034 insets.reset();
2035
2036 // Compute new insets in place.
Chris Craikd36a81f2014-07-17 10:16:51 -07002037 mAttachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
2038 mAttachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty();
Jeff Brownfbf09772011-01-16 14:06:57 -08002039
2040 // Tell the window manager.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002041 if (insetsPending || !mLastGivenInsets.equals(insets)) {
2042 mLastGivenInsets.set(insets);
Jeff Brownfbf09772011-01-16 14:06:57 -08002043
2044 // Translate insets to screen coordinates if needed.
2045 final Rect contentInsets;
2046 final Rect visibleInsets;
2047 final Region touchableRegion;
2048 if (mTranslator != null) {
2049 contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
2050 visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
2051 touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
2052 } else {
2053 contentInsets = insets.contentInsets;
2054 visibleInsets = insets.visibleInsets;
2055 touchableRegion = insets.touchableRegion;
2056 }
2057
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002058 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002059 mWindowSession.setInsets(mWindow, insets.mTouchableInsets,
Jeff Brownfbf09772011-01-16 14:06:57 -08002060 contentInsets, visibleInsets, touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002061 } catch (RemoteException e) {
2062 }
2063 }
2064 }
Romain Guy8506ab42009-06-11 17:35:47 -07002065
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002066 if (mFirst) {
2067 // handle first focus request
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002068 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: mView.hasFocus()="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002069 + mView.hasFocus());
2070 if (mView != null) {
2071 if (!mView.hasFocus()) {
2072 mView.requestFocus(View.FOCUS_FORWARD);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002073 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: requested focused view="
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002074 + mView.findFocus());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002075 } else {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002076 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: existing focused view="
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002077 + mView.findFocus());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002078 }
2079 }
2080 }
2081
Alan Viverette64bf97a2015-09-18 16:42:00 -04002082 final boolean changedVisibility = (viewVisibilityChanged || mFirst) && isViewVisible;
2083 final boolean hasWindowFocus = mAttachInfo.mHasWindowFocus && isViewVisible;
2084 final boolean regainedFocus = hasWindowFocus && mLostWindowFocus;
2085 if (regainedFocus) {
2086 mLostWindowFocus = false;
2087 } else if (!hasWindowFocus && mHadWindowFocus) {
2088 mLostWindowFocus = true;
2089 }
2090
2091 if (changedVisibility || regainedFocus) {
2092 host.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
2093 }
2094
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002095 mFirst = false;
2096 mWillDrawSoon = false;
2097 mNewSurfaceNeeded = false;
Jorim Jaggi4846ee32016-01-07 17:39:12 +01002098 mActivityRelaunched = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002099 mViewVisibility = viewVisibility;
Alan Viverette64bf97a2015-09-18 16:42:00 -04002100 mHadWindowFocus = hasWindowFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002101
Alan Viverette64bf97a2015-09-18 16:42:00 -04002102 if (hasWindowFocus && !isInLocalFocusMode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002103 final boolean imTarget = WindowManager.LayoutParams
2104 .mayUseInputMethod(mWindowAttributes.flags);
2105 if (imTarget != mLastWasImTarget) {
2106 mLastWasImTarget = imTarget;
2107 InputMethodManager imm = InputMethodManager.peekInstance();
2108 if (imm != null && imTarget) {
Alan Viverette64bf97a2015-09-18 16:42:00 -04002109 imm.onPreWindowFocus(mView, hasWindowFocus);
Yohei Yukawa5f059652015-05-14 22:16:41 -07002110 imm.onPostWindowFocus(mView, mView.findFocus(),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002111 mWindowAttributes.softInputMode,
2112 !mHasHadWindowFocus, mWindowAttributes.flags);
2113 }
2114 }
2115 }
Romain Guy8506ab42009-06-11 17:35:47 -07002116
Jeff Brown96e942d2011-11-30 19:55:01 -08002117 // Remember if we must report the next draw.
Jeff Brown98365d72012-08-19 20:30:52 -07002118 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
Jeff Brown96e942d2011-11-30 19:55:01 -08002119 mReportNextDraw = true;
2120 }
2121
Alan Viverette64bf97a2015-09-18 16:42:00 -04002122 boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002123
Jorim Jaggi3127c2a42016-01-26 18:48:44 -08002124 if (!cancelDraw) {
Chet Haase9c450412015-10-01 13:25:58 -07002125 if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
2126 for (int i = 0; i < mPendingTransitions.size(); ++i) {
2127 mPendingTransitions.get(i).startChangingAnimations();
Chet Haased56c6952011-09-07 08:46:23 -07002128 }
Chet Haase9c450412015-10-01 13:25:58 -07002129 mPendingTransitions.clear();
Chet Haased56c6952011-09-07 08:46:23 -07002130 }
Chet Haase9c450412015-10-01 13:25:58 -07002131
2132 performDraw();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002133 } else {
Alan Viverette64bf97a2015-09-18 16:42:00 -04002134 if (isViewVisible) {
Chris Wren78cb7cf2012-05-15 12:36:44 -04002135 // Try again
2136 scheduleTraversals();
2137 } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
Chet Haased56c6952011-09-07 08:46:23 -07002138 for (int i = 0; i < mPendingTransitions.size(); ++i) {
2139 mPendingTransitions.get(i).endChangingAnimations();
2140 }
2141 mPendingTransitions.clear();
2142 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002143 }
Craig Mautnerdf2390a2012-08-29 20:59:22 -07002144
2145 mIsInTraversal = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002146 }
2147
Jorim Jaggi2e95a482016-01-14 17:36:55 -08002148 private void maybeHandleWindowMove(Rect frame) {
2149
2150 // TODO: Well, we are checking whether the frame has changed similarly
2151 // to how this is done for the insets. This is however incorrect since
2152 // the insets and the frame are translated. For example, the old frame
2153 // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new
2154 // reported frame is (2, 2 - 2, 2) which implies no change but this is not
2155 // true since we are comparing a not translated value to a translated one.
2156 // This scenario is rare but we may want to fix that.
2157
2158 final boolean windowMoved = mAttachInfo.mWindowLeft != frame.left
2159 || mAttachInfo.mWindowTop != frame.top;
2160 if (windowMoved) {
2161 if (mTranslator != null) {
2162 mTranslator.translateRectInScreenToAppWinFrame(frame);
2163 }
2164 mAttachInfo.mWindowLeft = frame.left;
2165 mAttachInfo.mWindowTop = frame.top;
2166
2167 // Update the light position for the new window offsets.
2168 if (mAttachInfo.mHardwareRenderer != null) {
2169 mAttachInfo.mHardwareRenderer.setLightCenter(mAttachInfo);
2170 }
2171 }
2172 }
Jorim Jaggi3127c2a42016-01-26 18:48:44 -08002173
Romain Guy3696779b2013-01-28 14:04:07 -08002174 private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002175 Log.e(mTag, "OutOfResourcesException initializing HW surface", e);
Romain Guy3696779b2013-01-28 14:04:07 -08002176 try {
2177 if (!mWindowSession.outOfMemory(mWindow) &&
2178 Process.myUid() != Process.SYSTEM_UID) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002179 Slog.w(mTag, "No processes killed for memory; killing self");
Romain Guy3696779b2013-01-28 14:04:07 -08002180 Process.killProcess(Process.myPid());
2181 }
2182 } catch (RemoteException ex) {
2183 }
2184 mLayoutRequested = true; // ask wm for a new surface next time.
2185 }
2186
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002187 private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
2188 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
2189 try {
2190 mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
2191 } finally {
2192 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2193 }
2194 }
2195
Chet Haase97140572012-09-13 14:56:47 -07002196 /**
2197 * Called by {@link android.view.View#isInLayout()} to determine whether the view hierarchy
2198 * is currently undergoing a layout pass.
2199 *
2200 * @return whether the view hierarchy is currently undergoing a layout pass
2201 */
2202 boolean isInLayout() {
2203 return mInLayout;
2204 }
2205
2206 /**
Chet Haasecc699b42012-12-13 09:06:55 -08002207 * Called by {@link android.view.View#requestLayout()} if the view hierarchy is currently
2208 * undergoing a layout pass. requestLayout() should not generally be called during layout,
2209 * unless the container hierarchy knows what it is doing (i.e., it is fine as long as
2210 * all children in that container hierarchy are measured and laid out at the end of the layout
2211 * pass for that container). If requestLayout() is called anyway, we handle it correctly
2212 * by registering all requesters during a frame as it proceeds. At the end of the frame,
2213 * we check all of those views to see if any still have pending layout requests, which
2214 * indicates that they were not correctly handled by their container hierarchy. If that is
2215 * the case, we clear all such flags in the tree, to remove the buggy flag state that leads
2216 * to blank containers, and force a second request/measure/layout pass in this frame. If
Chet Haase97140572012-09-13 14:56:47 -07002217 * more requestLayout() calls are received during that second layout pass, we post those
Chet Haasecc699b42012-12-13 09:06:55 -08002218 * requests to the next frame to avoid possible infinite loops.
2219 *
2220 * <p>The return value from this method indicates whether the request should proceed
2221 * (if it is a request during the first layout pass) or should be skipped and posted to the
2222 * next frame (if it is a request during the second layout pass).</p>
Chet Haase97140572012-09-13 14:56:47 -07002223 *
2224 * @param view the view that requested the layout.
Chet Haasecc699b42012-12-13 09:06:55 -08002225 *
2226 * @return true if request should proceed, false otherwise.
Chet Haase97140572012-09-13 14:56:47 -07002227 */
Chet Haasecc699b42012-12-13 09:06:55 -08002228 boolean requestLayoutDuringLayout(final View view) {
2229 if (view.mParent == null || view.mAttachInfo == null) {
2230 // Would not normally trigger another layout, so just let it pass through as usual
2231 return true;
2232 }
Chet Haase107a4822013-03-13 06:46:50 -07002233 if (!mLayoutRequesters.contains(view)) {
2234 mLayoutRequesters.add(view);
2235 }
Chet Haase97140572012-09-13 14:56:47 -07002236 if (!mHandlingLayoutInLayoutRequest) {
Chet Haase107a4822013-03-13 06:46:50 -07002237 // Let the request proceed normally; it will be processed in a second layout pass
2238 // if necessary
Chet Haasecc699b42012-12-13 09:06:55 -08002239 return true;
Chet Haase97140572012-09-13 14:56:47 -07002240 } else {
Chet Haase107a4822013-03-13 06:46:50 -07002241 // Don't let the request proceed during the second layout pass.
2242 // It will post to the next frame instead.
Chet Haasecc699b42012-12-13 09:06:55 -08002243 return false;
Chet Haase97140572012-09-13 14:56:47 -07002244 }
2245 }
2246
Chet Haase3efa7b52012-12-03 08:33:17 -08002247 private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
2248 int desiredWindowHeight) {
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002249 mLayoutRequested = false;
2250 mScrollMayChange = true;
Chet Haase97140572012-09-13 14:56:47 -07002251 mInLayout = true;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002252
2253 final View host = mView;
2254 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002255 Log.v(mTag, "Laying out " + host + " to (" +
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002256 host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
2257 }
2258
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002259 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
2260 try {
2261 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haasecc699b42012-12-13 09:06:55 -08002262
Chet Haased5a83522012-11-21 16:24:44 -08002263 mInLayout = false;
Chet Haase97140572012-09-13 14:56:47 -07002264 int numViewsRequestingLayout = mLayoutRequesters.size();
2265 if (numViewsRequestingLayout > 0) {
Chet Haasecc699b42012-12-13 09:06:55 -08002266 // requestLayout() was called during layout.
2267 // If no layout-request flags are set on the requesting views, there is no problem.
2268 // If some requests are still pending, then we need to clear those flags and do
2269 // a full request/measure/layout pass to handle this situation.
Chet Haase107a4822013-03-13 06:46:50 -07002270 ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
2271 false);
2272 if (validLayoutRequesters != null) {
2273 // Set this flag to indicate that any further requests are happening during
2274 // the second pass, which may result in posting those requests to the next
2275 // frame instead
Chet Haasecc699b42012-12-13 09:06:55 -08002276 mHandlingLayoutInLayoutRequest = true;
Chet Haase107a4822013-03-13 06:46:50 -07002277
2278 // Process fresh layout requests, then measure and layout
2279 int numValidRequests = validLayoutRequesters.size();
Chet Haasecc699b42012-12-13 09:06:55 -08002280 for (int i = 0; i < numValidRequests; ++i) {
Chet Haase107a4822013-03-13 06:46:50 -07002281 final View view = validLayoutRequesters.get(i);
2282 Log.w("View", "requestLayout() improperly called by " + view +
2283 " during layout: running second layout pass");
2284 view.requestLayout();
Chet Haasecc699b42012-12-13 09:06:55 -08002285 }
2286 measureHierarchy(host, lp, mView.getContext().getResources(),
2287 desiredWindowWidth, desiredWindowHeight);
2288 mInLayout = true;
2289 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haase107a4822013-03-13 06:46:50 -07002290
Chet Haasecc699b42012-12-13 09:06:55 -08002291 mHandlingLayoutInLayoutRequest = false;
Chet Haase107a4822013-03-13 06:46:50 -07002292
2293 // Check the valid requests again, this time without checking/clearing the
2294 // layout flags, since requests happening during the second pass get noop'd
2295 validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);
2296 if (validLayoutRequesters != null) {
2297 final ArrayList<View> finalRequesters = validLayoutRequesters;
2298 // Post second-pass requests to the next frame
2299 getRunQueue().post(new Runnable() {
2300 @Override
2301 public void run() {
2302 int numValidRequests = finalRequesters.size();
2303 for (int i = 0; i < numValidRequests; ++i) {
2304 final View view = finalRequesters.get(i);
2305 Log.w("View", "requestLayout() improperly called by " + view +
2306 " during second layout pass: posting in next frame");
2307 view.requestLayout();
2308 }
2309 }
2310 });
2311 }
Chet Haasecc699b42012-12-13 09:06:55 -08002312 }
Chet Haase107a4822013-03-13 06:46:50 -07002313
Chet Haase97140572012-09-13 14:56:47 -07002314 }
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002315 } finally {
2316 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2317 }
Chet Haase97140572012-09-13 14:56:47 -07002318 mInLayout = false;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002319 }
2320
Chet Haase107a4822013-03-13 06:46:50 -07002321 /**
2322 * This method is called during layout when there have been calls to requestLayout() during
2323 * layout. It walks through the list of views that requested layout to determine which ones
2324 * still need it, based on visibility in the hierarchy and whether they have already been
2325 * handled (as is usually the case with ListView children).
2326 *
2327 * @param layoutRequesters The list of views that requested layout during layout
2328 * @param secondLayoutRequests Whether the requests were issued during the second layout pass.
2329 * If so, the FORCE_LAYOUT flag was not set on requesters.
2330 * @return A list of the actual views that still need to be laid out.
2331 */
2332 private ArrayList<View> getValidLayoutRequesters(ArrayList<View> layoutRequesters,
2333 boolean secondLayoutRequests) {
2334
2335 int numViewsRequestingLayout = layoutRequesters.size();
2336 ArrayList<View> validLayoutRequesters = null;
2337 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2338 View view = layoutRequesters.get(i);
2339 if (view != null && view.mAttachInfo != null && view.mParent != null &&
2340 (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) ==
2341 View.PFLAG_FORCE_LAYOUT)) {
2342 boolean gone = false;
2343 View parent = view;
2344 // Only trigger new requests for views in a non-GONE hierarchy
2345 while (parent != null) {
2346 if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) {
2347 gone = true;
2348 break;
2349 }
2350 if (parent.mParent instanceof View) {
2351 parent = (View) parent.mParent;
2352 } else {
2353 parent = null;
2354 }
2355 }
2356 if (!gone) {
2357 if (validLayoutRequesters == null) {
2358 validLayoutRequesters = new ArrayList<View>();
2359 }
2360 validLayoutRequesters.add(view);
2361 }
2362 }
2363 }
2364 if (!secondLayoutRequests) {
2365 // If we're checking the layout flags, then we need to clean them up also
2366 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2367 View view = layoutRequesters.get(i);
2368 while (view != null &&
2369 (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
2370 view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
2371 if (view.mParent instanceof View) {
2372 view = (View) view.mParent;
2373 } else {
2374 view = null;
2375 }
2376 }
2377 }
2378 }
2379 layoutRequesters.clear();
2380 return validLayoutRequesters;
2381 }
2382
Igor Murashkina86ab6402013-08-30 12:58:36 -07002383 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002384 public void requestTransparentRegion(View child) {
2385 // the test below should not fail unless someone is messing with us
2386 checkThread();
2387 if (mView == child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002388 mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002389 // Need to make sure we re-evaluate the window attributes next
2390 // time around, to ensure the window has the correct format.
2391 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -07002392 mWindowAttributesChangesFlag = 0;
Mathias Agopian1bd80ad2010-11-04 17:13:39 -07002393 requestLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002394 }
2395 }
2396
2397 /**
2398 * Figures out the measure spec for the root view in a window based on it's
2399 * layout params.
2400 *
2401 * @param windowSize
2402 * The available width or height of the window
2403 *
2404 * @param rootDimension
2405 * The layout params for one dimension (width or height) of the
2406 * window.
2407 *
2408 * @return The measure spec to use to measure the root view.
2409 */
Romain Guya998dff2012-03-23 18:58:36 -07002410 private static int getRootMeasureSpec(int windowSize, int rootDimension) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002411 int measureSpec;
2412 switch (rootDimension) {
2413
Romain Guy980a9382010-01-08 15:06:28 -08002414 case ViewGroup.LayoutParams.MATCH_PARENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002415 // Window can't resize. Force root view to be windowSize.
2416 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
2417 break;
2418 case ViewGroup.LayoutParams.WRAP_CONTENT:
2419 // Window can resize. Set max size for root view.
2420 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
2421 break;
2422 default:
2423 // Window wants to be an exact size. Force root view to be that size.
2424 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
2425 break;
2426 }
2427 return measureSpec;
2428 }
2429
Alan Viveretteccb11e12014-07-08 16:04:02 -07002430 int mHardwareXOffset;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002431 int mHardwareYOffset;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002432
Igor Murashkina86ab6402013-08-30 12:58:36 -07002433 @Override
Chris Craikf6829a02015-03-10 10:28:59 -07002434 public void onHardwarePreDraw(DisplayListCanvas canvas) {
Alan Viveretteccb11e12014-07-08 16:04:02 -07002435 canvas.translate(-mHardwareXOffset, -mHardwareYOffset);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002436 }
2437
Igor Murashkina86ab6402013-08-30 12:58:36 -07002438 @Override
Chris Craikf6829a02015-03-10 10:28:59 -07002439 public void onHardwarePostDraw(DisplayListCanvas canvas) {
Alan Viverette632af842014-10-28 13:45:11 -07002440 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002441 }
2442
Chet Haaseed30fd82011-04-22 16:18:45 -07002443 /**
2444 * @hide
2445 */
2446 void outputDisplayList(View view) {
Chris Craik356b5fe2015-07-07 10:39:36 -07002447 view.mRenderNode.output();
John Recke248bd12015-08-05 13:53:53 -07002448 if (mAttachInfo.mHardwareRenderer != null) {
2449 ((ThreadedRenderer)mAttachInfo.mHardwareRenderer).serializeDisplayListTree();
2450 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002451 }
2452
2453 /**
2454 * @see #PROPERTY_PROFILE_RENDERING
2455 */
2456 private void profileRendering(boolean enabled) {
2457 if (mProfileRendering) {
2458 mRenderProfilingEnabled = enabled;
Chris Craikae4f32042013-02-07 12:57:10 -08002459
2460 if (mRenderProfiler != null) {
2461 mChoreographer.removeFrameCallback(mRenderProfiler);
2462 }
2463 if (mRenderProfilingEnabled) {
2464 if (mRenderProfiler == null) {
2465 mRenderProfiler = new Choreographer.FrameCallback() {
2466 @Override
2467 public void doFrame(long frameTimeNanos) {
2468 mDirty.set(0, 0, mWidth, mHeight);
2469 scheduleTraversals();
2470 if (mRenderProfilingEnabled) {
2471 mChoreographer.postFrameCallback(mRenderProfiler);
2472 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002473 }
Chris Craikae4f32042013-02-07 12:57:10 -08002474 };
2475 }
Romain Guy5bb3c732012-11-29 17:52:58 -08002476 mChoreographer.postFrameCallback(mRenderProfiler);
Romain Guy59a12ca2011-06-09 17:48:21 -07002477 } else {
Romain Guy59a12ca2011-06-09 17:48:21 -07002478 mRenderProfiler = null;
Chet Haaseed30fd82011-04-22 16:18:45 -07002479 }
2480 }
2481 }
2482
Chet Haase2f2022a2011-10-11 06:41:59 -07002483 /**
2484 * Called from draw() when DEBUG_FPS is enabled
2485 */
2486 private void trackFPS() {
2487 // Tracks frames per second drawn. First value in a series of draws may be bogus
2488 // because it down not account for the intervening idle time
2489 long nowTime = System.currentTimeMillis();
2490 if (mFpsStartTime < 0) {
2491 mFpsStartTime = mFpsPrevTime = nowTime;
2492 mFpsNumFrames = 0;
2493 } else {
2494 ++mFpsNumFrames;
2495 String thisHash = Integer.toHexString(System.identityHashCode(this));
2496 long frameTime = nowTime - mFpsPrevTime;
2497 long totalTime = nowTime - mFpsStartTime;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002498 Log.v(mTag, "0x" + thisHash + "\tFrame time:\t" + frameTime);
Chet Haase2f2022a2011-10-11 06:41:59 -07002499 mFpsPrevTime = nowTime;
2500 if (totalTime > 1000) {
2501 float fps = (float) mFpsNumFrames * 1000 / totalTime;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002502 Log.v(mTag, "0x" + thisHash + "\tFPS:\t" + fps);
Chet Haase2f2022a2011-10-11 06:41:59 -07002503 mFpsStartTime = nowTime;
2504 mFpsNumFrames = 0;
2505 }
2506 }
2507 }
2508
Jeff Brown96e942d2011-11-30 19:55:01 -08002509 private void performDraw() {
Jeff Brownd912e1f2014-04-11 18:46:22 -07002510 if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
Craig Mautner006f0e42012-03-21 11:00:32 -07002511 return;
2512 }
Romain Guy7e4e5612012-03-05 14:37:29 -08002513
Jeff Brown96e942d2011-11-30 19:55:01 -08002514 final boolean fullRedrawNeeded = mFullRedrawNeeded;
2515 mFullRedrawNeeded = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002516
Romain Guy1f59e5c2012-05-06 14:11:16 -07002517 mIsDrawing = true;
Jeff Brown481c1572012-03-09 14:41:15 -08002518 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
2519 try {
2520 draw(fullRedrawNeeded);
2521 } finally {
Romain Guy1f59e5c2012-05-06 14:11:16 -07002522 mIsDrawing = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002523 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2524 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002525
John Reck119907c2014-08-14 09:02:01 -07002526 // For whatever reason we didn't create a HardwareRenderer, end any
2527 // hardware animations that are now dangling
2528 if (mAttachInfo.mPendingAnimatingRenderNodes != null) {
2529 final int count = mAttachInfo.mPendingAnimatingRenderNodes.size();
2530 for (int i = 0; i < count; i++) {
2531 mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators();
2532 }
2533 mAttachInfo.mPendingAnimatingRenderNodes.clear();
2534 }
2535
Jeff Brown96e942d2011-11-30 19:55:01 -08002536 if (mReportNextDraw) {
2537 mReportNextDraw = false;
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07002538
2539 // if we're using multi-thread renderer, wait for the window frame draws
2540 if (mWindowDrawCountDown != null) {
2541 try {
2542 mWindowDrawCountDown.await();
2543 } catch (InterruptedException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002544 Log.e(mTag, "Window redraw count down interruped!");
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07002545 }
2546 mWindowDrawCountDown = null;
2547 }
2548
John Reck28ad7b52014-04-07 16:59:25 -07002549 if (mAttachInfo.mHardwareRenderer != null) {
2550 mAttachInfo.mHardwareRenderer.fence();
2551 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002552
2553 if (LOCAL_LOGV) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002554 Log.v(mTag, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
Jeff Brown96e942d2011-11-30 19:55:01 -08002555 }
2556 if (mSurfaceHolder != null && mSurface.isValid()) {
2557 mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
2558 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
2559 if (callbacks != null) {
2560 for (SurfaceHolder.Callback c : callbacks) {
2561 if (c instanceof SurfaceHolder.Callback2) {
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08002562 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(mSurfaceHolder);
Jeff Brown96e942d2011-11-30 19:55:01 -08002563 }
2564 }
2565 }
2566 }
2567 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002568 mWindowSession.finishDrawing(mWindow);
Jeff Brown96e942d2011-11-30 19:55:01 -08002569 } catch (RemoteException e) {
2570 }
2571 }
2572 }
2573
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002574 private void draw(boolean fullRedrawNeeded) {
2575 Surface surface = mSurface;
Romain Guyfbb93fa2012-12-03 18:50:35 -08002576 if (!surface.isValid()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002577 return;
2578 }
2579
Chet Haase2f2022a2011-10-11 06:41:59 -07002580 if (DEBUG_FPS) {
2581 trackFPS();
2582 }
2583
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002584 if (!sFirstDrawComplete) {
2585 synchronized (sFirstDrawHandlers) {
2586 sFirstDrawComplete = true;
Romain Guy812ccbe2010-06-01 14:07:24 -07002587 final int count = sFirstDrawHandlers.size();
2588 for (int i = 0; i< count; i++) {
Jeff Browna175a5b2012-02-15 19:18:31 -08002589 mHandler.post(sFirstDrawHandlers.get(i));
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002590 }
2591 }
2592 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002593
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002594 scrollToRectOrFocus(null, false);
2595
Chris Craikd36a81f2014-07-17 10:16:51 -07002596 if (mAttachInfo.mViewScrollChanged) {
2597 mAttachInfo.mViewScrollChanged = false;
2598 mAttachInfo.mTreeObserver.dispatchOnScrollChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002599 }
Romain Guy8506ab42009-06-11 17:35:47 -07002600
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002601 boolean animating = mScroller != null && mScroller.computeScrollOffset();
Alan Viveretteccb11e12014-07-08 16:04:02 -07002602 final int curScrollY;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002603 if (animating) {
Alan Viveretteccb11e12014-07-08 16:04:02 -07002604 curScrollY = mScroller.getCurrY();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002605 } else {
Alan Viveretteccb11e12014-07-08 16:04:02 -07002606 curScrollY = mScrollY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002607 }
Alan Viveretteccb11e12014-07-08 16:04:02 -07002608 if (mCurScrollY != curScrollY) {
2609 mCurScrollY = curScrollY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002610 fullRedrawNeeded = true;
Adrian Roos0e7ae4e2014-10-01 15:33:22 +02002611 if (mView instanceof RootViewSurfaceTaker) {
2612 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
2613 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002614 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002615
Chris Craikd36a81f2014-07-17 10:16:51 -07002616 final float appScale = mAttachInfo.mApplicationScale;
2617 final boolean scalingRequired = mAttachInfo.mScalingRequired;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002618
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002619 int resizeAlpha = 0;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002620
Jeff Brown96e942d2011-11-30 19:55:01 -08002621 final Rect dirty = mDirty;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002622 if (mSurfaceHolder != null) {
2623 // The app owns the surface, we won't draw.
2624 dirty.setEmpty();
Derek Sollenberger8d948352015-07-16 09:27:59 -04002625 if (animating && mScroller != null) {
2626 mScroller.abortAnimation();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002627 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002628 return;
2629 }
Romain Guy58ef7fb2010-09-13 12:52:37 -07002630
2631 if (fullRedrawNeeded) {
Chris Craikd36a81f2014-07-17 10:16:51 -07002632 mAttachInfo.mIgnoreDirtyState = true;
Romain Guyc3166e12011-08-08 15:00:03 -07002633 dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
Romain Guy58ef7fb2010-09-13 12:52:37 -07002634 }
Chet Haasead4f7032011-06-22 09:18:31 -07002635
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002636 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002637 Log.v(mTag, "Draw " + mView + "/"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002638 + mWindowAttributes.getTitle()
2639 + ": dirty={" + dirty.left + "," + dirty.top
2640 + "," + dirty.right + "," + dirty.bottom + "} surface="
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002641 + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
2642 appScale + ", width=" + mWidth + ", height=" + mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002643 }
2644
Chris Craikd36a81f2014-07-17 10:16:51 -07002645 mAttachInfo.mTreeObserver.dispatchOnDraw();
Romain Guy25eba5c2012-04-04 17:29:03 -07002646
Chong Zhang0275e392015-09-17 10:41:44 -07002647 int xOffset = -mCanvasOffsetX;
2648 int yOffset = -mCanvasOffsetY + curScrollY;
Alan Viverettea51cab92014-07-16 15:15:49 -07002649 final WindowManager.LayoutParams params = mWindowAttributes;
2650 final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
2651 if (surfaceInsets != null) {
2652 xOffset -= surfaceInsets.left;
2653 yOffset -= surfaceInsets.top;
2654
2655 // Offset dirty rect for surface insets.
2656 dirty.offset(surfaceInsets.left, surfaceInsets.right);
2657 }
2658
Alan Viverette632af842014-10-28 13:45:11 -07002659 boolean accessibilityFocusDirty = false;
2660 final Drawable drawable = mAttachInfo.mAccessibilityFocusDrawable;
2661 if (drawable != null) {
2662 final Rect bounds = mAttachInfo.mTmpInvalRect;
2663 final boolean hasFocus = getAccessibilityFocusedRect(bounds);
2664 if (!hasFocus) {
2665 bounds.setEmpty();
2666 }
2667 if (!bounds.equals(drawable.getBounds())) {
2668 accessibilityFocusDirty = true;
2669 }
2670 }
2671
John Reckba6adf62015-02-19 14:36:50 -08002672 mAttachInfo.mDrawingTime =
2673 mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
2674
Alan Viverette632af842014-10-28 13:45:11 -07002675 if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
Chris Craikd36a81f2014-07-17 10:16:51 -07002676 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
Alan Viverette632af842014-10-28 13:45:11 -07002677 // If accessibility focus moved, always invalidate the root.
2678 boolean invalidateRoot = accessibilityFocusDirty;
2679
Jeff Brown96e942d2011-11-30 19:55:01 -08002680 // Draw with hardware renderer.
2681 mIsAnimating = false;
Alan Viverette632af842014-10-28 13:45:11 -07002682
John Reck0a973302014-07-16 13:29:45 -07002683 if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
2684 mHardwareYOffset = yOffset;
2685 mHardwareXOffset = xOffset;
Alan Viverette632af842014-10-28 13:45:11 -07002686 invalidateRoot = true;
Alan Viverettef6cf1a02014-08-11 14:13:02 -07002687 }
2688
Alan Viverette632af842014-10-28 13:45:11 -07002689 if (invalidateRoot) {
2690 mAttachInfo.mHardwareRenderer.invalidateRoot();
2691 }
2692
Jeff Brown96e942d2011-11-30 19:55:01 -08002693 dirty.setEmpty();
2694
Skuhne980ee472015-10-06 11:31:31 -07002695 // Stage the content drawn size now. It will be transferred to the renderer
2696 // shortly before the draw commands get send to the renderer.
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07002697 final boolean updated = updateContentDrawBounds();
2698
John Reck61375a82014-09-18 19:27:48 +00002699 mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this);
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07002700
2701 if (updated) {
2702 requestDrawWindow();
2703 }
Romain Guy3696779b2013-01-28 14:04:07 -08002704 } else {
2705 // If we get here with a disabled & requested hardware renderer, something went
2706 // wrong (an invalidate posted right before we destroyed the hardware surface
2707 // for instance) so we should just bail out. Locking the surface with software
2708 // rendering at this point would lock it forever and prevent hardware renderer
2709 // from doing its job when it comes back.
2710 // Before we request a new frame we must however attempt to reinitiliaze the
2711 // hardware renderer if it's in requested state. This would happen after an
2712 // eglTerminate() for instance.
Chris Craikd36a81f2014-07-17 10:16:51 -07002713 if (mAttachInfo.mHardwareRenderer != null &&
2714 !mAttachInfo.mHardwareRenderer.isEnabled() &&
2715 mAttachInfo.mHardwareRenderer.isRequested()) {
Romain Guy3696779b2013-01-28 14:04:07 -08002716
2717 try {
Chris Craikd36a81f2014-07-17 10:16:51 -07002718 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
Alan Viverette50210d92015-05-14 18:05:36 -07002719 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
Igor Murashkina86ab6402013-08-30 12:58:36 -07002720 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002721 handleOutOfResourcesException(e);
2722 return;
2723 }
2724
2725 mFullRedrawNeeded = true;
2726 scheduleTraversals();
2727 return;
2728 }
2729
Chris Craikd36a81f2014-07-17 10:16:51 -07002730 if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
Romain Guy3696779b2013-01-28 14:04:07 -08002731 return;
2732 }
Jeff Brown95db2b22011-11-30 19:54:41 -08002733 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002734 }
Romain Guy8506ab42009-06-11 17:35:47 -07002735
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002736 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002737 mFullRedrawNeeded = true;
2738 scheduleTraversals();
2739 }
2740 }
2741
Romain Guy25eba5c2012-04-04 17:29:03 -07002742 /**
Alan Viveretteccb11e12014-07-08 16:04:02 -07002743 * @return true if drawing was successful, false if an error occurred
Romain Guy25eba5c2012-04-04 17:29:03 -07002744 */
Alan Viveretteccb11e12014-07-08 16:04:02 -07002745 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
Romain Guy25eba5c2012-04-04 17:29:03 -07002746 boolean scalingRequired, Rect dirty) {
2747
2748 // Draw with software renderer.
Alan Viverettea51cab92014-07-16 15:15:49 -07002749 final Canvas canvas;
Romain Guy25eba5c2012-04-04 17:29:03 -07002750 try {
Alan Viverettea51cab92014-07-16 15:15:49 -07002751 final int left = dirty.left;
2752 final int top = dirty.top;
2753 final int right = dirty.right;
2754 final int bottom = dirty.bottom;
Romain Guy25eba5c2012-04-04 17:29:03 -07002755
Romain Guy25eba5c2012-04-04 17:29:03 -07002756 canvas = mSurface.lockCanvas(dirty);
2757
Romain Guye55945e2013-04-04 15:26:04 -07002758 // The dirty rectangle can be modified by Surface.lockCanvas()
2759 //noinspection ConstantConditions
Alan Viverettea51cab92014-07-16 15:15:49 -07002760 if (left != dirty.left || top != dirty.top || right != dirty.right
2761 || bottom != dirty.bottom) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002762 attachInfo.mIgnoreDirtyState = true;
2763 }
2764
2765 // TODO: Do this in native
2766 canvas.setDensity(mDensity);
2767 } catch (Surface.OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002768 handleOutOfResourcesException(e);
Romain Guy25eba5c2012-04-04 17:29:03 -07002769 return false;
2770 } catch (IllegalArgumentException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002771 Log.e(mTag, "Could not lock surface", e);
Romain Guy25eba5c2012-04-04 17:29:03 -07002772 // Don't assume this is due to out of memory, it could be
2773 // something else, and if it is something else then we could
2774 // kill stuff (or ourself) for no reason.
2775 mLayoutRequested = true; // ask wm for a new surface next time.
2776 return false;
2777 }
2778
2779 try {
2780 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002781 Log.v(mTag, "Surface " + surface + " drawing to bitmap w="
Romain Guy25eba5c2012-04-04 17:29:03 -07002782 + canvas.getWidth() + ", h=" + canvas.getHeight());
2783 //canvas.drawARGB(255, 255, 0, 0);
2784 }
2785
Romain Guy25eba5c2012-04-04 17:29:03 -07002786 // If this bitmap's format includes an alpha channel, we
2787 // need to clear it before drawing so that the child will
2788 // properly re-composite its drawing on a transparent
2789 // background. This automatically respects the clip/dirty region
2790 // or
2791 // If we are applying an offset, we need to clear the area
2792 // where the offset doesn't appear to avoid having garbage
2793 // left in the blank areas.
Alan Viveretteccb11e12014-07-08 16:04:02 -07002794 if (!canvas.isOpaque() || yoff != 0 || xoff != 0) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002795 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
2796 }
2797
2798 dirty.setEmpty();
2799 mIsAnimating = false;
Dianne Hackborn4702a852012-08-17 15:18:29 -07002800 mView.mPrivateFlags |= View.PFLAG_DRAWN;
Romain Guy25eba5c2012-04-04 17:29:03 -07002801
2802 if (DEBUG_DRAW) {
2803 Context cxt = mView.getContext();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002804 Log.i(mTag, "Drawing: package:" + cxt.getPackageName() +
Romain Guy25eba5c2012-04-04 17:29:03 -07002805 ", metrics=" + cxt.getResources().getDisplayMetrics() +
2806 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
2807 }
2808 try {
Alan Viveretteccb11e12014-07-08 16:04:02 -07002809 canvas.translate(-xoff, -yoff);
Romain Guy25eba5c2012-04-04 17:29:03 -07002810 if (mTranslator != null) {
2811 mTranslator.translateCanvas(canvas);
2812 }
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002813 canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
Romain Guy25eba5c2012-04-04 17:29:03 -07002814 attachInfo.mSetIgnoreDirtyState = false;
2815
Romain Guy25eba5c2012-04-04 17:29:03 -07002816 mView.draw(canvas);
Alan Viverette632af842014-10-28 13:45:11 -07002817
2818 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Romain Guy25eba5c2012-04-04 17:29:03 -07002819 } finally {
2820 if (!attachInfo.mSetIgnoreDirtyState) {
2821 // Only clear the flag if it was not set during the mView.draw() call
2822 attachInfo.mIgnoreDirtyState = false;
2823 }
2824 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002825 } finally {
Romain Guydddcd222012-05-18 15:33:57 -07002826 try {
2827 surface.unlockCanvasAndPost(canvas);
2828 } catch (IllegalArgumentException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002829 Log.e(mTag, "Could not unlock surface", e);
Romain Guydddcd222012-05-18 15:33:57 -07002830 mLayoutRequested = true; // ask wm for a new surface next time.
2831 //noinspection ReturnInsideFinallyBlock
2832 return false;
2833 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002834
Romain Guy25eba5c2012-04-04 17:29:03 -07002835 if (LOCAL_LOGV) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002836 Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost");
Romain Guy25eba5c2012-04-04 17:29:03 -07002837 }
2838 }
2839 return true;
2840 }
2841
Alan Viverette632af842014-10-28 13:45:11 -07002842 /**
2843 * We want to draw a highlight around the current accessibility focused.
2844 * Since adding a style for all possible view is not a viable option we
2845 * have this specialized drawing method.
2846 *
2847 * Note: We are doing this here to be able to draw the highlight for
2848 * virtual views in addition to real ones.
2849 *
2850 * @param canvas The canvas on which to draw.
2851 */
2852 private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
2853 final Rect bounds = mAttachInfo.mTmpInvalRect;
2854 if (getAccessibilityFocusedRect(bounds)) {
2855 final Drawable drawable = getAccessibilityFocusedDrawable();
2856 if (drawable != null) {
2857 drawable.setBounds(bounds);
2858 drawable.draw(canvas);
2859 }
2860 } else if (mAttachInfo.mAccessibilityFocusDrawable != null) {
2861 mAttachInfo.mAccessibilityFocusDrawable.setBounds(0, 0, 0, 0);
2862 }
2863 }
2864
2865 private boolean getAccessibilityFocusedRect(Rect bounds) {
2866 final AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
2867 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
2868 return false;
2869 }
2870
2871 final View host = mAccessibilityFocusedHost;
2872 if (host == null || host.mAttachInfo == null) {
2873 return false;
2874 }
2875
2876 final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
2877 if (provider == null) {
Svetoslavded133c2015-01-30 20:28:41 -08002878 host.getBoundsOnScreen(bounds, true);
Alan Viverette632af842014-10-28 13:45:11 -07002879 } else if (mAccessibilityFocusedVirtualView != null) {
2880 mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
2881 } else {
2882 return false;
2883 }
2884
Alan Viverette2232add2015-05-26 15:24:18 -07002885 // Transform the rect into window-relative coordinates.
Alan Viverette632af842014-10-28 13:45:11 -07002886 final AttachInfo attachInfo = mAttachInfo;
Alan Viverette2232add2015-05-26 15:24:18 -07002887 bounds.offset(0, attachInfo.mViewRootImpl.mScrollY);
Alan Viverette632af842014-10-28 13:45:11 -07002888 bounds.offset(-attachInfo.mWindowLeft, -attachInfo.mWindowTop);
Doris Liu9607fbe2015-05-28 17:17:28 -07002889 if (!bounds.intersect(0, 0, attachInfo.mViewRootImpl.mWidth,
2890 attachInfo.mViewRootImpl.mHeight)) {
2891 // If no intersection, set bounds to empty.
2892 bounds.setEmpty();
2893 }
Alan Viverette632af842014-10-28 13:45:11 -07002894 return !bounds.isEmpty();
2895 }
2896
2897 private Drawable getAccessibilityFocusedDrawable() {
Chris Craikd36a81f2014-07-17 10:16:51 -07002898 // Lazily load the accessibility focus drawable.
2899 if (mAttachInfo.mAccessibilityFocusDrawable == null) {
Alan Viverettef6cf1a02014-08-11 14:13:02 -07002900 final TypedValue value = new TypedValue();
Chris Craikd36a81f2014-07-17 10:16:51 -07002901 final boolean resolved = mView.mContext.getTheme().resolveAttribute(
2902 R.attr.accessibilityFocusedDrawable, value, true);
2903 if (resolved) {
2904 mAttachInfo.mAccessibilityFocusDrawable =
Alan Viverette8eea3ea2014-02-03 18:40:20 -08002905 mView.mContext.getDrawable(value.resourceId);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002906 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002907 }
Chris Craikd36a81f2014-07-17 10:16:51 -07002908 return mAttachInfo.mAccessibilityFocusDrawable;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002909 }
2910
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002911 boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
Chris Craikd36a81f2014-07-17 10:16:51 -07002912 final Rect ci = mAttachInfo.mContentInsets;
2913 final Rect vi = mAttachInfo.mVisibleInsets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002914 int scrollY = 0;
2915 boolean handled = false;
Romain Guy8506ab42009-06-11 17:35:47 -07002916
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002917 if (vi.left > ci.left || vi.top > ci.top
2918 || vi.right > ci.right || vi.bottom > ci.bottom) {
2919 // We'll assume that we aren't going to change the scroll
2920 // offset, since we want to avoid that unless it is actually
2921 // going to make the focus visible... otherwise we scroll
2922 // all over the place.
2923 scrollY = mScrollY;
2924 // We can be called for two different situations: during a draw,
2925 // to update the scroll position if the focus has changed (in which
2926 // case 'rectangle' is null), or in response to a
2927 // requestChildRectangleOnScreen() call (in which case 'rectangle'
2928 // is non-null and we just want to scroll to whatever that
2929 // rectangle is).
Craig Mautner26a84df2013-04-11 19:09:05 -07002930 final View focus = mView.findFocus();
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002931 if (focus == null) {
Romain Guye8b16522009-07-14 13:06:42 -07002932 return false;
2933 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002934 View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null;
Craig Mautner26a84df2013-04-11 19:09:05 -07002935 if (focus != lastScrolledFocus) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002936 // If the focus has changed, then ignore any requests to scroll
2937 // to a rectangle; first we want to make sure the entire focus
2938 // view is visible.
2939 rectangle = null;
2940 }
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002941 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Eval scroll: focus=" + focus
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002942 + " rectangle=" + rectangle + " ci=" + ci
2943 + " vi=" + vi);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002944 if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002945 // Optimization: if the focus hasn't changed since last
2946 // time, and no layout has happened, then just leave things
2947 // as they are.
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002948 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Keeping scroll y="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002949 + mScrollY + " vi=" + vi.toShortString());
Craig Mautner26a84df2013-04-11 19:09:05 -07002950 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002951 // We need to determine if the currently focused view is
2952 // within the visible part of the window and, if not, apply
2953 // a pan so it can be seen.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002954 mLastScrolledFocus = new WeakReference<View>(focus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002955 mScrollMayChange = false;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002956 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Need to scroll?");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002957 // Try to find the rectangle from the focus view.
2958 if (focus.getGlobalVisibleRect(mVisRect, null)) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002959 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Root w="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002960 + mView.getWidth() + " h=" + mView.getHeight()
2961 + " ci=" + ci.toShortString()
2962 + " vi=" + vi.toShortString());
2963 if (rectangle == null) {
2964 focus.getFocusedRect(mTempRect);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002965 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Focus " + focus
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002966 + ": focusRect=" + mTempRect.toShortString());
Dianne Hackborn1c6a8942010-03-23 16:34:20 -07002967 if (mView instanceof ViewGroup) {
2968 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
2969 focus, mTempRect);
2970 }
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002971 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002972 "Focus in window: focusRect="
2973 + mTempRect.toShortString()
2974 + " visRect=" + mVisRect.toShortString());
2975 } else {
2976 mTempRect.set(rectangle);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002977 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002978 "Request scroll to rect: "
2979 + mTempRect.toShortString()
2980 + " visRect=" + mVisRect.toShortString());
2981 }
2982 if (mTempRect.intersect(mVisRect)) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002983 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002984 "Focus window visible rect: "
2985 + mTempRect.toShortString());
2986 if (mTempRect.height() >
2987 (mView.getHeight()-vi.top-vi.bottom)) {
2988 // If the focus simply is not going to fit, then
2989 // best is probably just to leave things as-is.
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002990 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002991 "Too tall; leaving scrollY=" + scrollY);
2992 } else if ((mTempRect.top-scrollY) < vi.top) {
2993 scrollY -= vi.top - (mTempRect.top-scrollY);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002994 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002995 "Top covered; scrollY=" + scrollY);
2996 } else if ((mTempRect.bottom-scrollY)
2997 > (mView.getHeight()-vi.bottom)) {
2998 scrollY += (mTempRect.bottom-scrollY)
2999 - (mView.getHeight()-vi.bottom);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003000 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003001 "Bottom covered; scrollY=" + scrollY);
3002 }
3003 handled = true;
3004 }
3005 }
3006 }
3007 }
Romain Guy8506ab42009-06-11 17:35:47 -07003008
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003009 if (scrollY != mScrollY) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003010 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Pan scroll changed: old="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003011 + mScrollY + " , new=" + scrollY);
Derek Sollenberger8d948352015-07-16 09:27:59 -04003012 if (!immediate) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003013 if (mScroller == null) {
3014 mScroller = new Scroller(mView.getContext());
3015 }
3016 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
3017 } else if (mScroller != null) {
3018 mScroller.abortAnimation();
3019 }
3020 mScrollY = scrollY;
3021 }
Romain Guy8506ab42009-06-11 17:35:47 -07003022
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003023 return handled;
3024 }
Romain Guy8506ab42009-06-11 17:35:47 -07003025
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07003026 /**
3027 * @hide
3028 */
3029 public View getAccessibilityFocusedHost() {
3030 return mAccessibilityFocusedHost;
3031 }
3032
3033 /**
3034 * @hide
3035 */
3036 public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
3037 return mAccessibilityFocusedVirtualView;
3038 }
3039
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003040 void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003041 // If we have a virtual view with accessibility focus we need
3042 // to clear the focus and invalidate the virtual view bounds.
3043 if (mAccessibilityFocusedVirtualView != null) {
3044
3045 AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
3046 View focusHost = mAccessibilityFocusedHost;
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003047
3048 // Wipe the state of the current accessibility focus since
3049 // the call into the provider to clear accessibility focus
3050 // will fire an accessibility event which will end up calling
3051 // this method and we want to have clean state when this
3052 // invocation happens.
3053 mAccessibilityFocusedHost = null;
3054 mAccessibilityFocusedVirtualView = null;
3055
Alan Viverette239a0c02013-05-07 17:17:35 -07003056 // Clear accessibility focus on the host after clearing state since
3057 // this method may be reentrant.
3058 focusHost.clearAccessibilityFocusNoCallbacks();
3059
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003060 AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
3061 if (provider != null) {
3062 // Invalidate the area of the cleared accessibility focus.
3063 focusNode.getBoundsInParent(mTempRect);
3064 focusHost.invalidate(mTempRect);
3065 // Clear accessibility focus in the virtual node.
3066 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
3067 focusNode.getSourceNodeId());
3068 provider.performAction(virtualNodeId,
3069 AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
3070 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003071 focusNode.recycle();
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003072 }
3073 if (mAccessibilityFocusedHost != null) {
3074 // Clear accessibility focus in the view.
Svetoslav Ganov42138042012-03-20 11:51:39 -07003075 mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks();
3076 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003077
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003078 // Set the new focus host and node.
3079 mAccessibilityFocusedHost = view;
3080 mAccessibilityFocusedVirtualView = node;
John Reck0a973302014-07-16 13:29:45 -07003081
3082 if (mAttachInfo.mHardwareRenderer != null) {
3083 mAttachInfo.mHardwareRenderer.invalidateRoot();
3084 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07003085 }
3086
Jun Mukai347e5d42015-12-03 01:13:31 -08003087 void setPointerCapture(View view) {
3088 if (!mAttachInfo.mHasWindowFocus) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003089 Log.w(mTag, "Can't set capture if it's not focused.");
Jun Mukai347e5d42015-12-03 01:13:31 -08003090 return;
3091 }
3092 if (mCapturingView == view) {
3093 return;
3094 }
3095 mCapturingView = view;
3096 InputManager.getInstance().setPointerIconDetached(true);
3097 }
3098
3099 void releasePointerCapture(View view) {
3100 if (mCapturingView != view || mCapturingView == null) {
3101 return;
3102 }
3103
3104 mCapturingView = null;
3105 InputManager.getInstance().setPointerIconDetached(false);
3106 }
3107
3108 boolean hasPointerCapture(View view) {
3109 return view != null && mCapturingView == view;
3110 }
3111
Igor Murashkina86ab6402013-08-30 12:58:36 -07003112 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003113 public void requestChildFocus(View child, View focused) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003114 if (DEBUG_INPUT_RESIZE) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003115 Log.v(mTag, "Request child focus: focus now " + focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003116 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003117 checkThread();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003118 scheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003119 }
3120
Igor Murashkina86ab6402013-08-30 12:58:36 -07003121 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003122 public void clearChildFocus(View child) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003123 if (DEBUG_INPUT_RESIZE) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003124 Log.v(mTag, "Clearing child focus");
Amith Yamasani73eb97f2012-02-14 15:45:15 -08003125 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003126 checkThread();
3127 scheduleTraversals();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003128 }
Amith Yamasani73eb97f2012-02-14 15:45:15 -08003129
Svetoslav Ganov42138042012-03-20 11:51:39 -07003130 @Override
3131 public ViewParent getParentForAccessibility() {
3132 return null;
3133 }
3134
Igor Murashkina86ab6402013-08-30 12:58:36 -07003135 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003136 public void focusableViewAvailable(View v) {
3137 checkThread();
Romain Guy1c90f032011-05-24 14:59:50 -07003138 if (mView != null) {
3139 if (!mView.hasFocus()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003140 v.requestFocus();
Romain Guy1c90f032011-05-24 14:59:50 -07003141 } else {
3142 // the one case where will transfer focus away from the current one
3143 // is if the current view is a view group that prefers to give focus
3144 // to its children first AND the view is a descendant of it.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003145 View focused = mView.findFocus();
3146 if (focused instanceof ViewGroup) {
3147 ViewGroup group = (ViewGroup) focused;
3148 if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
3149 && isViewDescendantOf(v, focused)) {
3150 v.requestFocus();
3151 }
Romain Guy1c90f032011-05-24 14:59:50 -07003152 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003153 }
3154 }
3155 }
3156
Igor Murashkina86ab6402013-08-30 12:58:36 -07003157 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003158 public void recomputeViewAttributes(View child) {
3159 checkThread();
3160 if (mView == child) {
3161 mAttachInfo.mRecomputeGlobalAttributes = true;
3162 if (!mWillDrawSoon) {
3163 scheduleTraversals();
3164 }
3165 }
3166 }
3167
3168 void dispatchDetachedFromWindow() {
Romain Guy90fc03b2011-01-16 13:07:15 -08003169 if (mView != null && mView.mAttachInfo != null) {
Dianne Hackborn961cae92013-03-20 14:59:43 -07003170 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003171 mView.dispatchDetachedFromWindow();
3172 }
3173
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003174 mAccessibilityInteractionConnectionManager.ensureNoConnection();
3175 mAccessibilityManager.removeAccessibilityStateChangeListener(
3176 mAccessibilityInteractionConnectionManager);
Chris Craikcce47eb2014-07-16 15:12:15 -07003177 mAccessibilityManager.removeHighTextContrastStateChangeListener(
3178 mHighContrastTextManager);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07003179 removeSendWindowContentChangedCallback();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003180
Romain Guya998dff2012-03-23 18:58:36 -07003181 destroyHardwareRenderer();
3182
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003183 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003184
Craig Mautner8f303ad2013-06-14 11:32:22 -07003185 mView.assignParent(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003186 mView = null;
3187 mAttachInfo.mRootView = null;
3188
Jun Mukai347e5d42015-12-03 01:13:31 -08003189 if (mCapturingView != null) {
3190 releasePointerCapture(mCapturingView);
3191 }
3192
Dianne Hackborn0586a1b2009-09-06 21:08:27 -07003193 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003194
Jeff Browncc4f7db2011-08-30 20:34:48 -07003195 if (mInputQueueCallback != null && mInputQueue != null) {
3196 mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
Michael Wrighta44dd262013-04-10 21:12:00 -07003197 mInputQueue.dispose();
Jeff Browncc4f7db2011-08-30 20:34:48 -07003198 mInputQueueCallback = null;
3199 mInputQueue = null;
Michael Wrighta44dd262013-04-10 21:12:00 -07003200 }
3201 if (mInputEventReceiver != null) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08003202 mInputEventReceiver.dispose();
3203 mInputEventReceiver = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -07003204 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003205 try {
Jeff Brown98365d72012-08-19 20:30:52 -07003206 mWindowSession.remove(mWindow);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003207 } catch (RemoteException e) {
3208 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003209
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003210 // Dispose the input channel after removing the window so the Window Manager
3211 // doesn't interpret the input channel being closed as an abnormal termination.
3212 if (mInputChannel != null) {
3213 mInputChannel.dispose();
3214 mInputChannel = null;
Jeff Brown349703e2010-06-22 01:27:15 -07003215 }
Jeff Brown96e942d2011-11-30 19:55:01 -08003216
Jeff Brownd912e1f2014-04-11 18:46:22 -07003217 mDisplayManager.unregisterDisplayListener(mDisplayListener);
3218
Jeff Brownebb2d8d2012-03-23 17:14:34 -07003219 unscheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003220 }
Romain Guy8506ab42009-06-11 17:35:47 -07003221
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003222 void updateConfiguration(Configuration config, boolean force) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003223 if (DEBUG_CONFIGURATION) Log.v(mTag,
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003224 "Applying new config to window "
3225 + mWindowAttributes.getTitle()
3226 + ": " + config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07003227
Craig Mautner48d0d182013-06-11 07:53:06 -07003228 CompatibilityInfo ci = mDisplayAdjustments.getCompatibilityInfo();
3229 if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
Dianne Hackborn5fd21692011-06-07 14:09:47 -07003230 config = new Configuration(config);
Dianne Hackborn908aecc2012-07-31 16:37:34 -07003231 ci.applyToConfiguration(mNoncompatDensity, config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07003232 }
3233
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003234 synchronized (sConfigCallbacks) {
3235 for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
3236 sConfigCallbacks.get(i).onConfigurationChanged(config);
3237 }
3238 }
3239 if (mView != null) {
3240 // At this point the resources have been updated to
3241 // have the most recent config, whatever that is. Use
Dianne Hackborn908aecc2012-07-31 16:37:34 -07003242 // the one in them which may be newer.
Romain Guy1c90f032011-05-24 14:59:50 -07003243 config = mView.getResources().getConfiguration();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003244 if (force || mLastConfiguration.diff(config) != 0) {
Fabrice Di Megliocf128972012-10-16 20:51:12 -07003245 final int lastLayoutDirection = mLastConfiguration.getLayoutDirection();
3246 final int currentLayoutDirection = config.getLayoutDirection();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003247 mLastConfiguration.setTo(config);
Fabrice Di Megliob003e282012-10-17 17:20:19 -07003248 if (lastLayoutDirection != currentLayoutDirection &&
3249 mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
Fabrice Di Megliocf128972012-10-16 20:51:12 -07003250 mView.setLayoutDirection(currentLayoutDirection);
3251 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003252 mView.dispatchConfigurationChanged(config);
3253 }
3254 }
3255 }
John Reck05e85842014-04-23 14:48:28 -07003256
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003257 /**
3258 * Return true if child is an ancestor of parent, (or equal to the parent).
3259 */
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07003260 public static boolean isViewDescendantOf(View child, View parent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003261 if (child == parent) {
3262 return true;
3263 }
3264
3265 final ViewParent theParent = child.getParent();
3266 return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
3267 }
3268
Yohei Yukawad2e56472015-07-28 17:00:33 -07003269 private static void forceLayout(View view) {
3270 view.forceLayout();
3271 if (view instanceof ViewGroup) {
3272 ViewGroup group = (ViewGroup) view;
3273 final int count = group.getChildCount();
3274 for (int i = 0; i < count; i++) {
3275 forceLayout(group.getChildAt(i));
3276 }
3277 }
3278 }
3279
Jeff Browna175a5b2012-02-15 19:18:31 -08003280 private final static int MSG_INVALIDATE = 1;
3281 private final static int MSG_INVALIDATE_RECT = 2;
3282 private final static int MSG_DIE = 3;
3283 private final static int MSG_RESIZED = 4;
3284 private final static int MSG_RESIZED_REPORT = 5;
3285 private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
keunyoung30f420f2013-08-02 14:23:10 -07003286 private final static int MSG_DISPATCH_INPUT_EVENT = 7;
Jeff Browna175a5b2012-02-15 19:18:31 -08003287 private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
3288 private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
Jeff Browna175a5b2012-02-15 19:18:31 -08003289 private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
3290 private final static int MSG_FINISH_INPUT_CONNECTION = 12;
3291 private final static int MSG_CHECK_FOCUS = 13;
3292 private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
3293 private final static int MSG_DISPATCH_DRAG_EVENT = 15;
3294 private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
3295 private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
3296 private final static int MSG_UPDATE_CONFIGURATION = 18;
Svetoslav Ganov42138042012-03-20 11:51:39 -07003297 private final static int MSG_PROCESS_INPUT_EVENTS = 19;
Romain Guyfbb93fa2012-12-03 18:50:35 -08003298 private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
Jorim Jaggi827e0fa2015-05-07 11:41:41 -07003299 private final static int MSG_INVALIDATE_WORLD = 22;
3300 private final static int MSG_WINDOW_MOVED = 23;
3301 private final static int MSG_SYNTHESIZE_INPUT_EVENT = 24;
3302 private final static int MSG_DISPATCH_WINDOW_SHOWN = 25;
Clara Bayarri75e09792015-07-29 16:20:40 +01003303 private final static int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26;
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08003304 private final static int MSG_UPDATE_POINTER_ICON = 27;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003305
Jeff Browna175a5b2012-02-15 19:18:31 -08003306 final class ViewRootHandler extends Handler {
3307 @Override
3308 public String getMessageName(Message message) {
3309 switch (message.what) {
3310 case MSG_INVALIDATE:
3311 return "MSG_INVALIDATE";
3312 case MSG_INVALIDATE_RECT:
3313 return "MSG_INVALIDATE_RECT";
3314 case MSG_DIE:
3315 return "MSG_DIE";
3316 case MSG_RESIZED:
3317 return "MSG_RESIZED";
3318 case MSG_RESIZED_REPORT:
3319 return "MSG_RESIZED_REPORT";
3320 case MSG_WINDOW_FOCUS_CHANGED:
3321 return "MSG_WINDOW_FOCUS_CHANGED";
keunyoung30f420f2013-08-02 14:23:10 -07003322 case MSG_DISPATCH_INPUT_EVENT:
3323 return "MSG_DISPATCH_INPUT_EVENT";
Jeff Browna175a5b2012-02-15 19:18:31 -08003324 case MSG_DISPATCH_APP_VISIBILITY:
3325 return "MSG_DISPATCH_APP_VISIBILITY";
3326 case MSG_DISPATCH_GET_NEW_SURFACE:
3327 return "MSG_DISPATCH_GET_NEW_SURFACE";
Jeff Browna175a5b2012-02-15 19:18:31 -08003328 case MSG_DISPATCH_KEY_FROM_IME:
3329 return "MSG_DISPATCH_KEY_FROM_IME";
3330 case MSG_FINISH_INPUT_CONNECTION:
3331 return "MSG_FINISH_INPUT_CONNECTION";
3332 case MSG_CHECK_FOCUS:
3333 return "MSG_CHECK_FOCUS";
3334 case MSG_CLOSE_SYSTEM_DIALOGS:
3335 return "MSG_CLOSE_SYSTEM_DIALOGS";
3336 case MSG_DISPATCH_DRAG_EVENT:
3337 return "MSG_DISPATCH_DRAG_EVENT";
3338 case MSG_DISPATCH_DRAG_LOCATION_EVENT:
3339 return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
3340 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
3341 return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
3342 case MSG_UPDATE_CONFIGURATION:
3343 return "MSG_UPDATE_CONFIGURATION";
Jeff Browna175a5b2012-02-15 19:18:31 -08003344 case MSG_PROCESS_INPUT_EVENTS:
3345 return "MSG_PROCESS_INPUT_EVENTS";
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003346 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
3347 return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
Craig Mautner5702d4d2012-06-30 14:10:16 -07003348 case MSG_WINDOW_MOVED:
3349 return "MSG_WINDOW_MOVED";
Michael Wright899d7052014-04-23 17:23:39 -07003350 case MSG_SYNTHESIZE_INPUT_EVENT:
3351 return "MSG_SYNTHESIZE_INPUT_EVENT";
Craig Mautner9c795042014-10-28 19:59:59 -07003352 case MSG_DISPATCH_WINDOW_SHOWN:
3353 return "MSG_DISPATCH_WINDOW_SHOWN";
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08003354 case MSG_UPDATE_POINTER_ICON:
3355 return "MSG_UPDATE_POINTER_ICON";
Jeff Browna175a5b2012-02-15 19:18:31 -08003356 }
3357 return super.getMessageName(message);
Romain Guyf9284692011-07-13 18:46:21 -07003358 }
Romain Guyf9284692011-07-13 18:46:21 -07003359
Jeff Browna175a5b2012-02-15 19:18:31 -08003360 @Override
3361 public void handleMessage(Message msg) {
3362 switch (msg.what) {
3363 case MSG_INVALIDATE:
3364 ((View) msg.obj).invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003365 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003366 case MSG_INVALIDATE_RECT:
3367 final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
3368 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08003369 info.recycle();
Jeff Browna175a5b2012-02-15 19:18:31 -08003370 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003371 case MSG_PROCESS_INPUT_EVENTS:
3372 mProcessInputEventsScheduled = false;
3373 doProcessInputEvents();
3374 break;
3375 case MSG_DISPATCH_APP_VISIBILITY:
3376 handleAppVisibility(msg.arg1 != 0);
3377 break;
3378 case MSG_DISPATCH_GET_NEW_SURFACE:
3379 handleGetNewSurface();
3380 break;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003381 case MSG_RESIZED: {
3382 // Recycled in the fall through...
3383 SomeArgs args = (SomeArgs) msg.obj;
Romain Guydfab3632012-10-03 14:53:25 -07003384 if (mWinFrame.equals(args.arg1)
Dianne Hackbornc4aad012013-02-22 15:05:25 -08003385 && mPendingOverscanInsets.equals(args.arg5)
Romain Guydfab3632012-10-03 14:53:25 -07003386 && mPendingContentInsets.equals(args.arg2)
Adrian Roosfa104232014-06-20 16:10:14 -07003387 && mPendingStableInsets.equals(args.arg6)
Romain Guydfab3632012-10-03 14:53:25 -07003388 && mPendingVisibleInsets.equals(args.arg3)
Filip Gruszczynski2217f612015-05-26 11:32:08 -07003389 && mPendingOutsets.equals(args.arg7)
Jorim Jaggi0fe356e2016-01-05 14:43:25 +01003390 && mPendingBackDropFrame.equals(args.arg8)
Jorim Jaggia4a58ef2016-01-27 02:10:08 -08003391 && args.arg4 == null
3392 && args.argi1 == 0) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003393 break;
Romain Guycdb86672010-03-18 18:54:50 -07003394 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003395 } // fall through...
Jeff Browna175a5b2012-02-15 19:18:31 -08003396 case MSG_RESIZED_REPORT:
3397 if (mAdded) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003398 SomeArgs args = (SomeArgs) msg.obj;
3399
3400 Configuration config = (Configuration) args.arg4;
Jeff Browna175a5b2012-02-15 19:18:31 -08003401 if (config != null) {
3402 updateConfiguration(config, false);
3403 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003404
3405 mWinFrame.set((Rect) args.arg1);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08003406 mPendingOverscanInsets.set((Rect) args.arg5);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003407 mPendingContentInsets.set((Rect) args.arg2);
Adrian Roosfa104232014-06-20 16:10:14 -07003408 mPendingStableInsets.set((Rect) args.arg6);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003409 mPendingVisibleInsets.set((Rect) args.arg3);
Filip Gruszczynski2217f612015-05-26 11:32:08 -07003410 mPendingOutsets.set((Rect) args.arg7);
Jorim Jaggia7262a82015-11-03 15:15:40 +01003411 mPendingBackDropFrame.set((Rect) args.arg8);
Jorim Jaggia4a58ef2016-01-27 02:10:08 -08003412 mForceNextWindowRelayout = args.argi1 != 0;
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08003413 mPendingAlwaysConsumeNavBar = args.argi2 != 0;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003414
3415 args.recycle();
3416
Jeff Browna175a5b2012-02-15 19:18:31 -08003417 if (msg.what == MSG_RESIZED_REPORT) {
3418 mReportNextDraw = true;
3419 }
Romain Guy59a12ca2011-06-09 17:48:21 -07003420
Yohei Yukawad2e56472015-07-28 17:00:33 -07003421 if (mView != null) {
3422 forceLayout(mView);
3423 }
3424
Jeff Browna175a5b2012-02-15 19:18:31 -08003425 requestLayout();
3426 }
3427 break;
Craig Mautner5702d4d2012-06-30 14:10:16 -07003428 case MSG_WINDOW_MOVED:
3429 if (mAdded) {
3430 final int w = mWinFrame.width();
3431 final int h = mWinFrame.height();
3432 final int l = msg.arg1;
3433 final int t = msg.arg2;
3434 mWinFrame.left = l;
3435 mWinFrame.right = l + w;
3436 mWinFrame.top = t;
3437 mWinFrame.bottom = t + h;
3438
Jorim Jaggia7262a82015-11-03 15:15:40 +01003439 mPendingBackDropFrame.set(mWinFrame);
3440
Jorim Jaggi844e1712016-01-13 17:39:25 -08003441 // Suppress layouts during resizing - a correct layout will happen when resizing
3442 // is done, and this just increases system load.
Jorim Jaggi2e95a482016-01-14 17:36:55 -08003443 boolean isDockedDivider = mWindowAttributes.type == TYPE_DOCK_DIVIDER;
3444 boolean suppress = (mDragResizing && mResizeMode == RESIZE_MODE_DOCKED_DIVIDER)
3445 || isDockedDivider;
Jorim Jaggi844e1712016-01-13 17:39:25 -08003446 if (!suppress) {
3447 if (mView != null) {
3448 forceLayout(mView);
3449 }
3450 requestLayout();
Jorim Jaggi2e95a482016-01-14 17:36:55 -08003451 } else {
3452 maybeHandleWindowMove(mWinFrame);
Yohei Yukawad2e56472015-07-28 17:00:33 -07003453 }
Craig Mautner5702d4d2012-06-30 14:10:16 -07003454 }
3455 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003456 case MSG_WINDOW_FOCUS_CHANGED: {
3457 if (mAdded) {
3458 boolean hasWindowFocus = msg.arg1 != 0;
3459 mAttachInfo.mHasWindowFocus = hasWindowFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003460
Jeff Browna175a5b2012-02-15 19:18:31 -08003461 profileRendering(hasWindowFocus);
3462
3463 if (hasWindowFocus) {
3464 boolean inTouchMode = msg.arg2 != 0;
3465 ensureTouchModeLocally(inTouchMode);
3466
Romain Guye55945e2013-04-04 15:26:04 -07003467 if (mAttachInfo.mHardwareRenderer != null && mSurface.isValid()){
Jeff Browna175a5b2012-02-15 19:18:31 -08003468 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08003469 try {
Alan Viveretteccb11e12014-07-08 16:04:02 -07003470 final WindowManager.LayoutParams lp = mWindowAttributes;
Alan Viverette49a22e82014-07-12 20:01:27 -07003471 final Rect surfaceInsets = lp != null ? lp.surfaceInsets : null;
Romain Guy3696779b2013-01-28 14:04:07 -08003472 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
Alan Viverette50210d92015-05-14 18:05:36 -07003473 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
Igor Murashkina86ab6402013-08-30 12:58:36 -07003474 } catch (OutOfResourcesException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003475 Log.e(mTag, "OutOfResourcesException locking surface", e);
Jeff Browna175a5b2012-02-15 19:18:31 -08003476 try {
Jeff Brown98365d72012-08-19 20:30:52 -07003477 if (!mWindowSession.outOfMemory(mWindow)) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003478 Slog.w(mTag, "No processes killed for memory; killing self");
Jeff Browna175a5b2012-02-15 19:18:31 -08003479 Process.killProcess(Process.myPid());
3480 }
3481 } catch (RemoteException ex) {
Dianne Hackborn64825172011-03-02 21:32:58 -08003482 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003483 // Retry in a bit.
3484 sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
3485 return;
Dianne Hackborn64825172011-03-02 21:32:58 -08003486 }
Dianne Hackborn64825172011-03-02 21:32:58 -08003487 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003488 }
Romain Guy8506ab42009-06-11 17:35:47 -07003489
Jeff Browna175a5b2012-02-15 19:18:31 -08003490 mLastWasImTarget = WindowManager.LayoutParams
3491 .mayUseInputMethod(mWindowAttributes.flags);
Romain Guy8506ab42009-06-11 17:35:47 -07003492
Jeff Browna175a5b2012-02-15 19:18:31 -08003493 InputMethodManager imm = InputMethodManager.peekInstance();
Yohei Yukawa5f059652015-05-14 22:16:41 -07003494 if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
3495 imm.onPreWindowFocus(mView, hasWindowFocus);
3496 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003497 if (mView != null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003498 mAttachInfo.mKeyDispatchState.reset();
3499 mView.dispatchWindowFocusChanged(hasWindowFocus);
Dianne Hackborn961cae92013-03-20 14:59:43 -07003500 mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003501 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003502
Jeff Browna175a5b2012-02-15 19:18:31 -08003503 // Note: must be done after the focus change callbacks,
3504 // so all of the view state is set up correctly.
3505 if (hasWindowFocus) {
keunyoung30f420f2013-08-02 14:23:10 -07003506 if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
Yohei Yukawa5f059652015-05-14 22:16:41 -07003507 imm.onPostWindowFocus(mView, mView.findFocus(),
Jeff Browna175a5b2012-02-15 19:18:31 -08003508 mWindowAttributes.softInputMode,
3509 !mHasHadWindowFocus, mWindowAttributes.flags);
3510 }
3511 // Clear the forward bit. We can just do this directly, since
3512 // the window manager doesn't care about it.
3513 mWindowAttributes.softInputMode &=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003514 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
Jeff Browna175a5b2012-02-15 19:18:31 -08003515 ((WindowManager.LayoutParams)mView.getLayoutParams())
3516 .softInputMode &=
3517 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
3518 mHasHadWindowFocus = true;
Jun Mukai347e5d42015-12-03 01:13:31 -08003519 } else if (mCapturingView != null) {
3520 releasePointerCapture(mCapturingView);
Jeff Browna175a5b2012-02-15 19:18:31 -08003521 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003522 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003523 } break;
3524 case MSG_DIE:
3525 doDie();
3526 break;
keunyoung30f420f2013-08-02 14:23:10 -07003527 case MSG_DISPATCH_INPUT_EVENT: {
Jae Seo6a6059a2014-04-17 21:35:29 -07003528 SomeArgs args = (SomeArgs)msg.obj;
3529 InputEvent event = (InputEvent)args.arg1;
3530 InputEventReceiver receiver = (InputEventReceiver)args.arg2;
3531 enqueueInputEvent(event, receiver, 0, true);
3532 args.recycle();
Jeff Browna175a5b2012-02-15 19:18:31 -08003533 } break;
Michael Wright899d7052014-04-23 17:23:39 -07003534 case MSG_SYNTHESIZE_INPUT_EVENT: {
3535 InputEvent event = (InputEvent)msg.obj;
3536 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_UNHANDLED, true);
3537 } break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003538 case MSG_DISPATCH_KEY_FROM_IME: {
3539 if (LOCAL_LOGV) Log.v(
3540 TAG, "Dispatching key "
3541 + msg.obj + " from IME to " + mView);
3542 KeyEvent event = (KeyEvent)msg.obj;
3543 if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
3544 // The IME is trying to say this event is from the
3545 // system! Bad bad bad!
3546 //noinspection UnusedAssignment
Michael Wright899d7052014-04-23 17:23:39 -07003547 event = KeyEvent.changeFlags(event, event.getFlags() &
3548 ~KeyEvent.FLAG_FROM_SYSTEM);
Jeff Browna175a5b2012-02-15 19:18:31 -08003549 }
3550 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
3551 } break;
3552 case MSG_FINISH_INPUT_CONNECTION: {
3553 InputMethodManager imm = InputMethodManager.peekInstance();
3554 if (imm != null) {
3555 imm.reportFinishInputConnection((InputConnection)msg.obj);
3556 }
3557 } break;
3558 case MSG_CHECK_FOCUS: {
3559 InputMethodManager imm = InputMethodManager.peekInstance();
3560 if (imm != null) {
3561 imm.checkFocus();
3562 }
3563 } break;
3564 case MSG_CLOSE_SYSTEM_DIALOGS: {
3565 if (mView != null) {
3566 mView.onCloseSystemDialogs((String)msg.obj);
3567 }
3568 } break;
3569 case MSG_DISPATCH_DRAG_EVENT:
3570 case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
3571 DragEvent event = (DragEvent)msg.obj;
3572 event.mLocalState = mLocalDragState; // only present when this app called startDrag()
3573 handleDragEvent(event);
3574 } break;
3575 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
Romain Guyfbb93fa2012-12-03 18:50:35 -08003576 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj);
Jeff Browna175a5b2012-02-15 19:18:31 -08003577 } break;
3578 case MSG_UPDATE_CONFIGURATION: {
3579 Configuration config = (Configuration)msg.obj;
3580 if (config.isOtherSeqNewer(mLastConfiguration)) {
3581 config = mLastConfiguration;
3582 }
3583 updateConfiguration(config, false);
3584 } break;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003585 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003586 setAccessibilityFocus(null, null);
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003587 } break;
Dianne Hackborna53de062012-05-08 18:53:51 -07003588 case MSG_INVALIDATE_WORLD: {
Romain Guyf84208f2012-09-13 22:50:18 -07003589 if (mView != null) {
3590 invalidateWorld(mView);
3591 }
Dianne Hackborna53de062012-05-08 18:53:51 -07003592 } break;
Craig Mautner9c795042014-10-28 19:59:59 -07003593 case MSG_DISPATCH_WINDOW_SHOWN: {
3594 handleDispatchWindowShown();
Clara Bayarri75e09792015-07-29 16:20:40 +01003595 } break;
3596 case MSG_REQUEST_KEYBOARD_SHORTCUTS: {
3597 IResultReceiver receiver = (IResultReceiver) msg.obj;
3598 handleRequestKeyboardShortcuts(receiver);
3599 } break;
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08003600 case MSG_UPDATE_POINTER_ICON: {
3601 MotionEvent event = (MotionEvent) msg.obj;
3602 resetPointerIcon(event);
3603 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003604 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003605 }
3606 }
Romain Guy51e4d4d2012-03-15 18:30:47 -07003607
Jeff Browna175a5b2012-02-15 19:18:31 -08003608 final ViewRootHandler mHandler = new ViewRootHandler();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003609
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003610 /**
3611 * Something in the current window tells us we need to change the touch mode. For
3612 * example, we are not in touch mode, and the user touches the screen.
3613 *
3614 * If the touch mode has changed, tell the window manager, and handle it locally.
3615 *
3616 * @param inTouchMode Whether we want to be in touch mode.
3617 * @return True if the touch mode changed and focus changed was changed as a result
3618 */
3619 boolean ensureTouchMode(boolean inTouchMode) {
3620 if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
3621 + "touch mode is " + mAttachInfo.mInTouchMode);
3622 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3623
3624 // tell the window manager
3625 try {
Matt Wud6bc96d2016-01-14 12:59:24 -08003626 mWindowSession.setInTouchMode(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003627 } catch (RemoteException e) {
3628 throw new RuntimeException(e);
3629 }
3630
3631 // handle the change
Romain Guy2d4cff62010-04-09 15:39:00 -07003632 return ensureTouchModeLocally(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003633 }
3634
3635 /**
3636 * Ensure that the touch mode for this window is set, and if it is changing,
3637 * take the appropriate action.
3638 * @param inTouchMode Whether we want to be in touch mode.
3639 * @return True if the touch mode changed and focus changed was changed as a result
3640 */
Romain Guy2d4cff62010-04-09 15:39:00 -07003641 private boolean ensureTouchModeLocally(boolean inTouchMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003642 if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
3643 + "touch mode is " + mAttachInfo.mInTouchMode);
3644
3645 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3646
3647 mAttachInfo.mInTouchMode = inTouchMode;
3648 mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
3649
Romain Guy2d4cff62010-04-09 15:39:00 -07003650 return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003651 }
3652
3653 private boolean enterTouchMode() {
Alan Viveretteed7821a2013-07-24 15:49:23 -07003654 if (mView != null && mView.hasFocus()) {
3655 // note: not relying on mFocusedView here because this could
3656 // be when the window is first being added, and mFocused isn't
3657 // set yet.
3658 final View focused = mView.findFocus();
3659 if (focused != null && !focused.isFocusableInTouchMode()) {
3660 final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
3661 if (ancestorToTakeFocus != null) {
3662 // there is an ancestor that wants focus after its
3663 // descendants that is focusable in touch mode.. give it
3664 // focus
3665 return ancestorToTakeFocus.requestFocus();
3666 } else {
Alan Viverette973f3b42013-08-13 16:57:28 -07003667 // There's nothing to focus. Clear and propagate through the
3668 // hierarchy, but don't attempt to place new focus.
Alan Viverette223622a2013-12-17 13:29:02 -08003669 focused.clearFocusInternal(null, true, false);
Alan Viveretteed7821a2013-07-24 15:49:23 -07003670 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003671 }
3672 }
3673 }
3674 return false;
3675 }
3676
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003677 /**
3678 * Find an ancestor of focused that wants focus after its descendants and is
3679 * focusable in touch mode.
3680 * @param focused The currently focused view.
3681 * @return An appropriate view, or null if no such view exists.
3682 */
Romain Guya998dff2012-03-23 18:58:36 -07003683 private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003684 ViewParent parent = focused.getParent();
3685 while (parent instanceof ViewGroup) {
3686 final ViewGroup vgParent = (ViewGroup) parent;
3687 if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
3688 && vgParent.isFocusableInTouchMode()) {
3689 return vgParent;
3690 }
3691 if (vgParent.isRootNamespace()) {
3692 return null;
3693 } else {
3694 parent = vgParent.getParent();
3695 }
3696 }
3697 return null;
3698 }
3699
3700 private boolean leaveTouchMode() {
3701 if (mView != null) {
3702 if (mView.hasFocus()) {
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003703 View focusedView = mView.findFocus();
3704 if (!(focusedView instanceof ViewGroup)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003705 // some view has focus, let it keep it
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003706 return false;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003707 } else if (((ViewGroup) focusedView).getDescendantFocusability() !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003708 ViewGroup.FOCUS_AFTER_DESCENDANTS) {
3709 // some view group has focus, and doesn't prefer its children
3710 // over itself for focus, so let them keep it.
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003711 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003712 }
3713 }
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003714
3715 // find the best view to give focus to in this brave new non-touch-mode
3716 // world
3717 final View focused = focusSearch(null, View.FOCUS_DOWN);
3718 if (focused != null) {
3719 return focused.requestFocus(View.FOCUS_DOWN);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003720 }
3721 }
3722 return false;
3723 }
3724
Jeff Brownf9e989d2013-04-04 23:04:03 -07003725 /**
3726 * Base class for implementing a stage in the chain of responsibility
3727 * for processing input events.
3728 * <p>
3729 * Events are delivered to the stage by the {@link #deliver} method. The stage
3730 * then has the choice of finishing the event or forwarding it to the next stage.
3731 * </p>
3732 */
3733 abstract class InputStage {
3734 private final InputStage mNext;
3735
3736 protected static final int FORWARD = 0;
3737 protected static final int FINISH_HANDLED = 1;
3738 protected static final int FINISH_NOT_HANDLED = 2;
3739
3740 /**
3741 * Creates an input stage.
3742 * @param next The next stage to which events should be forwarded.
3743 */
3744 public InputStage(InputStage next) {
3745 mNext = next;
3746 }
3747
3748 /**
3749 * Delivers an event to be processed.
3750 */
3751 public final void deliver(QueuedInputEvent q) {
3752 if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
3753 forward(q);
Michael Wright17d28ca2013-10-31 17:47:45 -07003754 } else if (shouldDropInputEvent(q)) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003755 finish(q, false);
3756 } else {
3757 apply(q, onProcess(q));
3758 }
3759 }
3760
3761 /**
3762 * Marks the the input event as finished then forwards it to the next stage.
3763 */
3764 protected void finish(QueuedInputEvent q, boolean handled) {
3765 q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
3766 if (handled) {
3767 q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
3768 }
3769 forward(q);
3770 }
3771
3772 /**
3773 * Forwards the event to the next stage.
3774 */
3775 protected void forward(QueuedInputEvent q) {
3776 onDeliverToNext(q);
3777 }
3778
3779 /**
3780 * Applies a result code from {@link #onProcess} to the specified event.
3781 */
3782 protected void apply(QueuedInputEvent q, int result) {
3783 if (result == FORWARD) {
3784 forward(q);
3785 } else if (result == FINISH_HANDLED) {
3786 finish(q, true);
3787 } else if (result == FINISH_NOT_HANDLED) {
3788 finish(q, false);
3789 } else {
3790 throw new IllegalArgumentException("Invalid result: " + result);
3791 }
3792 }
3793
3794 /**
3795 * Called when an event is ready to be processed.
3796 * @return A result code indicating how the event was handled.
3797 */
3798 protected int onProcess(QueuedInputEvent q) {
3799 return FORWARD;
3800 }
3801
3802 /**
3803 * Called when an event is being delivered to the next stage.
3804 */
3805 protected void onDeliverToNext(QueuedInputEvent q) {
Michael Wright06a79252014-05-05 17:45:29 -07003806 if (DEBUG_INPUT_STAGES) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003807 Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);
Michael Wright06a79252014-05-05 17:45:29 -07003808 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003809 if (mNext != null) {
3810 mNext.deliver(q);
3811 } else {
3812 finishInputEvent(q);
3813 }
3814 }
Jeff Brown5182c782013-10-15 20:31:52 -07003815
Michael Wright17d28ca2013-10-31 17:47:45 -07003816 protected boolean shouldDropInputEvent(QueuedInputEvent q) {
3817 if (mView == null || !mAdded) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003818 Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent);
Michael Wright17d28ca2013-10-31 17:47:45 -07003819 return true;
George Mount41725de2015-04-09 08:23:05 -07003820 } else if ((!mAttachInfo.mHasWindowFocus
3821 && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) || mStopped
Joe LaPenna90776de2016-01-22 07:11:49 -08003822 || (mIsAmbientMode && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON))
3823 || (mPausedForTransition && !isBack(q.mEvent))) {
Wale Ogunwalec3672cd2014-11-05 15:17:35 -08003824 // This is a focus event and the window doesn't currently have input focus or
3825 // has stopped. This could be an event that came back from the previous stage
3826 // but the window has lost focus or stopped in the meantime.
3827 if (isTerminalInputEvent(q.mEvent)) {
3828 // Don't drop terminal input events, however mark them as canceled.
3829 q.mEvent.cancel();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003830 Slog.w(mTag, "Cancelling event due to no window focus: " + q.mEvent);
Wale Ogunwalec3672cd2014-11-05 15:17:35 -08003831 return false;
3832 }
3833
3834 // Drop non-terminal input events.
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003835 Slog.w(mTag, "Dropping event due to no window focus: " + q.mEvent);
Michael Wright17d28ca2013-10-31 17:47:45 -07003836 return true;
3837 }
3838 return false;
3839 }
3840
Jeff Brown5182c782013-10-15 20:31:52 -07003841 void dump(String prefix, PrintWriter writer) {
3842 if (mNext != null) {
3843 mNext.dump(prefix, writer);
3844 }
3845 }
George Mount41725de2015-04-09 08:23:05 -07003846
3847 private boolean isBack(InputEvent event) {
3848 if (event instanceof KeyEvent) {
3849 return ((KeyEvent) event).getKeyCode() == KeyEvent.KEYCODE_BACK;
3850 } else {
3851 return false;
3852 }
3853 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003854 }
3855
3856 /**
3857 * Base class for implementing an input pipeline stage that supports
3858 * asynchronous and out-of-order processing of input events.
3859 * <p>
3860 * In addition to what a normal input stage can do, an asynchronous
3861 * input stage may also defer an input event that has been delivered to it
3862 * and finish or forward it later.
3863 * </p>
3864 */
3865 abstract class AsyncInputStage extends InputStage {
3866 private final String mTraceCounter;
3867
3868 private QueuedInputEvent mQueueHead;
3869 private QueuedInputEvent mQueueTail;
3870 private int mQueueLength;
3871
3872 protected static final int DEFER = 3;
3873
3874 /**
3875 * Creates an asynchronous input stage.
3876 * @param next The next stage to which events should be forwarded.
3877 * @param traceCounter The name of a counter to record the size of
3878 * the queue of pending events.
3879 */
3880 public AsyncInputStage(InputStage next, String traceCounter) {
3881 super(next);
3882 mTraceCounter = traceCounter;
3883 }
3884
3885 /**
3886 * Marks the event as deferred, which is to say that it will be handled
3887 * asynchronously. The caller is responsible for calling {@link #forward}
3888 * or {@link #finish} later when it is done handling the event.
3889 */
3890 protected void defer(QueuedInputEvent q) {
3891 q.mFlags |= QueuedInputEvent.FLAG_DEFERRED;
3892 enqueue(q);
3893 }
3894
3895 @Override
3896 protected void forward(QueuedInputEvent q) {
3897 // Clear the deferred flag.
3898 q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED;
3899
3900 // Fast path if the queue is empty.
3901 QueuedInputEvent curr = mQueueHead;
3902 if (curr == null) {
3903 super.forward(q);
3904 return;
3905 }
3906
3907 // Determine whether the event must be serialized behind any others
3908 // before it can be delivered to the next stage. This is done because
3909 // deferred events might be handled out of order by the stage.
3910 final int deviceId = q.mEvent.getDeviceId();
3911 QueuedInputEvent prev = null;
3912 boolean blocked = false;
3913 while (curr != null && curr != q) {
3914 if (!blocked && deviceId == curr.mEvent.getDeviceId()) {
3915 blocked = true;
3916 }
3917 prev = curr;
3918 curr = curr.mNext;
3919 }
3920
3921 // If the event is blocked, then leave it in the queue to be delivered later.
3922 // Note that the event might not yet be in the queue if it was not previously
3923 // deferred so we will enqueue it if needed.
3924 if (blocked) {
3925 if (curr == null) {
3926 enqueue(q);
3927 }
3928 return;
3929 }
3930
3931 // The event is not blocked. Deliver it immediately.
3932 if (curr != null) {
3933 curr = curr.mNext;
3934 dequeue(q, prev);
3935 }
3936 super.forward(q);
3937
3938 // Dequeuing this event may have unblocked successors. Deliver them.
3939 while (curr != null) {
3940 if (deviceId == curr.mEvent.getDeviceId()) {
3941 if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) {
3942 break;
3943 }
3944 QueuedInputEvent next = curr.mNext;
3945 dequeue(curr, prev);
3946 super.forward(curr);
3947 curr = next;
3948 } else {
3949 prev = curr;
3950 curr = curr.mNext;
3951 }
3952 }
3953 }
3954
3955 @Override
3956 protected void apply(QueuedInputEvent q, int result) {
3957 if (result == DEFER) {
3958 defer(q);
3959 } else {
3960 super.apply(q, result);
3961 }
3962 }
3963
3964 private void enqueue(QueuedInputEvent q) {
3965 if (mQueueTail == null) {
3966 mQueueHead = q;
3967 mQueueTail = q;
3968 } else {
3969 mQueueTail.mNext = q;
3970 mQueueTail = q;
3971 }
3972
3973 mQueueLength += 1;
3974 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
3975 }
3976
3977 private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) {
3978 if (prev == null) {
3979 mQueueHead = q.mNext;
3980 } else {
3981 prev.mNext = q.mNext;
3982 }
3983 if (mQueueTail == q) {
3984 mQueueTail = prev;
3985 }
3986 q.mNext = null;
3987
3988 mQueueLength -= 1;
3989 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
3990 }
Jeff Brown5182c782013-10-15 20:31:52 -07003991
3992 @Override
3993 void dump(String prefix, PrintWriter writer) {
3994 writer.print(prefix);
3995 writer.print(getClass().getName());
3996 writer.print(": mQueueLength=");
3997 writer.println(mQueueLength);
3998
3999 super.dump(prefix, writer);
4000 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004001 }
4002
4003 /**
4004 * Delivers pre-ime input events to a native activity.
4005 * Does not support pointer events.
4006 */
Michael Wrighta44dd262013-04-10 21:12:00 -07004007 final class NativePreImeInputStage extends AsyncInputStage
4008 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004009 public NativePreImeInputStage(InputStage next, String traceCounter) {
4010 super(next, traceCounter);
4011 }
4012
4013 @Override
4014 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07004015 if (mInputQueue != null && q.mEvent instanceof KeyEvent) {
4016 mInputQueue.sendInputEvent(q.mEvent, q, true, this);
4017 return DEFER;
4018 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004019 return FORWARD;
4020 }
Michael Wrighta44dd262013-04-10 21:12:00 -07004021
4022 @Override
4023 public void onFinishedInputEvent(Object token, boolean handled) {
4024 QueuedInputEvent q = (QueuedInputEvent)token;
4025 if (handled) {
4026 finish(q, true);
4027 return;
4028 }
4029 forward(q);
4030 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004031 }
4032
4033 /**
4034 * Delivers pre-ime input events to the view hierarchy.
4035 * Does not support pointer events.
4036 */
4037 final class ViewPreImeInputStage extends InputStage {
4038 public ViewPreImeInputStage(InputStage next) {
4039 super(next);
4040 }
4041
4042 @Override
4043 protected int onProcess(QueuedInputEvent q) {
Jeff Brown481c1572012-03-09 14:41:15 -08004044 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004045 return processKeyEvent(q);
4046 }
4047 return FORWARD;
4048 }
4049
4050 private int processKeyEvent(QueuedInputEvent q) {
4051 final KeyEvent event = (KeyEvent)q.mEvent;
4052 if (mView.dispatchKeyEventPreIme(event)) {
4053 return FINISH_HANDLED;
4054 }
4055 return FORWARD;
4056 }
4057 }
4058
4059 /**
4060 * Delivers input events to the ime.
4061 * Does not support pointer events.
4062 */
4063 final class ImeInputStage extends AsyncInputStage
4064 implements InputMethodManager.FinishedInputEventCallback {
4065 public ImeInputStage(InputStage next, String traceCounter) {
4066 super(next, traceCounter);
4067 }
4068
4069 @Override
4070 protected int onProcess(QueuedInputEvent q) {
keunyoung30f420f2013-08-02 14:23:10 -07004071 if (mLastWasImTarget && !isInLocalFocusMode()) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004072 InputMethodManager imm = InputMethodManager.peekInstance();
4073 if (imm != null) {
4074 final InputEvent event = q.mEvent;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004075 if (DEBUG_IMF) Log.v(mTag, "Sending input event to IME: " + event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004076 int result = imm.dispatchInputEvent(event, q, this, mHandler);
4077 if (result == InputMethodManager.DISPATCH_HANDLED) {
4078 return FINISH_HANDLED;
4079 } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
Adam Lesinskic0f6eed2013-10-28 16:03:19 -07004080 // The IME could not handle it, so skip along to the next InputStage
4081 return FORWARD;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004082 } else {
4083 return DEFER; // callback will be invoked later
4084 }
4085 }
4086 }
4087 return FORWARD;
4088 }
4089
4090 @Override
4091 public void onFinishedInputEvent(Object token, boolean handled) {
4092 QueuedInputEvent q = (QueuedInputEvent)token;
4093 if (handled) {
4094 finish(q, true);
4095 return;
4096 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004097 forward(q);
4098 }
4099 }
4100
4101 /**
4102 * Performs early processing of post-ime input events.
4103 */
4104 final class EarlyPostImeInputStage extends InputStage {
4105 public EarlyPostImeInputStage(InputStage next) {
4106 super(next);
4107 }
4108
4109 @Override
4110 protected int onProcess(QueuedInputEvent q) {
4111 if (q.mEvent instanceof KeyEvent) {
4112 return processKeyEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08004113 } else {
Jeff Brown481c1572012-03-09 14:41:15 -08004114 final int source = q.mEvent.getSource();
4115 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004116 return processPointerEvent(q);
Jeff Brown481c1572012-03-09 14:41:15 -08004117 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08004118 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004119 return FORWARD;
4120 }
4121
4122 private int processKeyEvent(QueuedInputEvent q) {
4123 final KeyEvent event = (KeyEvent)q.mEvent;
4124
4125 // If the key's purpose is to exit touch mode then we consume it
4126 // and consider it handled.
4127 if (checkForLeavingTouchModeAndConsume(event)) {
4128 return FINISH_HANDLED;
4129 }
4130
4131 // Make sure the fallback event policy sees all keys that will be
4132 // delivered to the view hierarchy.
4133 mFallbackEventHandler.preDispatchKeyEvent(event);
4134 return FORWARD;
4135 }
4136
4137 private int processPointerEvent(QueuedInputEvent q) {
4138 final MotionEvent event = (MotionEvent)q.mEvent;
4139
4140 // Translate the pointer event for compatibility, if needed.
4141 if (mTranslator != null) {
4142 mTranslator.translateEventInScreenToAppWindow(event);
4143 }
4144
4145 // Enter touch mode on down or scroll.
4146 final int action = event.getAction();
4147 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
4148 ensureTouchMode(true);
4149 }
4150
4151 // Offset the scroll position.
4152 if (mCurScrollY != 0) {
4153 event.offsetLocation(0, mCurScrollY);
4154 }
4155
4156 // Remember the touch position for possible drag-initiation.
4157 if (event.isTouchEvent()) {
4158 mLastTouchPoint.x = event.getRawX();
4159 mLastTouchPoint.y = event.getRawY();
Vladislav Kaznacheevba761122016-01-22 12:09:45 -08004160 mLastTouchSource = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004161 }
4162 return FORWARD;
Jeff Brown4952dfd2011-11-30 19:23:22 -08004163 }
4164 }
4165
Jeff Brownf9e989d2013-04-04 23:04:03 -07004166 /**
4167 * Delivers post-ime input events to a native activity.
4168 */
Michael Wrighta44dd262013-04-10 21:12:00 -07004169 final class NativePostImeInputStage extends AsyncInputStage
4170 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004171 public NativePostImeInputStage(InputStage next, String traceCounter) {
4172 super(next, traceCounter);
4173 }
4174
4175 @Override
4176 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07004177 if (mInputQueue != null) {
4178 mInputQueue.sendInputEvent(q.mEvent, q, false, this);
4179 return DEFER;
4180 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004181 return FORWARD;
4182 }
Michael Wrighta44dd262013-04-10 21:12:00 -07004183
4184 @Override
4185 public void onFinishedInputEvent(Object token, boolean handled) {
4186 QueuedInputEvent q = (QueuedInputEvent)token;
4187 if (handled) {
4188 finish(q, true);
4189 return;
4190 }
4191 forward(q);
4192 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004193 }
4194
4195 /**
4196 * Delivers post-ime input events to the view hierarchy.
4197 */
4198 final class ViewPostImeInputStage extends InputStage {
4199 public ViewPostImeInputStage(InputStage next) {
4200 super(next);
4201 }
4202
4203 @Override
4204 protected int onProcess(QueuedInputEvent q) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08004205 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004206 return processKeyEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08004207 } else {
4208 final int source = q.mEvent.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004209 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
4210 return processPointerEvent(q);
4211 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
4212 return processTrackballEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08004213 } else {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004214 return processGenericMotionEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08004215 }
4216 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08004217 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08004218
Michael Wright9d744c72014-02-18 21:27:42 -08004219 @Override
4220 protected void onDeliverToNext(QueuedInputEvent q) {
4221 if (mUnbufferedInputDispatch
4222 && q.mEvent instanceof MotionEvent
4223 && ((MotionEvent)q.mEvent).isTouchEvent()
4224 && isTerminalInputEvent(q.mEvent)) {
4225 mUnbufferedInputDispatch = false;
4226 scheduleConsumeBatchedInput();
4227 }
4228 super.onDeliverToNext(q);
4229 }
4230
Jeff Brownf9e989d2013-04-04 23:04:03 -07004231 private int processKeyEvent(QueuedInputEvent q) {
4232 final KeyEvent event = (KeyEvent)q.mEvent;
4233
4234 // Deliver the key to the view hierarchy.
4235 if (mView.dispatchKeyEvent(event)) {
4236 return FINISH_HANDLED;
Jeff Brown21bc5c92011-02-28 18:27:14 -08004237 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004238
Michael Wright17d28ca2013-10-31 17:47:45 -07004239 if (shouldDropInputEvent(q)) {
4240 return FINISH_NOT_HANDLED;
4241 }
4242
Jeff Brownf9e989d2013-04-04 23:04:03 -07004243 // If the Control modifier is held, try to interpret the key as a shortcut.
4244 if (event.getAction() == KeyEvent.ACTION_DOWN
4245 && event.isCtrlPressed()
4246 && event.getRepeatCount() == 0
4247 && !KeyEvent.isModifierKey(event.getKeyCode())) {
4248 if (mView.dispatchKeyShortcutEvent(event)) {
4249 return FINISH_HANDLED;
4250 }
Michael Wright17d28ca2013-10-31 17:47:45 -07004251 if (shouldDropInputEvent(q)) {
4252 return FINISH_NOT_HANDLED;
4253 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004254 }
4255
4256 // Apply the fallback event policy.
4257 if (mFallbackEventHandler.dispatchKeyEvent(event)) {
4258 return FINISH_HANDLED;
4259 }
Michael Wright17d28ca2013-10-31 17:47:45 -07004260 if (shouldDropInputEvent(q)) {
4261 return FINISH_NOT_HANDLED;
4262 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004263
4264 // Handle automatic focus changes.
4265 if (event.getAction() == KeyEvent.ACTION_DOWN) {
4266 int direction = 0;
4267 switch (event.getKeyCode()) {
4268 case KeyEvent.KEYCODE_DPAD_LEFT:
4269 if (event.hasNoModifiers()) {
4270 direction = View.FOCUS_LEFT;
4271 }
4272 break;
4273 case KeyEvent.KEYCODE_DPAD_RIGHT:
4274 if (event.hasNoModifiers()) {
4275 direction = View.FOCUS_RIGHT;
4276 }
4277 break;
4278 case KeyEvent.KEYCODE_DPAD_UP:
4279 if (event.hasNoModifiers()) {
4280 direction = View.FOCUS_UP;
4281 }
4282 break;
4283 case KeyEvent.KEYCODE_DPAD_DOWN:
4284 if (event.hasNoModifiers()) {
4285 direction = View.FOCUS_DOWN;
4286 }
4287 break;
4288 case KeyEvent.KEYCODE_TAB:
4289 if (event.hasNoModifiers()) {
4290 direction = View.FOCUS_FORWARD;
4291 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
4292 direction = View.FOCUS_BACKWARD;
4293 }
4294 break;
4295 }
4296 if (direction != 0) {
4297 View focused = mView.findFocus();
4298 if (focused != null) {
4299 View v = focused.focusSearch(direction);
4300 if (v != null && v != focused) {
4301 // do the math the get the interesting rect
4302 // of previous focused into the coord system of
4303 // newly focused view
4304 focused.getFocusedRect(mTempRect);
4305 if (mView instanceof ViewGroup) {
4306 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
4307 focused, mTempRect);
4308 ((ViewGroup) mView).offsetRectIntoDescendantCoords(
4309 v, mTempRect);
4310 }
4311 if (v.requestFocus(direction, mTempRect)) {
4312 playSoundEffect(SoundEffectConstants
4313 .getContantForFocusDirection(direction));
4314 return FINISH_HANDLED;
4315 }
4316 }
4317
4318 // Give the focused view a last chance to handle the dpad key.
4319 if (mView.dispatchUnhandledMove(focused, direction)) {
4320 return FINISH_HANDLED;
4321 }
4322 } else {
4323 // find the best view to give focus to in this non-touch-mode with no-focus
4324 View v = focusSearch(null, direction);
4325 if (v != null && v.requestFocus(direction)) {
4326 return FINISH_HANDLED;
4327 }
4328 }
4329 }
4330 }
4331 return FORWARD;
Jeff Brown21bc5c92011-02-28 18:27:14 -08004332 }
4333
Jeff Brownf9e989d2013-04-04 23:04:03 -07004334 private int processPointerEvent(QueuedInputEvent q) {
4335 final MotionEvent event = (MotionEvent)q.mEvent;
4336
Vladislav Kaznacheev527905e2016-02-16 16:20:56 -08004337 mAttachInfo.mUnbufferedDispatchRequested = false;
4338 final View eventTarget =
4339 (event.isFromSource(InputDevice.SOURCE_MOUSE) && mCapturingView != null) ?
4340 mCapturingView : mView;
4341 mAttachInfo.mHandlingPointerEvent = true;
4342 boolean handled = eventTarget.dispatchPointerEvent(event);
4343 maybeUpdatePointerIcon(event);
4344 mAttachInfo.mHandlingPointerEvent = false;
4345 if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
4346 mUnbufferedInputDispatch = true;
4347 if (mConsumeBatchedInputScheduled) {
4348 scheduleConsumeBatchedInputImmediately();
4349 }
4350 }
4351 return handled ? FINISH_HANDLED : FORWARD;
4352 }
4353
4354 private void maybeUpdatePointerIcon(MotionEvent event) {
Jun Mukai1db53972015-09-11 18:08:31 -07004355 if (event.getPointerCount() == 1
4356 && event.isFromSource(InputDevice.SOURCE_MOUSE)) {
4357 if (event.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER
4358 || event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
4359 // Other apps or the window manager may change the icon shape outside of
4360 // this app, therefore the icon shape has to be reset on enter/exit event.
4361 mPointerIconShape = PointerIcon.STYLE_NOT_SPECIFIED;
4362 }
4363
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08004364 if (event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT) {
4365 if (!updatePointerIcon(event) &&
4366 event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) {
4367 mPointerIconShape = PointerIcon.STYLE_NOT_SPECIFIED;
Jun Mukai1db53972015-09-11 18:08:31 -07004368 }
4369 }
4370 }
Jeff Brown3915bb82010-11-05 15:02:16 -07004371 }
4372
Jeff Brownf9e989d2013-04-04 23:04:03 -07004373 private int processTrackballEvent(QueuedInputEvent q) {
4374 final MotionEvent event = (MotionEvent)q.mEvent;
4375
4376 if (mView.dispatchTrackballEvent(event)) {
4377 return FINISH_HANDLED;
4378 }
4379 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004380 }
4381
Jeff Brownf9e989d2013-04-04 23:04:03 -07004382 private int processGenericMotionEvent(QueuedInputEvent q) {
4383 final MotionEvent event = (MotionEvent)q.mEvent;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07004384
Jeff Brownf9e989d2013-04-04 23:04:03 -07004385 // Deliver the event to the view.
4386 if (mView.dispatchGenericMotionEvent(event)) {
4387 return FINISH_HANDLED;
4388 }
4389 return FORWARD;
Jeff Brown3915bb82010-11-05 15:02:16 -07004390 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07004391 }
4392
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08004393 private void resetPointerIcon(MotionEvent event) {
4394 mPointerIconShape = PointerIcon.STYLE_NOT_SPECIFIED;
4395 updatePointerIcon(event);
4396 }
4397
4398 private boolean updatePointerIcon(MotionEvent event) {
4399 final float x = event.getX();
4400 final float y = event.getY();
Andrii Kulian33c1bc52016-02-29 10:38:59 -08004401 if (mView == null) {
4402 // E.g. click outside a popup to dismiss it
4403 Slog.d(mTag, "updatePointerIcon called after view was removed");
4404 return false;
4405 }
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08004406 if (x < 0 || x >= mView.getWidth() || y < 0 || y >= mView.getHeight()) {
Andrii Kulian33c1bc52016-02-29 10:38:59 -08004407 // E.g. when moving window divider with mouse
4408 Slog.d(mTag, "updatePointerIcon called with position out of bounds");
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08004409 return false;
4410 }
4411 final PointerIcon pointerIcon = mView.getPointerIcon(event, x, y);
4412 final int pointerShape = (pointerIcon != null) ?
4413 pointerIcon.getStyle() : PointerIcon.STYLE_DEFAULT;
4414
4415 if (mPointerIconShape != pointerShape) {
4416 mPointerIconShape = pointerShape;
4417 if (mPointerIconShape != PointerIcon.STYLE_CUSTOM) {
4418 mCustomPointerIcon = null;
4419 InputManager.getInstance().setPointerIconShape(pointerShape);
4420 return true;
4421 }
4422 }
4423 if (mPointerIconShape == PointerIcon.STYLE_CUSTOM &&
4424 !pointerIcon.equals(mCustomPointerIcon)) {
4425 mCustomPointerIcon = pointerIcon;
4426 InputManager.getInstance().setCustomPointerIcon(mCustomPointerIcon);
4427 }
4428 return true;
4429 }
4430
Jeff Brownf9e989d2013-04-04 23:04:03 -07004431 /**
Jeff Brown678a1252013-04-09 17:46:25 -07004432 * Performs synthesis of new input events from unhandled input events.
Jeff Brownf9e989d2013-04-04 23:04:03 -07004433 */
4434 final class SyntheticInputStage extends InputStage {
Jeff Brown678a1252013-04-09 17:46:25 -07004435 private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler();
4436 private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
4437 private final SyntheticTouchNavigationHandler mTouchNavigation =
4438 new SyntheticTouchNavigationHandler();
Michael Wright899d7052014-04-23 17:23:39 -07004439 private final SyntheticKeyboardHandler mKeyboard = new SyntheticKeyboardHandler();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004440
4441 public SyntheticInputStage() {
4442 super(null);
Jeff Brown21bc5c92011-02-28 18:27:14 -08004443 }
4444
Jeff Brownf9e989d2013-04-04 23:04:03 -07004445 @Override
4446 protected int onProcess(QueuedInputEvent q) {
4447 q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED;
4448 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07004449 final MotionEvent event = (MotionEvent)q.mEvent;
4450 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004451 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004452 mTrackball.process(event);
4453 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004454 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004455 mJoystick.process(event);
4456 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004457 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
4458 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07004459 mTouchNavigation.process(event);
4460 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004461 }
Michael Wright899d7052014-04-23 17:23:39 -07004462 } else if ((q.mFlags & QueuedInputEvent.FLAG_UNHANDLED) != 0) {
4463 mKeyboard.process((KeyEvent)q.mEvent);
4464 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004465 }
Michael Wright899d7052014-04-23 17:23:39 -07004466
Jeff Brownf9e989d2013-04-04 23:04:03 -07004467 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004468 }
4469
Jeff Brownf9e989d2013-04-04 23:04:03 -07004470 @Override
4471 protected void onDeliverToNext(QueuedInputEvent q) {
4472 if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) {
4473 // Cancel related synthetic events if any prior stage has handled the event.
4474 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07004475 final MotionEvent event = (MotionEvent)q.mEvent;
4476 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004477 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004478 mTrackball.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004479 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004480 mJoystick.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004481 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
4482 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07004483 mTouchNavigation.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004484 }
4485 }
4486 }
4487 super.onDeliverToNext(q);
4488 }
Jeff Brown678a1252013-04-09 17:46:25 -07004489 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004490
Jeff Brown678a1252013-04-09 17:46:25 -07004491 /**
4492 * Creates dpad events from unhandled trackball movements.
4493 */
4494 final class SyntheticTrackballHandler {
4495 private final TrackballAxis mX = new TrackballAxis();
4496 private final TrackballAxis mY = new TrackballAxis();
4497 private long mLastTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004498
Jeff Brown678a1252013-04-09 17:46:25 -07004499 public void process(MotionEvent event) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004500 // Translate the trackball event into DPAD keys and try to deliver those.
Jeff Brownf9e989d2013-04-04 23:04:03 -07004501 long curTime = SystemClock.uptimeMillis();
Jeff Brown678a1252013-04-09 17:46:25 -07004502 if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004503 // It has been too long since the last movement,
4504 // so restart at the beginning.
Jeff Brown678a1252013-04-09 17:46:25 -07004505 mX.reset(0);
4506 mY.reset(0);
4507 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004508 }
4509
4510 final int action = event.getAction();
4511 final int metaState = event.getMetaState();
4512 switch (action) {
4513 case MotionEvent.ACTION_DOWN:
Jeff Brown678a1252013-04-09 17:46:25 -07004514 mX.reset(2);
4515 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004516 enqueueInputEvent(new KeyEvent(curTime, curTime,
4517 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
4518 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4519 InputDevice.SOURCE_KEYBOARD));
4520 break;
4521 case MotionEvent.ACTION_UP:
Jeff Brown678a1252013-04-09 17:46:25 -07004522 mX.reset(2);
4523 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004524 enqueueInputEvent(new KeyEvent(curTime, curTime,
4525 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
4526 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4527 InputDevice.SOURCE_KEYBOARD));
4528 break;
4529 }
4530
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004531 if (DEBUG_TRACKBALL) Log.v(mTag, "TB X=" + mX.position + " step="
Jeff Brown678a1252013-04-09 17:46:25 -07004532 + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07004533 + " move=" + event.getX()
Jeff Brown678a1252013-04-09 17:46:25 -07004534 + " / Y=" + mY.position + " step="
4535 + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07004536 + " move=" + event.getY());
Jeff Brown678a1252013-04-09 17:46:25 -07004537 final float xOff = mX.collect(event.getX(), event.getEventTime(), "X");
4538 final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y");
Jeff Brownf9e989d2013-04-04 23:04:03 -07004539
4540 // Generate DPAD events based on the trackball movement.
4541 // We pick the axis that has moved the most as the direction of
4542 // the DPAD. When we generate DPAD events for one axis, then the
4543 // other axis is reset -- we don't want to perform DPAD jumps due
4544 // to slight movements in the trackball when making major movements
4545 // along the other axis.
4546 int keycode = 0;
4547 int movement = 0;
4548 float accel = 1;
4549 if (xOff > yOff) {
Jeff Brown678a1252013-04-09 17:46:25 -07004550 movement = mX.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004551 if (movement != 0) {
4552 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
4553 : KeyEvent.KEYCODE_DPAD_LEFT;
Jeff Brown678a1252013-04-09 17:46:25 -07004554 accel = mX.acceleration;
4555 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004556 }
4557 } else if (yOff > 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004558 movement = mY.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004559 if (movement != 0) {
4560 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
4561 : KeyEvent.KEYCODE_DPAD_UP;
Jeff Brown678a1252013-04-09 17:46:25 -07004562 accel = mY.acceleration;
4563 mX.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004564 }
4565 }
4566
4567 if (keycode != 0) {
4568 if (movement < 0) movement = -movement;
4569 int accelMovement = (int)(movement * accel);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004570 if (DEBUG_TRACKBALL) Log.v(mTag, "Move: movement=" + movement
Jeff Brownf9e989d2013-04-04 23:04:03 -07004571 + " accelMovement=" + accelMovement
4572 + " accel=" + accel);
4573 if (accelMovement > movement) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004574 if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
Jeff Brownf9e989d2013-04-04 23:04:03 -07004575 + keycode);
4576 movement--;
4577 int repeatCount = accelMovement - movement;
4578 enqueueInputEvent(new KeyEvent(curTime, curTime,
4579 KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
4580 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4581 InputDevice.SOURCE_KEYBOARD));
4582 }
4583 while (movement > 0) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004584 if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
Jeff Brownf9e989d2013-04-04 23:04:03 -07004585 + keycode);
4586 movement--;
4587 curTime = SystemClock.uptimeMillis();
4588 enqueueInputEvent(new KeyEvent(curTime, curTime,
4589 KeyEvent.ACTION_DOWN, keycode, 0, metaState,
4590 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4591 InputDevice.SOURCE_KEYBOARD));
4592 enqueueInputEvent(new KeyEvent(curTime, curTime,
4593 KeyEvent.ACTION_UP, keycode, 0, metaState,
4594 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4595 InputDevice.SOURCE_KEYBOARD));
4596 }
Jeff Brown678a1252013-04-09 17:46:25 -07004597 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004598 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004599 }
4600
Jeff Brown678a1252013-04-09 17:46:25 -07004601 public void cancel(MotionEvent event) {
4602 mLastTime = Integer.MIN_VALUE;
Jeff Brown3915bb82010-11-05 15:02:16 -07004603
Jeff Brownf9e989d2013-04-04 23:04:03 -07004604 // If we reach this, we consumed a trackball event.
4605 // Because we will not translate the trackball event into a key event,
4606 // touch mode will not exit, so we exit touch mode here.
4607 if (mView != null && mAdded) {
4608 ensureTouchMode(false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07004609 }
4610 }
Jeff Brown678a1252013-04-09 17:46:25 -07004611 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004612
Jeff Brown678a1252013-04-09 17:46:25 -07004613 /**
4614 * Maintains state information for a single trackball axis, generating
4615 * discrete (DPAD) movements based on raw trackball motion.
4616 */
4617 static final class TrackballAxis {
4618 /**
4619 * The maximum amount of acceleration we will apply.
4620 */
4621 static final float MAX_ACCELERATION = 20;
4622
4623 /**
4624 * The maximum amount of time (in milliseconds) between events in order
4625 * for us to consider the user to be doing fast trackball movements,
4626 * and thus apply an acceleration.
4627 */
4628 static final long FAST_MOVE_TIME = 150;
4629
4630 /**
4631 * Scaling factor to the time (in milliseconds) between events to how
4632 * much to multiple/divide the current acceleration. When movement
4633 * is < FAST_MOVE_TIME this multiplies the acceleration; when >
4634 * FAST_MOVE_TIME it divides it.
4635 */
4636 static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
4637
4638 static final float FIRST_MOVEMENT_THRESHOLD = 0.5f;
4639 static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f;
4640 static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f;
4641
4642 float position;
4643 float acceleration = 1;
4644 long lastMoveTime = 0;
4645 int step;
4646 int dir;
4647 int nonAccelMovement;
4648
4649 void reset(int _step) {
4650 position = 0;
4651 acceleration = 1;
4652 lastMoveTime = 0;
4653 step = _step;
4654 dir = 0;
Jeff Brown6f2fba42011-02-19 01:08:02 -08004655 }
4656
Jeff Brown678a1252013-04-09 17:46:25 -07004657 /**
4658 * Add trackball movement into the state. If the direction of movement
4659 * has been reversed, the state is reset before adding the
4660 * movement (so that you don't have to compensate for any previously
4661 * collected movement before see the result of the movement in the
4662 * new direction).
4663 *
4664 * @return Returns the absolute value of the amount of movement
4665 * collected so far.
4666 */
4667 float collect(float off, long time, String axis) {
4668 long normTime;
4669 if (off > 0) {
4670 normTime = (long)(off * FAST_MOVE_TIME);
4671 if (dir < 0) {
4672 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
4673 position = 0;
4674 step = 0;
4675 acceleration = 1;
4676 lastMoveTime = 0;
4677 }
4678 dir = 1;
4679 } else if (off < 0) {
4680 normTime = (long)((-off) * FAST_MOVE_TIME);
4681 if (dir > 0) {
4682 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
4683 position = 0;
4684 step = 0;
4685 acceleration = 1;
4686 lastMoveTime = 0;
4687 }
4688 dir = -1;
4689 } else {
4690 normTime = 0;
4691 }
4692
4693 // The number of milliseconds between each movement that is
4694 // considered "normal" and will not result in any acceleration
4695 // or deceleration, scaled by the offset we have here.
4696 if (normTime > 0) {
4697 long delta = time - lastMoveTime;
4698 lastMoveTime = time;
4699 float acc = acceleration;
4700 if (delta < normTime) {
4701 // The user is scrolling rapidly, so increase acceleration.
4702 float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
4703 if (scale > 1) acc *= scale;
4704 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
4705 + off + " normTime=" + normTime + " delta=" + delta
4706 + " scale=" + scale + " acc=" + acc);
4707 acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
4708 } else {
4709 // The user is scrolling slowly, so decrease acceleration.
4710 float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
4711 if (scale > 1) acc /= scale;
4712 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
4713 + off + " normTime=" + normTime + " delta=" + delta
4714 + " scale=" + scale + " acc=" + acc);
4715 acceleration = acc > 1 ? acc : 1;
4716 }
4717 }
4718 position += off;
4719 return Math.abs(position);
Jeff Brown6f2fba42011-02-19 01:08:02 -08004720 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004721
Jeff Brown678a1252013-04-09 17:46:25 -07004722 /**
4723 * Generate the number of discrete movement events appropriate for
4724 * the currently collected trackball movement.
4725 *
4726 * @return Returns the number of discrete movements, either positive
4727 * or negative, or 0 if there is not enough trackball movement yet
4728 * for a discrete movement.
4729 */
4730 int generate() {
4731 int movement = 0;
4732 nonAccelMovement = 0;
4733 do {
4734 final int dir = position >= 0 ? 1 : -1;
4735 switch (step) {
4736 // If we are going to execute the first step, then we want
4737 // to do this as soon as possible instead of waiting for
4738 // a full movement, in order to make things look responsive.
4739 case 0:
4740 if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) {
4741 return movement;
4742 }
4743 movement += dir;
4744 nonAccelMovement += dir;
4745 step = 1;
4746 break;
4747 // If we have generated the first movement, then we need
4748 // to wait for the second complete trackball motion before
4749 // generating the second discrete movement.
4750 case 1:
4751 if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) {
4752 return movement;
4753 }
4754 movement += dir;
4755 nonAccelMovement += dir;
4756 position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir;
4757 step = 2;
4758 break;
4759 // After the first two, we generate discrete movements
4760 // consistently with the trackball, applying an acceleration
4761 // if the trackball is moving quickly. This is a simple
4762 // acceleration on top of what we already compute based
4763 // on how quickly the wheel is being turned, to apply
4764 // a longer increasing acceleration to continuous movement
4765 // in one direction.
4766 default:
4767 if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) {
4768 return movement;
4769 }
4770 movement += dir;
4771 position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD;
4772 float acc = acceleration;
4773 acc *= 1.1f;
4774 acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
4775 break;
4776 }
4777 } while (true);
4778 }
4779 }
4780
4781 /**
4782 * Creates dpad events from unhandled joystick movements.
4783 */
4784 final class SyntheticJoystickHandler extends Handler {
Michael Wright9adca062014-03-19 11:51:26 -07004785 private final static String TAG = "SyntheticJoystickHandler";
Jeff Brown678a1252013-04-09 17:46:25 -07004786 private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
4787 private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
4788
4789 private int mLastXDirection;
4790 private int mLastYDirection;
4791 private int mLastXKeyCode;
4792 private int mLastYKeyCode;
4793
4794 public SyntheticJoystickHandler() {
4795 super(true);
4796 }
4797
4798 @Override
4799 public void handleMessage(Message msg) {
4800 switch (msg.what) {
4801 case MSG_ENQUEUE_X_AXIS_KEY_REPEAT:
4802 case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: {
4803 KeyEvent oldEvent = (KeyEvent)msg.obj;
4804 KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent,
4805 SystemClock.uptimeMillis(),
4806 oldEvent.getRepeatCount() + 1);
4807 if (mAttachInfo.mHasWindowFocus) {
4808 enqueueInputEvent(e);
4809 Message m = obtainMessage(msg.what, e);
4810 m.setAsynchronous(true);
4811 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay());
4812 }
4813 } break;
4814 }
4815 }
4816
4817 public void process(MotionEvent event) {
Michael Wright9adca062014-03-19 11:51:26 -07004818 switch(event.getActionMasked()) {
4819 case MotionEvent.ACTION_CANCEL:
4820 cancel(event);
4821 break;
4822 case MotionEvent.ACTION_MOVE:
4823 update(event, true);
4824 break;
4825 default:
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004826 Log.w(mTag, "Unexpected action: " + event.getActionMasked());
Michael Wright9adca062014-03-19 11:51:26 -07004827 }
Jeff Brown678a1252013-04-09 17:46:25 -07004828 }
4829
Michael Wright9adca062014-03-19 11:51:26 -07004830 private void cancel(MotionEvent event) {
4831 removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
4832 removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
Jeff Brown678a1252013-04-09 17:46:25 -07004833 update(event, false);
4834 }
4835
4836 private void update(MotionEvent event, boolean synthesizeNewKeys) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004837 final long time = event.getEventTime();
4838 final int metaState = event.getMetaState();
4839 final int deviceId = event.getDeviceId();
4840 final int source = event.getSource();
4841
4842 int xDirection = joystickAxisValueToDirection(
4843 event.getAxisValue(MotionEvent.AXIS_HAT_X));
4844 if (xDirection == 0) {
4845 xDirection = joystickAxisValueToDirection(event.getX());
Jeff Browncb1404e2011-01-15 18:14:15 -08004846 }
4847
Jeff Brownf9e989d2013-04-04 23:04:03 -07004848 int yDirection = joystickAxisValueToDirection(
4849 event.getAxisValue(MotionEvent.AXIS_HAT_Y));
4850 if (yDirection == 0) {
4851 yDirection = joystickAxisValueToDirection(event.getY());
4852 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004853
Jeff Brown678a1252013-04-09 17:46:25 -07004854 if (xDirection != mLastXDirection) {
4855 if (mLastXKeyCode != 0) {
4856 removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004857 enqueueInputEvent(new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004858 KeyEvent.ACTION_UP, mLastXKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004859 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Brown678a1252013-04-09 17:46:25 -07004860 mLastXKeyCode = 0;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004861 }
4862
Jeff Brown678a1252013-04-09 17:46:25 -07004863 mLastXDirection = xDirection;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004864
4865 if (xDirection != 0 && synthesizeNewKeys) {
Jeff Brown678a1252013-04-09 17:46:25 -07004866 mLastXKeyCode = xDirection > 0
Jeff Brownf9e989d2013-04-04 23:04:03 -07004867 ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
4868 final KeyEvent e = new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004869 KeyEvent.ACTION_DOWN, mLastXKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004870 deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
4871 enqueueInputEvent(e);
Jeff Brown678a1252013-04-09 17:46:25 -07004872 Message m = obtainMessage(MSG_ENQUEUE_X_AXIS_KEY_REPEAT, e);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004873 m.setAsynchronous(true);
Michael Wrightb9618522013-04-10 15:20:56 -07004874 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
Jeff Brownf9e989d2013-04-04 23:04:03 -07004875 }
4876 }
4877
Jeff Brown678a1252013-04-09 17:46:25 -07004878 if (yDirection != mLastYDirection) {
4879 if (mLastYKeyCode != 0) {
4880 removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004881 enqueueInputEvent(new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004882 KeyEvent.ACTION_UP, mLastYKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004883 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Brown678a1252013-04-09 17:46:25 -07004884 mLastYKeyCode = 0;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004885 }
4886
Jeff Brown678a1252013-04-09 17:46:25 -07004887 mLastYDirection = yDirection;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004888
4889 if (yDirection != 0 && synthesizeNewKeys) {
Jeff Brown678a1252013-04-09 17:46:25 -07004890 mLastYKeyCode = yDirection > 0
Jeff Brownf9e989d2013-04-04 23:04:03 -07004891 ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
4892 final KeyEvent e = new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004893 KeyEvent.ACTION_DOWN, mLastYKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004894 deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
4895 enqueueInputEvent(e);
Jeff Brown678a1252013-04-09 17:46:25 -07004896 Message m = obtainMessage(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT, e);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004897 m.setAsynchronous(true);
Jeff Brown678a1252013-04-09 17:46:25 -07004898 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
Jeff Brownf9e989d2013-04-04 23:04:03 -07004899 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004900 }
4901 }
4902
Jeff Brownf9e989d2013-04-04 23:04:03 -07004903 private int joystickAxisValueToDirection(float value) {
4904 if (value >= 0.5f) {
4905 return 1;
4906 } else if (value <= -0.5f) {
4907 return -1;
4908 } else {
4909 return 0;
Jeff Browncb1404e2011-01-15 18:14:15 -08004910 }
4911 }
Jeff Brown678a1252013-04-09 17:46:25 -07004912 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004913
Jeff Brown678a1252013-04-09 17:46:25 -07004914 /**
4915 * Creates dpad events from unhandled touch navigation movements.
4916 */
4917 final class SyntheticTouchNavigationHandler extends Handler {
Jeff Brown4dac9012013-04-10 01:03:19 -07004918 private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler";
4919 private static final boolean LOCAL_DEBUG = false;
Jeff Brown678a1252013-04-09 17:46:25 -07004920
Jeff Brown4dac9012013-04-10 01:03:19 -07004921 // Assumed nominal width and height in millimeters of a touch navigation pad,
4922 // if no resolution information is available from the input system.
4923 private static final float DEFAULT_WIDTH_MILLIMETERS = 48;
4924 private static final float DEFAULT_HEIGHT_MILLIMETERS = 48;
Jeff Brown678a1252013-04-09 17:46:25 -07004925
Jeff Brown4dac9012013-04-10 01:03:19 -07004926 /* TODO: These constants should eventually be moved to ViewConfiguration. */
Jeff Brown678a1252013-04-09 17:46:25 -07004927
Jeff Brown4dac9012013-04-10 01:03:19 -07004928 // The nominal distance traveled to move by one unit.
4929 private static final int TICK_DISTANCE_MILLIMETERS = 12;
4930
4931 // Minimum and maximum fling velocity in ticks per second.
4932 // The minimum velocity should be set such that we perform enough ticks per
4933 // second that the fling appears to be fluid. For example, if we set the minimum
4934 // to 2 ticks per second, then there may be up to half a second delay between the next
4935 // to last and last ticks which is noticeably discrete and jerky. This value should
4936 // probably not be set to anything less than about 4.
4937 // If fling accuracy is a problem then consider tuning the tick distance instead.
4938 private static final float MIN_FLING_VELOCITY_TICKS_PER_SECOND = 6f;
4939 private static final float MAX_FLING_VELOCITY_TICKS_PER_SECOND = 20f;
4940
4941 // Fling velocity decay factor applied after each new key is emitted.
4942 // This parameter controls the deceleration and overall duration of the fling.
4943 // The fling stops automatically when its velocity drops below the minimum
4944 // fling velocity defined above.
4945 private static final float FLING_TICK_DECAY = 0.8f;
4946
4947 /* The input device that we are tracking. */
4948
4949 private int mCurrentDeviceId = -1;
4950 private int mCurrentSource;
4951 private boolean mCurrentDeviceSupported;
4952
4953 /* Configuration for the current input device. */
4954
Jeff Brown4dac9012013-04-10 01:03:19 -07004955 // The scaled tick distance. A movement of this amount should generally translate
4956 // into a single dpad event in a given direction.
4957 private float mConfigTickDistance;
4958
4959 // The minimum and maximum scaled fling velocity.
4960 private float mConfigMinFlingVelocity;
4961 private float mConfigMaxFlingVelocity;
4962
4963 /* Tracking state. */
4964
4965 // The velocity tracker for detecting flings.
4966 private VelocityTracker mVelocityTracker;
4967
4968 // The active pointer id, or -1 if none.
4969 private int mActivePointerId = -1;
4970
John Reck79d81e62013-11-05 13:26:57 -08004971 // Location where tracking started.
Jeff Brown4dac9012013-04-10 01:03:19 -07004972 private float mStartX;
4973 private float mStartY;
4974
4975 // Most recently observed position.
4976 private float mLastX;
4977 private float mLastY;
4978
4979 // Accumulated movement delta since the last direction key was sent.
Jeff Brown678a1252013-04-09 17:46:25 -07004980 private float mAccumulatedX;
4981 private float mAccumulatedY;
4982
Jeff Brown4dac9012013-04-10 01:03:19 -07004983 // Set to true if any movement was delivered to the app.
4984 // Implies that tap slop was exceeded.
4985 private boolean mConsumedMovement;
Jeff Brown678a1252013-04-09 17:46:25 -07004986
Jeff Brown4dac9012013-04-10 01:03:19 -07004987 // The most recently sent key down event.
4988 // The keycode remains set until the direction changes or a fling ends
4989 // so that repeated key events may be generated as required.
4990 private long mPendingKeyDownTime;
4991 private int mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
4992 private int mPendingKeyRepeatCount;
4993 private int mPendingKeyMetaState;
Jeff Brown678a1252013-04-09 17:46:25 -07004994
Jeff Brown4dac9012013-04-10 01:03:19 -07004995 // The current fling velocity while a fling is in progress.
4996 private boolean mFlinging;
4997 private float mFlingVelocity;
Jeff Brown678a1252013-04-09 17:46:25 -07004998
4999 public SyntheticTouchNavigationHandler() {
5000 super(true);
Jeff Brown678a1252013-04-09 17:46:25 -07005001 }
5002
5003 public void process(MotionEvent event) {
Jeff Brown4dac9012013-04-10 01:03:19 -07005004 // Update the current device information.
5005 final long time = event.getEventTime();
5006 final int deviceId = event.getDeviceId();
5007 final int source = event.getSource();
5008 if (mCurrentDeviceId != deviceId || mCurrentSource != source) {
5009 finishKeys(time);
5010 finishTracking(time);
5011 mCurrentDeviceId = deviceId;
5012 mCurrentSource = source;
5013 mCurrentDeviceSupported = false;
5014 InputDevice device = event.getDevice();
5015 if (device != null) {
5016 // In order to support an input device, we must know certain
5017 // characteristics about it, such as its size and resolution.
5018 InputDevice.MotionRange xRange = device.getMotionRange(MotionEvent.AXIS_X);
5019 InputDevice.MotionRange yRange = device.getMotionRange(MotionEvent.AXIS_Y);
5020 if (xRange != null && yRange != null) {
5021 mCurrentDeviceSupported = true;
Jeff Brown678a1252013-04-09 17:46:25 -07005022
Jeff Brown4dac9012013-04-10 01:03:19 -07005023 // Infer the resolution if it not actually known.
5024 float xRes = xRange.getResolution();
5025 if (xRes <= 0) {
5026 xRes = xRange.getRange() / DEFAULT_WIDTH_MILLIMETERS;
5027 }
5028 float yRes = yRange.getResolution();
5029 if (yRes <= 0) {
5030 yRes = yRange.getRange() / DEFAULT_HEIGHT_MILLIMETERS;
5031 }
5032 float nominalRes = (xRes + yRes) * 0.5f;
Jeff Brown678a1252013-04-09 17:46:25 -07005033
Jeff Brown4dac9012013-04-10 01:03:19 -07005034 // Precompute all of the configuration thresholds we will need.
Jeff Brown4dac9012013-04-10 01:03:19 -07005035 mConfigTickDistance = TICK_DISTANCE_MILLIMETERS * nominalRes;
5036 mConfigMinFlingVelocity =
5037 MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
5038 mConfigMaxFlingVelocity =
5039 MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
5040
5041 if (LOCAL_DEBUG) {
5042 Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId
5043 + " (" + Integer.toHexString(mCurrentSource) + "): "
Jeff Brown4dac9012013-04-10 01:03:19 -07005044 + ", mConfigTickDistance=" + mConfigTickDistance
5045 + ", mConfigMinFlingVelocity=" + mConfigMinFlingVelocity
5046 + ", mConfigMaxFlingVelocity=" + mConfigMaxFlingVelocity);
5047 }
5048 }
5049 }
Jeff Brown678a1252013-04-09 17:46:25 -07005050 }
Jeff Brown4dac9012013-04-10 01:03:19 -07005051 if (!mCurrentDeviceSupported) {
Jeff Brown678a1252013-04-09 17:46:25 -07005052 return;
5053 }
5054
Jeff Brown4dac9012013-04-10 01:03:19 -07005055 // Handle the event.
5056 final int action = event.getActionMasked();
5057 switch (action) {
Jeff Brown678a1252013-04-09 17:46:25 -07005058 case MotionEvent.ACTION_DOWN: {
Jeff Brown4dac9012013-04-10 01:03:19 -07005059 boolean caughtFling = mFlinging;
5060 finishKeys(time);
5061 finishTracking(time);
5062 mActivePointerId = event.getPointerId(0);
5063 mVelocityTracker = VelocityTracker.obtain();
5064 mVelocityTracker.addMovement(event);
Jeff Brown4dac9012013-04-10 01:03:19 -07005065 mStartX = event.getX();
5066 mStartY = event.getY();
5067 mLastX = mStartX;
5068 mLastY = mStartY;
Jeff Brown678a1252013-04-09 17:46:25 -07005069 mAccumulatedX = 0;
5070 mAccumulatedY = 0;
Jeff Brown4dac9012013-04-10 01:03:19 -07005071
5072 // If we caught a fling, then pretend that the tap slop has already
5073 // been exceeded to suppress taps whose only purpose is to stop the fling.
5074 mConsumedMovement = caughtFling;
Jeff Brown678a1252013-04-09 17:46:25 -07005075 break;
5076 }
5077
Jeff Brown4dac9012013-04-10 01:03:19 -07005078 case MotionEvent.ACTION_MOVE:
Jeff Brown678a1252013-04-09 17:46:25 -07005079 case MotionEvent.ACTION_UP: {
Jeff Brown4dac9012013-04-10 01:03:19 -07005080 if (mActivePointerId < 0) {
5081 break;
5082 }
5083 final int index = event.findPointerIndex(mActivePointerId);
5084 if (index < 0) {
5085 finishKeys(time);
5086 finishTracking(time);
5087 break;
5088 }
Jeff Brown678a1252013-04-09 17:46:25 -07005089
Jeff Brown4dac9012013-04-10 01:03:19 -07005090 mVelocityTracker.addMovement(event);
5091 final float x = event.getX(index);
5092 final float y = event.getY(index);
5093 mAccumulatedX += x - mLastX;
5094 mAccumulatedY += y - mLastY;
5095 mLastX = x;
5096 mLastY = y;
5097
5098 // Consume any accumulated movement so far.
5099 final int metaState = event.getMetaState();
5100 consumeAccumulatedMovement(time, metaState);
5101
5102 // Detect taps and flings.
5103 if (action == MotionEvent.ACTION_UP) {
Michael Wright88d7f792013-08-27 15:45:42 -07005104 if (mConsumedMovement && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
Jeff Brown4dac9012013-04-10 01:03:19 -07005105 // It might be a fling.
5106 mVelocityTracker.computeCurrentVelocity(1000, mConfigMaxFlingVelocity);
5107 final float vx = mVelocityTracker.getXVelocity(mActivePointerId);
5108 final float vy = mVelocityTracker.getYVelocity(mActivePointerId);
5109 if (!startFling(time, vx, vy)) {
5110 finishKeys(time);
Jeff Brown678a1252013-04-09 17:46:25 -07005111 }
5112 }
Jeff Brown4dac9012013-04-10 01:03:19 -07005113 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07005114 }
Jeff Brown4dac9012013-04-10 01:03:19 -07005115 break;
5116 }
5117
5118 case MotionEvent.ACTION_CANCEL: {
5119 finishKeys(time);
5120 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07005121 break;
5122 }
5123 }
Jeff Browncb1404e2011-01-15 18:14:15 -08005124 }
Jeff Brown4dac9012013-04-10 01:03:19 -07005125
5126 public void cancel(MotionEvent event) {
5127 if (mCurrentDeviceId == event.getDeviceId()
5128 && mCurrentSource == event.getSource()) {
5129 final long time = event.getEventTime();
5130 finishKeys(time);
5131 finishTracking(time);
5132 }
5133 }
5134
5135 private void finishKeys(long time) {
5136 cancelFling();
5137 sendKeyUp(time);
5138 }
5139
5140 private void finishTracking(long time) {
5141 if (mActivePointerId >= 0) {
5142 mActivePointerId = -1;
5143 mVelocityTracker.recycle();
5144 mVelocityTracker = null;
5145 }
5146 }
5147
5148 private void consumeAccumulatedMovement(long time, int metaState) {
5149 final float absX = Math.abs(mAccumulatedX);
5150 final float absY = Math.abs(mAccumulatedY);
5151 if (absX >= absY) {
5152 if (absX >= mConfigTickDistance) {
5153 mAccumulatedX = consumeAccumulatedMovement(time, metaState, mAccumulatedX,
5154 KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT);
5155 mAccumulatedY = 0;
5156 mConsumedMovement = true;
5157 }
5158 } else {
5159 if (absY >= mConfigTickDistance) {
5160 mAccumulatedY = consumeAccumulatedMovement(time, metaState, mAccumulatedY,
5161 KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN);
5162 mAccumulatedX = 0;
5163 mConsumedMovement = true;
5164 }
5165 }
5166 }
5167
5168 private float consumeAccumulatedMovement(long time, int metaState,
5169 float accumulator, int negativeKeyCode, int positiveKeyCode) {
5170 while (accumulator <= -mConfigTickDistance) {
5171 sendKeyDownOrRepeat(time, negativeKeyCode, metaState);
5172 accumulator += mConfigTickDistance;
5173 }
5174 while (accumulator >= mConfigTickDistance) {
5175 sendKeyDownOrRepeat(time, positiveKeyCode, metaState);
5176 accumulator -= mConfigTickDistance;
5177 }
5178 return accumulator;
5179 }
5180
5181 private void sendKeyDownOrRepeat(long time, int keyCode, int metaState) {
5182 if (mPendingKeyCode != keyCode) {
5183 sendKeyUp(time);
5184 mPendingKeyDownTime = time;
5185 mPendingKeyCode = keyCode;
5186 mPendingKeyRepeatCount = 0;
5187 } else {
5188 mPendingKeyRepeatCount += 1;
5189 }
5190 mPendingKeyMetaState = metaState;
5191
5192 // Note: Normally we would pass FLAG_LONG_PRESS when the repeat count is 1
5193 // but it doesn't quite make sense when simulating the events in this way.
5194 if (LOCAL_DEBUG) {
5195 Log.d(LOCAL_TAG, "Sending key down: keyCode=" + mPendingKeyCode
5196 + ", repeatCount=" + mPendingKeyRepeatCount
5197 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
5198 }
5199 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
5200 KeyEvent.ACTION_DOWN, mPendingKeyCode, mPendingKeyRepeatCount,
5201 mPendingKeyMetaState, mCurrentDeviceId,
5202 KeyEvent.FLAG_FALLBACK, mCurrentSource));
5203 }
5204
5205 private void sendKeyUp(long time) {
5206 if (mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
5207 if (LOCAL_DEBUG) {
5208 Log.d(LOCAL_TAG, "Sending key up: keyCode=" + mPendingKeyCode
5209 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
5210 }
5211 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
5212 KeyEvent.ACTION_UP, mPendingKeyCode, 0, mPendingKeyMetaState,
5213 mCurrentDeviceId, 0, KeyEvent.FLAG_FALLBACK,
5214 mCurrentSource));
5215 mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
5216 }
5217 }
5218
5219 private boolean startFling(long time, float vx, float vy) {
5220 if (LOCAL_DEBUG) {
5221 Log.d(LOCAL_TAG, "Considering fling: vx=" + vx + ", vy=" + vy
5222 + ", min=" + mConfigMinFlingVelocity);
5223 }
5224
5225 // Flings must be oriented in the same direction as the preceding movements.
5226 switch (mPendingKeyCode) {
5227 case KeyEvent.KEYCODE_DPAD_LEFT:
5228 if (-vx >= mConfigMinFlingVelocity
5229 && Math.abs(vy) < mConfigMinFlingVelocity) {
5230 mFlingVelocity = -vx;
5231 break;
5232 }
5233 return false;
5234
5235 case KeyEvent.KEYCODE_DPAD_RIGHT:
5236 if (vx >= mConfigMinFlingVelocity
5237 && Math.abs(vy) < mConfigMinFlingVelocity) {
5238 mFlingVelocity = vx;
5239 break;
5240 }
5241 return false;
5242
5243 case KeyEvent.KEYCODE_DPAD_UP:
5244 if (-vy >= mConfigMinFlingVelocity
5245 && Math.abs(vx) < mConfigMinFlingVelocity) {
5246 mFlingVelocity = -vy;
5247 break;
5248 }
5249 return false;
5250
5251 case KeyEvent.KEYCODE_DPAD_DOWN:
5252 if (vy >= mConfigMinFlingVelocity
5253 && Math.abs(vx) < mConfigMinFlingVelocity) {
5254 mFlingVelocity = vy;
5255 break;
5256 }
5257 return false;
5258 }
5259
5260 // Post the first fling event.
5261 mFlinging = postFling(time);
5262 return mFlinging;
5263 }
5264
5265 private boolean postFling(long time) {
5266 // The idea here is to estimate the time when the pointer would have
5267 // traveled one tick distance unit given the current fling velocity.
5268 // This effect creates continuity of motion.
5269 if (mFlingVelocity >= mConfigMinFlingVelocity) {
5270 long delay = (long)(mConfigTickDistance / mFlingVelocity * 1000);
5271 postAtTime(mFlingRunnable, time + delay);
5272 if (LOCAL_DEBUG) {
5273 Log.d(LOCAL_TAG, "Posted fling: velocity="
5274 + mFlingVelocity + ", delay=" + delay
5275 + ", keyCode=" + mPendingKeyCode);
5276 }
5277 return true;
5278 }
5279 return false;
5280 }
5281
5282 private void cancelFling() {
5283 if (mFlinging) {
5284 removeCallbacks(mFlingRunnable);
5285 mFlinging = false;
5286 }
5287 }
5288
5289 private final Runnable mFlingRunnable = new Runnable() {
5290 @Override
5291 public void run() {
5292 final long time = SystemClock.uptimeMillis();
5293 sendKeyDownOrRepeat(time, mPendingKeyCode, mPendingKeyMetaState);
5294 mFlingVelocity *= FLING_TICK_DECAY;
5295 if (!postFling(time)) {
5296 mFlinging = false;
5297 finishKeys(time);
5298 }
5299 }
5300 };
Jeff Browncb1404e2011-01-15 18:14:15 -08005301 }
5302
Michael Wright899d7052014-04-23 17:23:39 -07005303 final class SyntheticKeyboardHandler {
5304 public void process(KeyEvent event) {
5305 if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
5306 return;
5307 }
5308
5309 final KeyCharacterMap kcm = event.getKeyCharacterMap();
5310 final int keyCode = event.getKeyCode();
5311 final int metaState = event.getMetaState();
5312
5313 // Check for fallback actions specified by the key character map.
5314 KeyCharacterMap.FallbackAction fallbackAction =
5315 kcm.getFallbackAction(keyCode, metaState);
5316 if (fallbackAction != null) {
5317 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
5318 KeyEvent fallbackEvent = KeyEvent.obtain(
5319 event.getDownTime(), event.getEventTime(),
5320 event.getAction(), fallbackAction.keyCode,
5321 event.getRepeatCount(), fallbackAction.metaState,
5322 event.getDeviceId(), event.getScanCode(),
5323 flags, event.getSource(), null);
5324 fallbackAction.recycle();
5325 enqueueInputEvent(fallbackEvent);
5326 }
5327 }
5328 }
5329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005330 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08005331 * Returns true if the key is used for keyboard navigation.
5332 * @param keyEvent The key event.
5333 * @return True if the key is used for keyboard navigation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005334 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08005335 private static boolean isNavigationKey(KeyEvent keyEvent) {
5336 switch (keyEvent.getKeyCode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005337 case KeyEvent.KEYCODE_DPAD_LEFT:
5338 case KeyEvent.KEYCODE_DPAD_RIGHT:
5339 case KeyEvent.KEYCODE_DPAD_UP:
5340 case KeyEvent.KEYCODE_DPAD_DOWN:
Jeff Brown4e6319b2010-12-13 10:36:51 -08005341 case KeyEvent.KEYCODE_DPAD_CENTER:
5342 case KeyEvent.KEYCODE_PAGE_UP:
5343 case KeyEvent.KEYCODE_PAGE_DOWN:
5344 case KeyEvent.KEYCODE_MOVE_HOME:
5345 case KeyEvent.KEYCODE_MOVE_END:
5346 case KeyEvent.KEYCODE_TAB:
5347 case KeyEvent.KEYCODE_SPACE:
5348 case KeyEvent.KEYCODE_ENTER:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005349 return true;
5350 }
5351 return false;
5352 }
5353
5354 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08005355 * Returns true if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005356 * @param keyEvent The key event.
Jeff Brown4e6319b2010-12-13 10:36:51 -08005357 * @return True if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005358 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08005359 private static boolean isTypingKey(KeyEvent keyEvent) {
5360 return keyEvent.getUnicodeChar() > 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005361 }
5362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005363 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08005364 * 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 -08005365 * @param event The key event.
5366 * @return Whether this key event should be consumed (meaning the act of
5367 * leaving touch mode alone is considered the event).
5368 */
5369 private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08005370 // Only relevant in touch mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005371 if (!mAttachInfo.mInTouchMode) {
5372 return false;
5373 }
5374
Jeff Brown4e6319b2010-12-13 10:36:51 -08005375 // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
5376 final int action = event.getAction();
5377 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005378 return false;
5379 }
5380
Jeff Brown4e6319b2010-12-13 10:36:51 -08005381 // Don't leave touch mode if the IME told us not to.
5382 if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
5383 return false;
5384 }
5385
5386 // If the key can be used for keyboard navigation then leave touch mode
5387 // and select a focused view if needed (in ensureTouchMode).
5388 // When a new focused view is selected, we consume the navigation key because
5389 // navigation doesn't make much sense unless a view already has focus so
5390 // the key's purpose is to set focus.
5391 if (isNavigationKey(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005392 return ensureTouchMode(false);
5393 }
Jeff Brown4e6319b2010-12-13 10:36:51 -08005394
5395 // If the key can be used for typing then leave touch mode
5396 // and select a focused view if needed (in ensureTouchMode).
5397 // Always allow the view to process the typing key.
5398 if (isTypingKey(event)) {
5399 ensureTouchMode(false);
5400 return false;
5401 }
5402
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005403 return false;
5404 }
5405
Christopher Tatea53146c2010-09-07 11:57:52 -07005406 /* drag/drop */
Christopher Tate407b4e92010-11-30 17:14:08 -08005407 void setLocalDragState(Object obj) {
5408 mLocalDragState = obj;
5409 }
5410
Christopher Tatea53146c2010-09-07 11:57:52 -07005411 private void handleDragEvent(DragEvent event) {
5412 // From the root, only drag start/end/location are dispatched. entered/exited
5413 // are determined and dispatched by the viewgroup hierarchy, who then report
5414 // that back here for ultimate reporting back to the framework.
5415 if (mView != null && mAdded) {
5416 final int what = event.mAction;
5417
5418 if (what == DragEvent.ACTION_DRAG_EXITED) {
5419 // A direct EXITED event means that the window manager knows we've just crossed
5420 // a window boundary, so the current drag target within this one must have
5421 // just been exited. Send it the usual notifications and then we're done
5422 // for now.
Chris Tate9d1ab882010-11-02 15:55:39 -07005423 mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07005424 } else {
5425 // Cache the drag description when the operation starts, then fill it in
5426 // on subsequent calls as a convenience
5427 if (what == DragEvent.ACTION_DRAG_STARTED) {
Chris Tate9d1ab882010-11-02 15:55:39 -07005428 mCurrentDragView = null; // Start the current-recipient tracking
Christopher Tatea53146c2010-09-07 11:57:52 -07005429 mDragDescription = event.mClipDescription;
5430 } else {
5431 event.mClipDescription = mDragDescription;
5432 }
5433
5434 // For events with a [screen] location, translate into window coordinates
5435 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
5436 mDragPoint.set(event.mX, event.mY);
5437 if (mTranslator != null) {
5438 mTranslator.translatePointInScreenToAppWindow(mDragPoint);
5439 }
5440
5441 if (mCurScrollY != 0) {
5442 mDragPoint.offset(0, mCurScrollY);
5443 }
5444
5445 event.mX = mDragPoint.x;
5446 event.mY = mDragPoint.y;
5447 }
5448
5449 // Remember who the current drag target is pre-dispatch
5450 final View prevDragView = mCurrentDragView;
5451
5452 // Now dispatch the drag/drop event
Chris Tated4533f12010-10-19 15:15:08 -07005453 boolean result = mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07005454
5455 // If we changed apparent drag target, tell the OS about it
5456 if (prevDragView != mCurrentDragView) {
5457 try {
5458 if (prevDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07005459 mWindowSession.dragRecipientExited(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07005460 }
5461 if (mCurrentDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07005462 mWindowSession.dragRecipientEntered(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07005463 }
5464 } catch (RemoteException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005465 Slog.e(mTag, "Unable to note drag target change");
Christopher Tatea53146c2010-09-07 11:57:52 -07005466 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005467 }
Chris Tated4533f12010-10-19 15:15:08 -07005468
Christopher Tate407b4e92010-11-30 17:14:08 -08005469 // Report the drop result when we're done
Chris Tated4533f12010-10-19 15:15:08 -07005470 if (what == DragEvent.ACTION_DROP) {
Christopher Tate1fc014f2011-01-19 12:56:26 -08005471 mDragDescription = null;
Chris Tated4533f12010-10-19 15:15:08 -07005472 try {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005473 Log.i(mTag, "Reporting drop result: " + result);
Jeff Brown98365d72012-08-19 20:30:52 -07005474 mWindowSession.reportDropResult(mWindow, result);
Chris Tated4533f12010-10-19 15:15:08 -07005475 } catch (RemoteException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005476 Log.e(mTag, "Unable to report drop result");
Chris Tated4533f12010-10-19 15:15:08 -07005477 }
5478 }
Christopher Tate407b4e92010-11-30 17:14:08 -08005479
Vladislav Kaznacheev82063912015-11-20 14:20:13 -08005480 // When the drag operation ends, reset drag-related state
Christopher Tate407b4e92010-11-30 17:14:08 -08005481 if (what == DragEvent.ACTION_DRAG_ENDED) {
5482 setLocalDragState(null);
Vladislav Kaznacheev82063912015-11-20 14:20:13 -08005483 mAttachInfo.mDragToken = null;
Vladislav Kaznacheev4f639742015-11-18 13:21:35 -08005484 if (mAttachInfo.mDragSurface != null) {
5485 mAttachInfo.mDragSurface.release();
5486 mAttachInfo.mDragSurface = null;
5487 }
Christopher Tate407b4e92010-11-30 17:14:08 -08005488 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005489 }
5490 }
5491 event.recycle();
5492 }
5493
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005494 public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
5495 if (mSeq != args.seq) {
5496 // The sequence has changed, so we need to update our value and make
5497 // sure to do a traversal afterward so the window manager is given our
5498 // most recent data.
5499 mSeq = args.seq;
5500 mAttachInfo.mForceReportNewAttributes = true;
Igor Murashkina86ab6402013-08-30 12:58:36 -07005501 scheduleTraversals();
Joe Onorato14782f72011-01-25 19:53:17 -08005502 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005503 if (mView == null) return;
5504 if (args.localChanges != 0) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005505 mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005506 }
Chris Craikd36a81f2014-07-17 10:16:51 -07005507
5508 int visibility = args.globalVisibility&View.SYSTEM_UI_CLEARABLE_FLAGS;
5509 if (visibility != mAttachInfo.mGlobalSystemUiVisibility) {
5510 mAttachInfo.mGlobalSystemUiVisibility = visibility;
5511 mView.dispatchSystemUiVisibilityChanged(visibility);
Dianne Hackborncf675782012-05-10 15:07:24 -07005512 }
Joe Onorato664644d2011-01-23 17:53:23 -08005513 }
5514
Craig Mautner9c795042014-10-28 19:59:59 -07005515 public void handleDispatchWindowShown() {
5516 mAttachInfo.mTreeObserver.dispatchOnWindowShown();
5517 }
5518
Clara Bayarri75e09792015-07-29 16:20:40 +01005519 public void handleRequestKeyboardShortcuts(IResultReceiver receiver) {
5520 Bundle data = new Bundle();
5521 ArrayList<KeyboardShortcutGroup> list = new ArrayList<>();
5522 if (mView != null) {
5523 mView.requestKeyboardShortcuts(list);
5524 }
5525 data.putParcelableArrayList(WindowManager.PARCEL_KEY_SHORTCUTS_ARRAY, list);
5526 try {
5527 receiver.send(0, data);
5528 } catch (RemoteException e) {
5529 }
5530 }
5531
Christopher Tate2c095f32010-10-04 14:13:40 -07005532 public void getLastTouchPoint(Point outLocation) {
5533 outLocation.x = (int) mLastTouchPoint.x;
5534 outLocation.y = (int) mLastTouchPoint.y;
5535 }
5536
Vladislav Kaznacheevba761122016-01-22 12:09:45 -08005537 public int getLastTouchSource() {
5538 return mLastTouchSource;
5539 }
5540
Chris Tate9d1ab882010-11-02 15:55:39 -07005541 public void setDragFocus(View newDragTarget) {
Christopher Tatea53146c2010-09-07 11:57:52 -07005542 if (mCurrentDragView != newDragTarget) {
Chris Tate048691c2010-10-12 17:39:18 -07005543 mCurrentDragView = newDragTarget;
Christopher Tatea53146c2010-09-07 11:57:52 -07005544 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005545 }
5546
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005547 private AudioManager getAudioManager() {
5548 if (mView == null) {
5549 throw new IllegalStateException("getAudioManager called when there is no mView");
5550 }
5551 if (mAudioManager == null) {
5552 mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
5553 }
5554 return mAudioManager;
5555 }
5556
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005557 public AccessibilityInteractionController getAccessibilityInteractionController() {
5558 if (mView == null) {
5559 throw new IllegalStateException("getAccessibilityInteractionController"
5560 + " called when there is no mView");
5561 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07005562 if (mAccessibilityInteractionController == null) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005563 mAccessibilityInteractionController = new AccessibilityInteractionController(this);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005564 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07005565 return mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005566 }
5567
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07005568 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
5569 boolean insetsPending) throws RemoteException {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005570
5571 float appScale = mAttachInfo.mApplicationScale;
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005572 boolean restore = false;
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005573 if (params != null && mTranslator != null) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005574 restore = true;
5575 params.backup();
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005576 mTranslator.translateWindowLayout(params);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005577 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005578 if (params != null) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005579 if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005580 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07005581 mPendingConfiguration.seq = 0;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005582 //Log.d(mTag, ">>>>>> CALLING relayout");
Dianne Hackborn180c4842011-09-13 12:39:25 -07005583 if (params != null && mOrigWindowType != params.type) {
5584 // For compatibility with old apps, don't crash here.
Michael Wright5bd69e62015-05-14 14:48:08 +01005585 if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005586 Slog.w(mTag, "Window type can not be changed after "
Dianne Hackborn180c4842011-09-13 12:39:25 -07005587 + "the window is added; ignoring change of " + mView);
5588 params.type = mOrigWindowType;
5589 }
5590 }
Jeff Brown98365d72012-08-19 20:30:52 -07005591 int relayoutResult = mWindowSession.relayout(
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005592 mWindow, mSeq, params,
Dianne Hackborn189ee182010-12-02 21:48:53 -08005593 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
5594 (int) (mView.getMeasuredHeight() * appScale + 0.5f),
Jeff Brown98365d72012-08-19 20:30:52 -07005595 viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005596 mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
Jorim Jaggi2e95a482016-01-14 17:36:55 -08005597 mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration,
5598 mSurface);
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08005599
5600 mPendingAlwaysConsumeNavBar =
5601 (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR) != 0;
5602
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005603 //Log.d(mTag, "<<<<<< BACK FROM relayout");
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005604 if (restore) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005605 params.restore();
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005606 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07005607
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005608 if (mTranslator != null) {
5609 mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005610 mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005611 mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
5612 mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
Adrian Roosfa104232014-06-20 16:10:14 -07005613 mTranslator.translateRectInScreenToAppWindow(mPendingStableInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005614 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07005615 return relayoutResult;
5616 }
Romain Guy8506ab42009-06-11 17:35:47 -07005617
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005618 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005619 * {@inheritDoc}
5620 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005621 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005622 public void playSoundEffect(int effectId) {
5623 checkThread();
5624
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005625 try {
5626 final AudioManager audioManager = getAudioManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005627
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005628 switch (effectId) {
5629 case SoundEffectConstants.CLICK:
5630 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
5631 return;
5632 case SoundEffectConstants.NAVIGATION_DOWN:
5633 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
5634 return;
5635 case SoundEffectConstants.NAVIGATION_LEFT:
5636 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
5637 return;
5638 case SoundEffectConstants.NAVIGATION_RIGHT:
5639 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
5640 return;
5641 case SoundEffectConstants.NAVIGATION_UP:
5642 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
5643 return;
5644 default:
5645 throw new IllegalArgumentException("unknown effect id " + effectId +
5646 " not defined in " + SoundEffectConstants.class.getCanonicalName());
5647 }
5648 } catch (IllegalStateException e) {
5649 // Exception thrown by getAudioManager() when mView is null
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005650 Log.e(mTag, "FATAL EXCEPTION when attempting to play sound effect: " + e);
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005651 e.printStackTrace();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005652 }
5653 }
5654
5655 /**
5656 * {@inheritDoc}
5657 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005658 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005659 public boolean performHapticFeedback(int effectId, boolean always) {
5660 try {
Jeff Brown98365d72012-08-19 20:30:52 -07005661 return mWindowSession.performHapticFeedback(mWindow, effectId, always);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005662 } catch (RemoteException e) {
5663 return false;
5664 }
5665 }
5666
5667 /**
5668 * {@inheritDoc}
5669 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005670 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005671 public View focusSearch(View focused, int direction) {
5672 checkThread();
5673 if (!(mView instanceof ViewGroup)) {
5674 return null;
5675 }
5676 return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
5677 }
5678
5679 public void debug() {
5680 mView.debug();
5681 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07005682
Jeff Brown5182c782013-10-15 20:31:52 -07005683 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
5684 String innerPrefix = prefix + " ";
5685 writer.print(prefix); writer.println("ViewRoot:");
5686 writer.print(innerPrefix); writer.print("mAdded="); writer.print(mAdded);
5687 writer.print(" mRemoved="); writer.println(mRemoved);
5688 writer.print(innerPrefix); writer.print("mConsumeBatchedInputScheduled=");
5689 writer.println(mConsumeBatchedInputScheduled);
Michael Wright9d744c72014-02-18 21:27:42 -08005690 writer.print(innerPrefix); writer.print("mConsumeBatchedInputImmediatelyScheduled=");
5691 writer.println(mConsumeBatchedInputImmediatelyScheduled);
Jeff Brown5182c782013-10-15 20:31:52 -07005692 writer.print(innerPrefix); writer.print("mPendingInputEventCount=");
5693 writer.println(mPendingInputEventCount);
5694 writer.print(innerPrefix); writer.print("mProcessInputEventsScheduled=");
5695 writer.println(mProcessInputEventsScheduled);
5696 writer.print(innerPrefix); writer.print("mTraversalScheduled=");
5697 writer.print(mTraversalScheduled);
Daniel Koulomzin087ae472015-12-16 17:52:25 -05005698 writer.print(innerPrefix); writer.print("mIsAmbientMode=");
5699 writer.print(mIsAmbientMode);
Jeff Brown5182c782013-10-15 20:31:52 -07005700 if (mTraversalScheduled) {
5701 writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
5702 } else {
5703 writer.println();
5704 }
5705 mFirstInputStage.dump(innerPrefix, writer);
5706
5707 mChoreographer.dump(prefix, writer);
5708
5709 writer.print(prefix); writer.println("View Hierarchy:");
5710 dumpViewHierarchy(innerPrefix, writer, mView);
5711 }
5712
5713 private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) {
5714 writer.print(prefix);
5715 if (view == null) {
5716 writer.println("null");
5717 return;
5718 }
5719 writer.println(view.toString());
5720 if (!(view instanceof ViewGroup)) {
5721 return;
5722 }
5723 ViewGroup grp = (ViewGroup)view;
5724 final int N = grp.getChildCount();
5725 if (N <= 0) {
5726 return;
5727 }
5728 prefix = prefix + " ";
5729 for (int i=0; i<N; i++) {
5730 dumpViewHierarchy(prefix, writer, grp.getChildAt(i));
5731 }
5732 }
5733
Romain Guy211370f2012-02-01 16:10:55 -08005734 public void dumpGfxInfo(int[] info) {
Romain Guy54ab3472012-06-14 12:52:53 -07005735 info[0] = info[1] = 0;
Romain Guy65b345f2011-07-27 18:51:50 -07005736 if (mView != null) {
5737 getGfxInfo(mView, info);
Romain Guy65b345f2011-07-27 18:51:50 -07005738 }
5739 }
5740
Romain Guya998dff2012-03-23 18:58:36 -07005741 private static void getGfxInfo(View view, int[] info) {
Chris Craik64a12e12014-03-28 18:12:12 -07005742 RenderNode renderNode = view.mRenderNode;
Romain Guy65b345f2011-07-27 18:51:50 -07005743 info[0]++;
Chris Craik64a12e12014-03-28 18:12:12 -07005744 if (renderNode != null) {
John Reckfe5e7b72014-05-23 17:42:28 -07005745 info[1] += renderNode.getDebugSize();
Romain Guy65b345f2011-07-27 18:51:50 -07005746 }
5747
5748 if (view instanceof ViewGroup) {
5749 ViewGroup group = (ViewGroup) view;
5750
5751 int count = group.getChildCount();
5752 for (int i = 0; i < count; i++) {
5753 getGfxInfo(group.getChildAt(i), info);
5754 }
5755 }
5756 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005757
Craig Mautner8f303ad2013-06-14 11:32:22 -07005758 /**
5759 * @param immediate True, do now if not in traversal. False, put on queue and do later.
5760 * @return True, request has been queued. False, request has been completed.
5761 */
5762 boolean die(boolean immediate) {
Craig Mautnerdf2390a2012-08-29 20:59:22 -07005763 // Make sure we do execute immediately if we are in the middle of a traversal or the damage
5764 // done by dispatchDetachedFromWindow will cause havoc on return.
5765 if (immediate && !mIsInTraversal) {
Dianne Hackborn94d69142009-09-28 22:14:42 -07005766 doDie();
Craig Mautner8f303ad2013-06-14 11:32:22 -07005767 return false;
Dianne Hackborn94d69142009-09-28 22:14:42 -07005768 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07005769
5770 if (!mIsDrawing) {
5771 destroyHardwareRenderer();
5772 } else {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005773 Log.e(mTag, "Attempting to destroy the window while drawing!\n" +
Craig Mautner8f303ad2013-06-14 11:32:22 -07005774 " window=" + this + ", title=" + mWindowAttributes.getTitle());
5775 }
5776 mHandler.sendEmptyMessage(MSG_DIE);
5777 return true;
Dianne Hackborn94d69142009-09-28 22:14:42 -07005778 }
5779
5780 void doDie() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005781 checkThread();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005782 if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005783 synchronized (this) {
Craig Mautner8f303ad2013-06-14 11:32:22 -07005784 if (mRemoved) {
5785 return;
5786 }
5787 mRemoved = true;
Romain Guy16260e72011-09-01 14:26:11 -07005788 if (mAdded) {
Romain Guy16260e72011-09-01 14:26:11 -07005789 dispatchDetachedFromWindow();
5790 }
5791
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005792 if (mAdded && !mFirst) {
Romain Guy29d89972010-09-22 16:10:57 -07005793 destroyHardwareRenderer();
5794
Romain Guyedbca122012-04-04 18:25:53 -07005795 if (mView != null) {
5796 int viewVisibility = mView.getVisibility();
5797 boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
5798 if (mWindowAttributesChanged || viewVisibilityChanged) {
5799 // If layout params have been changed, first give them
5800 // to the window manager to make sure it has the correct
5801 // animation info.
5802 try {
5803 if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
Jeff Brown98365d72012-08-19 20:30:52 -07005804 & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
5805 mWindowSession.finishDrawing(mWindow);
Romain Guyedbca122012-04-04 18:25:53 -07005806 }
5807 } catch (RemoteException e) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005808 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005809 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07005810
Romain Guyedbca122012-04-04 18:25:53 -07005811 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005812 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005813 }
Romain Guyedbca122012-04-04 18:25:53 -07005814
5815 mAdded = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005816 }
Craig Mautner05eb7302013-06-03 17:24:21 -07005817 WindowManagerGlobal.getInstance().doRemoveView(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005818 }
5819
Dianne Hackborn5fd21692011-06-07 14:09:47 -07005820 public void requestUpdateConfiguration(Configuration config) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005821 Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
5822 mHandler.sendMessage(msg);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07005823 }
5824
Dianne Hackborna53de062012-05-08 18:53:51 -07005825 public void loadSystemProperties() {
Romain Guy5bb3c732012-11-29 17:52:58 -08005826 mHandler.post(new Runnable() {
5827 @Override
5828 public void run() {
5829 // Profiling
5830 mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false);
5831 profileRendering(mAttachInfo.mHasWindowFocus);
5832
5833 // Hardware rendering
5834 if (mAttachInfo.mHardwareRenderer != null) {
John Reckcec24ae2013-11-05 13:27:50 -08005835 if (mAttachInfo.mHardwareRenderer.loadSystemProperties()) {
Romain Guy5bb3c732012-11-29 17:52:58 -08005836 invalidate();
5837 }
5838 }
5839
5840 // Layout debugging
5841 boolean layout = SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false);
5842 if (layout != mAttachInfo.mDebugLayout) {
5843 mAttachInfo.mDebugLayout = layout;
5844 if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
5845 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
5846 }
5847 }
Dianne Hackborna53de062012-05-08 18:53:51 -07005848 }
Romain Guy5bb3c732012-11-29 17:52:58 -08005849 });
Dianne Hackborna53de062012-05-08 18:53:51 -07005850 }
5851
Romain Guy29d89972010-09-22 16:10:57 -07005852 private void destroyHardwareRenderer() {
John Reck51aaf902015-12-02 15:08:07 -08005853 ThreadedRenderer hardwareRenderer = mAttachInfo.mHardwareRenderer;
Romain Guya998dff2012-03-23 18:58:36 -07005854
5855 if (hardwareRenderer != null) {
5856 if (mView != null) {
5857 hardwareRenderer.destroyHardwareResources(mView);
5858 }
John Reckf47a5942014-06-30 16:20:04 -07005859 hardwareRenderer.destroy();
Romain Guya998dff2012-03-23 18:58:36 -07005860 hardwareRenderer.setRequested(false);
5861
Chris Craikd36a81f2014-07-17 10:16:51 -07005862 mAttachInfo.mHardwareRenderer = null;
5863 mAttachInfo.mHardwareAccelerated = false;
Romain Guy29d89972010-09-22 16:10:57 -07005864 }
5865 }
5866
Jeff Browna175a5b2012-02-15 19:18:31 -08005867 public void dispatchFinishInputConnection(InputConnection connection) {
5868 Message msg = mHandler.obtainMessage(MSG_FINISH_INPUT_CONNECTION, connection);
5869 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005870 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005871
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005872 public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Filip Gruszczynski2217f612015-05-26 11:32:08 -07005873 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08005874 Configuration newConfig, Rect backDropFrame, boolean forceLayout,
5875 boolean alwaysConsumeNavBar) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005876 if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005877 + " contentInsets=" + contentInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005878 + " visibleInsets=" + visibleInsets.toShortString()
Chong Zhangd153c4f2015-11-06 20:26:40 -08005879 + " reportDraw=" + reportDraw
5880 + " backDropFrame=" + backDropFrame);
Chong Zhangdcee1de2015-10-06 10:26:00 -07005881
5882 // Tell all listeners that we are resizing the window so that the chrome can get
5883 // updated as fast as possible on a separate thread,
5884 if (mDragResizing) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08005885 boolean fullscreen = frame.equals(backDropFrame);
Chong Zhangdcee1de2015-10-06 10:26:00 -07005886 synchronized (mWindowCallbacks) {
5887 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08005888 mWindowCallbacks.get(i).onWindowSizeIsChanging(backDropFrame, fullscreen,
5889 visibleInsets, stableInsets);
Chong Zhangdcee1de2015-10-06 10:26:00 -07005890 }
5891 }
5892 }
5893
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005894 Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005895 if (mTranslator != null) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005896 mTranslator.translateRectInScreenToAppWindow(frame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005897 mTranslator.translateRectInScreenToAppWindow(overscanInsets);
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07005898 mTranslator.translateRectInScreenToAppWindow(contentInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005899 mTranslator.translateRectInScreenToAppWindow(visibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005900 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005901 SomeArgs args = SomeArgs.obtain();
5902 final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
5903 args.arg1 = sameProcessCall ? new Rect(frame) : frame;
5904 args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets;
5905 args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
5906 args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005907 args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
Adrian Roosfa104232014-06-20 16:10:14 -07005908 args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
Filip Gruszczynski2217f612015-05-26 11:32:08 -07005909 args.arg7 = sameProcessCall ? new Rect(outsets) : outsets;
Jorim Jaggia7262a82015-11-03 15:15:40 +01005910 args.arg8 = sameProcessCall ? new Rect(backDropFrame) : backDropFrame;
Jorim Jaggia4a58ef2016-01-27 02:10:08 -08005911 args.argi1 = forceLayout ? 1 : 0;
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08005912 args.argi2 = alwaysConsumeNavBar ? 1 : 0;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005913 msg.obj = args;
Jeff Browna175a5b2012-02-15 19:18:31 -08005914 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005915 }
Chet Haase1f4786b2011-11-02 10:51:52 -07005916
Craig Mautner5702d4d2012-06-30 14:10:16 -07005917 public void dispatchMoved(int newX, int newY) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005918 if (DEBUG_LAYOUT) Log.v(mTag, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
Craig Mautner5702d4d2012-06-30 14:10:16 -07005919 if (mTranslator != null) {
5920 PointF point = new PointF(newX, newY);
5921 mTranslator.translatePointInScreenToAppWindow(point);
5922 newX = (int) (point.x + 0.5);
5923 newY = (int) (point.y + 0.5);
5924 }
5925 Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY);
5926 mHandler.sendMessage(msg);
5927 }
5928
Jeff Brown4952dfd2011-11-30 19:23:22 -08005929 /**
5930 * Represents a pending input event that is waiting in a queue.
5931 *
5932 * Input events are processed in serial order by the timestamp specified by
Romain Guy211370f2012-02-01 16:10:55 -08005933 * {@link InputEvent#getEventTimeNano()}. In general, the input dispatcher delivers
Jeff Brown4952dfd2011-11-30 19:23:22 -08005934 * one input event to the application at a time and waits for the application
5935 * to finish handling it before delivering the next one.
5936 *
5937 * However, because the application or IME can synthesize and inject multiple
5938 * key events at a time without going through the input dispatcher, we end up
5939 * needing a queue on the application's side.
5940 */
5941 private static final class QueuedInputEvent {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005942 public static final int FLAG_DELIVER_POST_IME = 1 << 0;
5943 public static final int FLAG_DEFERRED = 1 << 1;
5944 public static final int FLAG_FINISHED = 1 << 2;
5945 public static final int FLAG_FINISHED_HANDLED = 1 << 3;
5946 public static final int FLAG_RESYNTHESIZED = 1 << 4;
Michael Wright899d7052014-04-23 17:23:39 -07005947 public static final int FLAG_UNHANDLED = 1 << 5;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005948
5949 public QueuedInputEvent mNext;
5950
5951 public InputEvent mEvent;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005952 public InputEventReceiver mReceiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005953 public int mFlags;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005954
5955 public boolean shouldSkipIme() {
5956 if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
5957 return true;
5958 }
5959 return mEvent instanceof MotionEvent
5960 && mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER);
5961 }
Michael Wright899d7052014-04-23 17:23:39 -07005962
5963 public boolean shouldSendToSynthesizer() {
5964 if ((mFlags & FLAG_UNHANDLED) != 0) {
5965 return true;
5966 }
5967
5968 return false;
5969 }
Michael Wright06a79252014-05-05 17:45:29 -07005970
5971 @Override
5972 public String toString() {
5973 StringBuilder sb = new StringBuilder("QueuedInputEvent{flags=");
5974 boolean hasPrevious = false;
5975 hasPrevious = flagToString("DELIVER_POST_IME", FLAG_DELIVER_POST_IME, hasPrevious, sb);
5976 hasPrevious = flagToString("DEFERRED", FLAG_DEFERRED, hasPrevious, sb);
5977 hasPrevious = flagToString("FINISHED", FLAG_FINISHED, hasPrevious, sb);
5978 hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb);
5979 hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb);
5980 hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb);
5981 if (!hasPrevious) {
5982 sb.append("0");
5983 }
5984 sb.append(", hasNextQueuedEvent=" + (mEvent != null ? "true" : "false"));
5985 sb.append(", hasInputEventReceiver=" + (mReceiver != null ? "true" : "false"));
5986 sb.append(", mEvent=" + mEvent + "}");
5987 return sb.toString();
5988 }
5989
5990 private boolean flagToString(String name, int flag,
5991 boolean hasPrevious, StringBuilder sb) {
5992 if ((mFlags & flag) != 0) {
5993 if (hasPrevious) {
5994 sb.append("|");
5995 }
5996 sb.append(name);
5997 return true;
5998 }
5999 return hasPrevious;
6000 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08006001 }
6002
6003 private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
Jeff Brown32cbc38552011-12-01 14:01:49 -08006004 InputEventReceiver receiver, int flags) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08006005 QueuedInputEvent q = mQueuedInputEventPool;
6006 if (q != null) {
6007 mQueuedInputEventPoolSize -= 1;
6008 mQueuedInputEventPool = q.mNext;
6009 q.mNext = null;
6010 } else {
6011 q = new QueuedInputEvent();
Jeff Brown46b9ac02010-04-22 18:58:52 -07006012 }
6013
Jeff Brown4952dfd2011-11-30 19:23:22 -08006014 q.mEvent = event;
Jeff Brown32cbc38552011-12-01 14:01:49 -08006015 q.mReceiver = receiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006016 q.mFlags = flags;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006017 return q;
6018 }
6019
6020 private void recycleQueuedInputEvent(QueuedInputEvent q) {
6021 q.mEvent = null;
Jeff Brown32cbc38552011-12-01 14:01:49 -08006022 q.mReceiver = null;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006023
6024 if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
6025 mQueuedInputEventPoolSize += 1;
6026 q.mNext = mQueuedInputEventPool;
6027 mQueuedInputEventPool = q;
6028 }
6029 }
6030
Jeff Brownf9261d22012-02-03 13:49:15 -08006031 void enqueueInputEvent(InputEvent event) {
6032 enqueueInputEvent(event, null, 0, false);
6033 }
6034
Jeff Brown4952dfd2011-11-30 19:23:22 -08006035 void enqueueInputEvent(InputEvent event,
Jeff Brownf9261d22012-02-03 13:49:15 -08006036 InputEventReceiver receiver, int flags, boolean processImmediately) {
Michael Wright5bd69e62015-05-14 14:48:08 +01006037 adjustInputEventForCompatibility(event);
Jeff Brown32cbc38552011-12-01 14:01:49 -08006038 QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
Jeff Brown4952dfd2011-11-30 19:23:22 -08006039
Jeff Brown4952dfd2011-11-30 19:23:22 -08006040 // Always enqueue the input event in order, regardless of its time stamp.
6041 // We do this because the application or the IME may inject key events
6042 // in response to touch events and we want to ensure that the injected keys
6043 // are processed in the order they were received and we cannot trust that
6044 // the time stamp of injected events are monotonic.
Michael Wrightc8a7e542013-03-20 17:58:33 -07006045 QueuedInputEvent last = mPendingInputEventTail;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006046 if (last == null) {
Michael Wrightc8a7e542013-03-20 17:58:33 -07006047 mPendingInputEventHead = q;
6048 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006049 } else {
Jeff Brown4952dfd2011-11-30 19:23:22 -08006050 last.mNext = q;
Michael Wrightc8a7e542013-03-20 17:58:33 -07006051 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006052 }
Michael Wright95ae9422013-03-14 10:58:50 -07006053 mPendingInputEventCount += 1;
6054 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
6055 mPendingInputEventCount);
Jeff Brown4952dfd2011-11-30 19:23:22 -08006056
Jeff Brownf9261d22012-02-03 13:49:15 -08006057 if (processImmediately) {
6058 doProcessInputEvents();
6059 } else {
6060 scheduleProcessInputEvents();
6061 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08006062 }
6063
6064 private void scheduleProcessInputEvents() {
Jeff Brown96e942d2011-11-30 19:55:01 -08006065 if (!mProcessInputEventsScheduled) {
6066 mProcessInputEventsScheduled = true;
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006067 Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
6068 msg.setAsynchronous(true);
6069 mHandler.sendMessage(msg);
Jeff Brown4952dfd2011-11-30 19:23:22 -08006070 }
6071 }
6072
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006073 void doProcessInputEvents() {
Jeff Brownf9e989d2013-04-04 23:04:03 -07006074 // Deliver all pending input events in the queue.
Michael Wrightc8a7e542013-03-20 17:58:33 -07006075 while (mPendingInputEventHead != null) {
6076 QueuedInputEvent q = mPendingInputEventHead;
6077 mPendingInputEventHead = q.mNext;
6078 if (mPendingInputEventHead == null) {
6079 mPendingInputEventTail = null;
6080 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08006081 q.mNext = null;
Jeff Brown29c0ed22013-01-14 13:50:37 -08006082
Michael Wright95ae9422013-03-14 10:58:50 -07006083 mPendingInputEventCount -= 1;
6084 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
6085 mPendingInputEventCount);
6086
John Reckba6adf62015-02-19 14:36:50 -08006087 long eventTime = q.mEvent.getEventTimeNano();
6088 long oldestEventTime = eventTime;
6089 if (q.mEvent instanceof MotionEvent) {
6090 MotionEvent me = (MotionEvent)q.mEvent;
6091 if (me.getHistorySize() > 0) {
6092 oldestEventTime = me.getHistoricalEventTimeNano(0);
6093 }
6094 }
6095 mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
6096
Jeff Brownf9e989d2013-04-04 23:04:03 -07006097 deliverInputEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08006098 }
6099
6100 // We are done processing all input events that we can process right now
6101 // so we can clear the pending flag immediately.
Jeff Brown96e942d2011-11-30 19:55:01 -08006102 if (mProcessInputEventsScheduled) {
6103 mProcessInputEventsScheduled = false;
Jeff Browna175a5b2012-02-15 19:18:31 -08006104 mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
Jeff Brown4952dfd2011-11-30 19:23:22 -08006105 }
6106 }
6107
Jeff Brownf9e989d2013-04-04 23:04:03 -07006108 private void deliverInputEvent(QueuedInputEvent q) {
Michael Wrightd2c3adc2014-02-18 22:50:50 -08006109 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
6110 q.mEvent.getSequenceNumber());
6111 if (mInputEventConsistencyVerifier != null) {
6112 mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
6113 }
Michael Wrightc8a7e542013-03-20 17:58:33 -07006114
Michael Wright899d7052014-04-23 17:23:39 -07006115 InputStage stage;
6116 if (q.shouldSendToSynthesizer()) {
6117 stage = mSyntheticInputStage;
6118 } else {
6119 stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
6120 }
6121
Michael Wrightd2c3adc2014-02-18 22:50:50 -08006122 if (stage != null) {
6123 stage.deliver(q);
6124 } else {
6125 finishInputEvent(q);
Michael Wrightbf020962013-03-28 17:27:50 -07006126 }
Michael Wrightbf020962013-03-28 17:27:50 -07006127 }
6128
Jeff Brownf9e989d2013-04-04 23:04:03 -07006129 private void finishInputEvent(QueuedInputEvent q) {
Michael Wrightd2c3adc2014-02-18 22:50:50 -08006130 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
6131 q.mEvent.getSequenceNumber());
Michael Wright9d744c72014-02-18 21:27:42 -08006132
Jeff Brown32cbc38552011-12-01 14:01:49 -08006133 if (q.mReceiver != null) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07006134 boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
Jeff Brown32cbc38552011-12-01 14:01:49 -08006135 q.mReceiver.finishInputEvent(q.mEvent, handled);
Jeff Brown92cc2d82011-12-02 01:19:47 -08006136 } else {
6137 q.mEvent.recycleIfNeededAfterDispatch();
Jeff Brown4952dfd2011-11-30 19:23:22 -08006138 }
6139
6140 recycleQueuedInputEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08006141 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08006142
Michael Wright5bd69e62015-05-14 14:48:08 +01006143 private void adjustInputEventForCompatibility(InputEvent e) {
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006144 if (mTargetSdkVersion < Build.VERSION_CODES.M && e instanceof MotionEvent) {
Michael Wright5bd69e62015-05-14 14:48:08 +01006145 MotionEvent motion = (MotionEvent) e;
6146 final int mask =
6147 MotionEvent.BUTTON_STYLUS_PRIMARY | MotionEvent.BUTTON_STYLUS_SECONDARY;
6148 final int buttonState = motion.getButtonState();
6149 final int compatButtonState = (buttonState & mask) >> 4;
6150 if (compatButtonState != 0) {
6151 motion.setButtonState(buttonState | compatButtonState);
6152 }
6153 }
6154 }
6155
Jeff Brownf9e989d2013-04-04 23:04:03 -07006156 static boolean isTerminalInputEvent(InputEvent event) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08006157 if (event instanceof KeyEvent) {
6158 final KeyEvent keyEvent = (KeyEvent)event;
6159 return keyEvent.getAction() == KeyEvent.ACTION_UP;
6160 } else {
6161 final MotionEvent motionEvent = (MotionEvent)event;
6162 final int action = motionEvent.getAction();
6163 return action == MotionEvent.ACTION_UP
6164 || action == MotionEvent.ACTION_CANCEL
6165 || action == MotionEvent.ACTION_HOVER_EXIT;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006166 }
6167 }
6168
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006169 void scheduleConsumeBatchedInput() {
6170 if (!mConsumeBatchedInputScheduled) {
6171 mConsumeBatchedInputScheduled = true;
6172 mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
6173 mConsumedBatchedInputRunnable, null);
Jeff Brown4a06c802012-02-15 15:06:01 -08006174 }
6175 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006176
6177 void unscheduleConsumeBatchedInput() {
6178 if (mConsumeBatchedInputScheduled) {
6179 mConsumeBatchedInputScheduled = false;
6180 mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT,
6181 mConsumedBatchedInputRunnable, null);
6182 }
6183 }
6184
Michael Wright9d744c72014-02-18 21:27:42 -08006185 void scheduleConsumeBatchedInputImmediately() {
6186 if (!mConsumeBatchedInputImmediatelyScheduled) {
6187 unscheduleConsumeBatchedInput();
6188 mConsumeBatchedInputImmediatelyScheduled = true;
6189 mHandler.post(mConsumeBatchedInputImmediatelyRunnable);
6190 }
6191 }
6192
Jeff Brown771526c2012-04-27 15:13:25 -07006193 void doConsumeBatchedInput(long frameTimeNanos) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006194 if (mConsumeBatchedInputScheduled) {
6195 mConsumeBatchedInputScheduled = false;
Jeff Brown330314c2012-04-27 02:20:22 -07006196 if (mInputEventReceiver != null) {
Michael Wright9d744c72014-02-18 21:27:42 -08006197 if (mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos)
6198 && frameTimeNanos != -1) {
Michael Wright62ce65d2013-10-25 14:50:36 -07006199 // If we consumed a batch here, we want to go ahead and schedule the
6200 // consumption of batched input events on the next frame. Otherwise, we would
6201 // wait until we have more input events pending and might get starved by other
Michael Wright9d744c72014-02-18 21:27:42 -08006202 // things occurring in the process. If the frame time is -1, however, then
6203 // we're in a non-batching mode, so there's no need to schedule this.
Michael Wright62ce65d2013-10-25 14:50:36 -07006204 scheduleConsumeBatchedInput();
6205 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006206 }
Jeff Brown330314c2012-04-27 02:20:22 -07006207 doProcessInputEvents();
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006208 }
6209 }
6210
6211 final class TraversalRunnable implements Runnable {
6212 @Override
6213 public void run() {
6214 doTraversal();
6215 }
6216 }
6217 final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
Jeff Brown4a06c802012-02-15 15:06:01 -08006218
Jeff Brown32cbc38552011-12-01 14:01:49 -08006219 final class WindowInputEventReceiver extends InputEventReceiver {
6220 public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
6221 super(inputChannel, looper);
Jeff Brown46b9ac02010-04-22 18:58:52 -07006222 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08006223
6224 @Override
6225 public void onInputEvent(InputEvent event) {
Jeff Brownf9261d22012-02-03 13:49:15 -08006226 enqueueInputEvent(event, this, 0, true);
Jeff Brown32cbc38552011-12-01 14:01:49 -08006227 }
Jeff Brown072ec962012-02-07 14:46:57 -08006228
6229 @Override
6230 public void onBatchedInputEventPending() {
Michael Wright9d744c72014-02-18 21:27:42 -08006231 if (mUnbufferedInputDispatch) {
6232 super.onBatchedInputEventPending();
6233 } else {
6234 scheduleConsumeBatchedInput();
6235 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006236 }
6237
6238 @Override
6239 public void dispose() {
6240 unscheduleConsumeBatchedInput();
6241 super.dispose();
Jeff Brown072ec962012-02-07 14:46:57 -08006242 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08006243 }
6244 WindowInputEventReceiver mInputEventReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006245
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006246 final class ConsumeBatchedInputRunnable implements Runnable {
6247 @Override
6248 public void run() {
Jeff Brown771526c2012-04-27 15:13:25 -07006249 doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006250 }
6251 }
6252 final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =
6253 new ConsumeBatchedInputRunnable();
6254 boolean mConsumeBatchedInputScheduled;
6255
Michael Wright9d744c72014-02-18 21:27:42 -08006256 final class ConsumeBatchedInputImmediatelyRunnable implements Runnable {
6257 @Override
6258 public void run() {
6259 doConsumeBatchedInput(-1);
6260 }
6261 }
6262 final ConsumeBatchedInputImmediatelyRunnable mConsumeBatchedInputImmediatelyRunnable =
6263 new ConsumeBatchedInputImmediatelyRunnable();
6264 boolean mConsumeBatchedInputImmediatelyScheduled;
6265
Jeff Brown6cb7b462012-03-05 13:21:17 -08006266 final class InvalidateOnAnimationRunnable implements Runnable {
6267 private boolean mPosted;
Igor Murashkina86ab6402013-08-30 12:58:36 -07006268 private final ArrayList<View> mViews = new ArrayList<View>();
6269 private final ArrayList<AttachInfo.InvalidateInfo> mViewRects =
Jeff Brown6cb7b462012-03-05 13:21:17 -08006270 new ArrayList<AttachInfo.InvalidateInfo>();
6271 private View[] mTempViews;
6272 private AttachInfo.InvalidateInfo[] mTempViewRects;
6273
6274 public void addView(View view) {
6275 synchronized (this) {
6276 mViews.add(view);
6277 postIfNeededLocked();
6278 }
6279 }
6280
6281 public void addViewRect(AttachInfo.InvalidateInfo info) {
6282 synchronized (this) {
6283 mViewRects.add(info);
6284 postIfNeededLocked();
6285 }
6286 }
6287
6288 public void removeView(View view) {
6289 synchronized (this) {
6290 mViews.remove(view);
6291
6292 for (int i = mViewRects.size(); i-- > 0; ) {
6293 AttachInfo.InvalidateInfo info = mViewRects.get(i);
6294 if (info.target == view) {
6295 mViewRects.remove(i);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08006296 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08006297 }
6298 }
6299
6300 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006301 mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08006302 mPosted = false;
6303 }
6304 }
6305 }
6306
6307 @Override
6308 public void run() {
6309 final int viewCount;
6310 final int viewRectCount;
6311 synchronized (this) {
6312 mPosted = false;
6313
6314 viewCount = mViews.size();
6315 if (viewCount != 0) {
6316 mTempViews = mViews.toArray(mTempViews != null
6317 ? mTempViews : new View[viewCount]);
6318 mViews.clear();
6319 }
6320
6321 viewRectCount = mViewRects.size();
6322 if (viewRectCount != 0) {
6323 mTempViewRects = mViewRects.toArray(mTempViewRects != null
6324 ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]);
6325 mViewRects.clear();
6326 }
6327 }
6328
6329 for (int i = 0; i < viewCount; i++) {
6330 mTempViews[i].invalidate();
Adam Powell3e3c4ee2012-05-16 17:34:21 -07006331 mTempViews[i] = null;
Jeff Brown6cb7b462012-03-05 13:21:17 -08006332 }
6333
6334 for (int i = 0; i < viewRectCount; i++) {
6335 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
6336 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08006337 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08006338 }
6339 }
6340
6341 private void postIfNeededLocked() {
6342 if (!mPosted) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006343 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08006344 mPosted = true;
6345 }
6346 }
6347 }
6348 final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
6349 new InvalidateOnAnimationRunnable();
6350
Jeff Browna175a5b2012-02-15 19:18:31 -08006351 public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
6352 Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
6353 mHandler.sendMessageDelayed(msg, delayMilliseconds);
6354 }
6355
Jeff Browna175a5b2012-02-15 19:18:31 -08006356 public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
6357 long delayMilliseconds) {
6358 final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
6359 mHandler.sendMessageDelayed(msg, delayMilliseconds);
6360 }
6361
Jeff Brown6cb7b462012-03-05 13:21:17 -08006362 public void dispatchInvalidateOnAnimation(View view) {
6363 mInvalidateOnAnimationRunnable.addView(view);
6364 }
6365
6366 public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) {
6367 mInvalidateOnAnimationRunnable.addViewRect(info);
6368 }
6369
6370 public void cancelInvalidate(View view) {
6371 mHandler.removeMessages(MSG_INVALIDATE, view);
6372 // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning
6373 // them to the pool
6374 mHandler.removeMessages(MSG_INVALIDATE_RECT, view);
6375 mInvalidateOnAnimationRunnable.removeView(view);
6376 }
6377
keunyoung30f420f2013-08-02 14:23:10 -07006378 public void dispatchInputEvent(InputEvent event) {
Jae Seo6a6059a2014-04-17 21:35:29 -07006379 dispatchInputEvent(event, null);
6380 }
6381
6382 public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
6383 SomeArgs args = SomeArgs.obtain();
6384 args.arg1 = event;
6385 args.arg2 = receiver;
6386 Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
Jeff Browne0dbd002012-02-15 19:34:58 -08006387 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08006388 mHandler.sendMessage(msg);
6389 }
6390
Michael Wright899d7052014-04-23 17:23:39 -07006391 public void synthesizeInputEvent(InputEvent event) {
6392 Message msg = mHandler.obtainMessage(MSG_SYNTHESIZE_INPUT_EVENT, event);
6393 msg.setAsynchronous(true);
6394 mHandler.sendMessage(msg);
6395 }
6396
Jeff Browna175a5b2012-02-15 19:18:31 -08006397 public void dispatchKeyFromIme(KeyEvent event) {
6398 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
Jeff Browne0dbd002012-02-15 19:34:58 -08006399 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08006400 mHandler.sendMessage(msg);
Jeff Browncb1404e2011-01-15 18:14:15 -08006401 }
6402
Michael Wright899d7052014-04-23 17:23:39 -07006403 /**
6404 * Reinject unhandled {@link InputEvent}s in order to synthesize fallbacks events.
6405 *
6406 * Note that it is the responsibility of the caller of this API to recycle the InputEvent it
6407 * passes in.
6408 */
Michael Wright3da28342014-04-22 17:00:11 -07006409 public void dispatchUnhandledInputEvent(InputEvent event) {
Michael Wright899d7052014-04-23 17:23:39 -07006410 if (event instanceof MotionEvent) {
6411 event = MotionEvent.obtain((MotionEvent) event);
Michael Wright3da28342014-04-22 17:00:11 -07006412 }
Michael Wright899d7052014-04-23 17:23:39 -07006413 synthesizeInputEvent(event);
Michael Wright3da28342014-04-22 17:00:11 -07006414 }
6415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006416 public void dispatchAppVisibility(boolean visible) {
Jeff Browna175a5b2012-02-15 19:18:31 -08006417 Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006418 msg.arg1 = visible ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08006419 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006420 }
6421
6422 public void dispatchGetNewSurface() {
Jeff Browna175a5b2012-02-15 19:18:31 -08006423 Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
6424 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006425 }
6426
6427 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
6428 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08006429 msg.what = MSG_WINDOW_FOCUS_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006430 msg.arg1 = hasFocus ? 1 : 0;
6431 msg.arg2 = inTouchMode ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08006432 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006433 }
6434
Craig Mautner9c795042014-10-28 19:59:59 -07006435 public void dispatchWindowShown() {
6436 mHandler.sendEmptyMessage(MSG_DISPATCH_WINDOW_SHOWN);
6437 }
6438
Dianne Hackbornffa42482009-09-23 22:20:11 -07006439 public void dispatchCloseSystemDialogs(String reason) {
6440 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08006441 msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
Dianne Hackbornffa42482009-09-23 22:20:11 -07006442 msg.obj = reason;
Jeff Browna175a5b2012-02-15 19:18:31 -08006443 mHandler.sendMessage(msg);
Dianne Hackbornffa42482009-09-23 22:20:11 -07006444 }
Christopher Tatea53146c2010-09-07 11:57:52 -07006445
6446 public void dispatchDragEvent(DragEvent event) {
Chris Tate91e9bb32010-10-12 12:58:43 -07006447 final int what;
6448 if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
Jeff Browna175a5b2012-02-15 19:18:31 -08006449 what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
6450 mHandler.removeMessages(what);
Chris Tate91e9bb32010-10-12 12:58:43 -07006451 } else {
Jeff Browna175a5b2012-02-15 19:18:31 -08006452 what = MSG_DISPATCH_DRAG_EVENT;
Chris Tate91e9bb32010-10-12 12:58:43 -07006453 }
Jeff Browna175a5b2012-02-15 19:18:31 -08006454 Message msg = mHandler.obtainMessage(what, event);
6455 mHandler.sendMessage(msg);
Christopher Tatea53146c2010-09-07 11:57:52 -07006456 }
6457
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08006458 public void updatePointerIcon(float x, float y) {
6459 final int what = MSG_UPDATE_POINTER_ICON;
6460 mHandler.removeMessages(what);
6461 final long now = SystemClock.uptimeMillis();
6462 final MotionEvent event = MotionEvent.obtain(
6463 0, now, MotionEvent.ACTION_HOVER_MOVE, x, y, 0);
6464 Message msg = mHandler.obtainMessage(what, event);
6465 mHandler.sendMessage(msg);
6466 }
6467
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006468 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
6469 int localValue, int localChanges) {
6470 SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
6471 args.seq = seq;
6472 args.globalVisibility = globalVisibility;
6473 args.localValue = localValue;
6474 args.localChanges = localChanges;
Jeff Browna175a5b2012-02-15 19:18:31 -08006475 mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
6476 }
6477
6478 public void dispatchCheckFocus() {
6479 if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
6480 // This will result in a call to checkFocus() below.
6481 mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
6482 }
Joe Onorato664644d2011-01-23 17:53:23 -08006483 }
6484
Clara Bayarri75e09792015-07-29 16:20:40 +01006485 public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver) {
6486 mHandler.obtainMessage(MSG_REQUEST_KEYBOARD_SHORTCUTS, receiver).sendToTarget();
6487 }
6488
svetoslavganov75986cf2009-05-14 22:28:01 -07006489 /**
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006490 * Post a callback to send a
6491 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
Svetoslav Ganova0156172011-06-26 17:55:44 -07006492 * This event is send at most once every
6493 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006494 */
Alan Viverette77e9a282013-09-12 17:16:09 -07006495 private void postSendWindowContentChangedCallback(View source, int changeType) {
Svetoslav Ganova0156172011-06-26 17:55:44 -07006496 if (mSendWindowContentChangedAccessibilityEvent == null) {
6497 mSendWindowContentChangedAccessibilityEvent =
6498 new SendWindowContentChangedAccessibilityEvent();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006499 }
Alan Viverette77e9a282013-09-12 17:16:09 -07006500 mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006501 }
6502
6503 /**
6504 * Remove a posted callback to send a
6505 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
6506 */
6507 private void removeSendWindowContentChangedCallback() {
Svetoslav Ganova0156172011-06-26 17:55:44 -07006508 if (mSendWindowContentChangedAccessibilityEvent != null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08006509 mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006510 }
6511 }
6512
Igor Murashkina86ab6402013-08-30 12:58:36 -07006513 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006514 public boolean showContextMenuForChild(View originalView) {
6515 return false;
6516 }
6517
Igor Murashkina86ab6402013-08-30 12:58:36 -07006518 @Override
Oren Blasberged391262015-09-01 12:12:51 -07006519 public boolean showContextMenuForChild(View originalView, float x, float y) {
6520 return false;
6521 }
6522
6523 @Override
Adam Powell6e346362010-07-23 10:18:23 -07006524 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
6525 return null;
6526 }
6527
Igor Murashkina86ab6402013-08-30 12:58:36 -07006528 @Override
Clara Bayarri4423d912015-03-02 19:42:48 +00006529 public ActionMode startActionModeForChild(
6530 View originalView, ActionMode.Callback callback, int type) {
6531 return null;
6532 }
6533
6534 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006535 public void createContextMenu(ContextMenu menu) {
6536 }
6537
Igor Murashkina86ab6402013-08-30 12:58:36 -07006538 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006539 public void childDrawableStateChanged(View child) {
6540 }
6541
Igor Murashkina86ab6402013-08-30 12:58:36 -07006542 @Override
Svetoslav Ganov736c2752011-04-22 18:30:36 -07006543 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
George Mount41725de2015-04-09 08:23:05 -07006544 if (mView == null || mStopped || mPausedForTransition) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -07006545 return false;
6546 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006547 // Intercept accessibility focus events fired by virtual nodes to keep
6548 // track of accessibility focus position in such nodes.
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006549 final int eventType = event.getEventType();
6550 switch (eventType) {
6551 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006552 final long sourceNodeId = event.getSourceNodeId();
6553 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
6554 sourceNodeId);
6555 View source = mView.findViewByAccessibilityId(accessibilityViewId);
6556 if (source != null) {
6557 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
6558 if (provider != null) {
Svetoslavb3ba1d42014-09-26 15:20:40 -07006559 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
6560 sourceNodeId);
6561 final AccessibilityNodeInfo node;
6562 if (virtualNodeId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
6563 node = provider.createAccessibilityNodeInfo(
6564 AccessibilityNodeProvider.HOST_VIEW_ID);
6565 } else {
6566 node = provider.createAccessibilityNodeInfo(virtualNodeId);
6567 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006568 setAccessibilityFocus(source, node);
6569 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006570 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006571 } break;
6572 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006573 final long sourceNodeId = event.getSourceNodeId();
6574 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
6575 sourceNodeId);
6576 View source = mView.findViewByAccessibilityId(accessibilityViewId);
6577 if (source != null) {
6578 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
6579 if (provider != null) {
6580 setAccessibilityFocus(null, null);
6581 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006582 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006583 } break;
Svetoslavf0c758b2014-09-03 17:47:37 -07006584
6585
6586 case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: {
Alan Viverette34457f52015-03-25 13:09:20 -07006587 handleWindowContentChangedEvent(event);
Svetoslavf0c758b2014-09-03 17:47:37 -07006588 } break;
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006589 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006590 mAccessibilityManager.sendAccessibilityEvent(event);
Svetoslav Ganov736c2752011-04-22 18:30:36 -07006591 return true;
6592 }
6593
Alan Viverette34457f52015-03-25 13:09:20 -07006594 /**
6595 * Updates the focused virtual view, when necessary, in response to a
6596 * content changed event.
6597 * <p>
6598 * This is necessary to get updated bounds after a position change.
6599 *
6600 * @param event an accessibility event of type
6601 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}
6602 */
6603 private void handleWindowContentChangedEvent(AccessibilityEvent event) {
Alan Viverette25acc7e2015-05-19 11:32:08 -07006604 final View focusedHost = mAccessibilityFocusedHost;
6605 if (focusedHost == null || mAccessibilityFocusedVirtualView == null) {
6606 // No virtual view focused, nothing to do here.
Alan Viverette34457f52015-03-25 13:09:20 -07006607 return;
6608 }
6609
Alan Viverette25acc7e2015-05-19 11:32:08 -07006610 final AccessibilityNodeProvider provider = focusedHost.getAccessibilityNodeProvider();
Alan Viverette34457f52015-03-25 13:09:20 -07006611 if (provider == null) {
Alan Viverette25acc7e2015-05-19 11:32:08 -07006612 // Error state: virtual view with no provider. Clear focus.
6613 mAccessibilityFocusedHost = null;
6614 mAccessibilityFocusedVirtualView = null;
6615 focusedHost.clearAccessibilityFocusNoCallbacks();
Alan Viverette34457f52015-03-25 13:09:20 -07006616 return;
6617 }
6618
6619 // We only care about change types that may affect the bounds of the
6620 // focused virtual view.
6621 final int changes = event.getContentChangeTypes();
6622 if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) == 0
6623 && changes != AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) {
6624 return;
6625 }
6626
6627 final long eventSourceNodeId = event.getSourceNodeId();
6628 final int changedViewId = AccessibilityNodeInfo.getAccessibilityViewId(eventSourceNodeId);
6629
6630 // Search up the tree for subtree containment.
6631 boolean hostInSubtree = false;
6632 View root = mAccessibilityFocusedHost;
6633 while (root != null && !hostInSubtree) {
6634 if (changedViewId == root.getAccessibilityViewId()) {
6635 hostInSubtree = true;
6636 } else {
6637 final ViewParent parent = root.getParent();
6638 if (parent instanceof View) {
6639 root = (View) parent;
6640 } else {
6641 root = null;
6642 }
6643 }
6644 }
6645
6646 // We care only about changes in subtrees containing the host view.
6647 if (!hostInSubtree) {
6648 return;
6649 }
6650
6651 final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId();
6652 int focusedChildId = AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId);
6653 if (focusedChildId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
6654 // TODO: Should we clear the focused virtual view?
6655 focusedChildId = AccessibilityNodeProvider.HOST_VIEW_ID;
6656 }
6657
6658 // Refresh the node for the focused virtual view.
Alan Viverettea7ea65e2015-05-15 11:30:21 -07006659 final Rect oldBounds = mTempRect;
6660 mAccessibilityFocusedVirtualView.getBoundsInScreen(oldBounds);
Alan Viverette34457f52015-03-25 13:09:20 -07006661 mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo(focusedChildId);
Alan Viverette25acc7e2015-05-19 11:32:08 -07006662 if (mAccessibilityFocusedVirtualView == null) {
6663 // Error state: The node no longer exists. Clear focus.
6664 mAccessibilityFocusedHost = null;
6665 focusedHost.clearAccessibilityFocusNoCallbacks();
6666
6667 // This will probably fail, but try to keep the provider's internal
6668 // state consistent by clearing focus.
6669 provider.performAction(focusedChildId,
6670 AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(), null);
Alan Viverettea7ea65e2015-05-15 11:30:21 -07006671 invalidateRectOnScreen(oldBounds);
Alan Viverette25acc7e2015-05-19 11:32:08 -07006672 } else {
6673 // The node was refreshed, invalidate bounds if necessary.
6674 final Rect newBounds = mAccessibilityFocusedVirtualView.getBoundsInScreen();
6675 if (!oldBounds.equals(newBounds)) {
6676 oldBounds.union(newBounds);
6677 invalidateRectOnScreen(oldBounds);
6678 }
Alan Viverettea7ea65e2015-05-15 11:30:21 -07006679 }
Alan Viverette34457f52015-03-25 13:09:20 -07006680 }
6681
Svetoslav Ganov42138042012-03-20 11:51:39 -07006682 @Override
Alan Viverette77e9a282013-09-12 17:16:09 -07006683 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
6684 postSendWindowContentChangedCallback(source, changeType);
Svetoslav Ganov42138042012-03-20 11:51:39 -07006685 }
6686
Fabrice Di Meglio9dd4c5c2013-02-08 18:15:07 -08006687 @Override
6688 public boolean canResolveLayoutDirection() {
6689 return true;
6690 }
6691
6692 @Override
6693 public boolean isLayoutDirectionResolved() {
6694 return true;
6695 }
6696
6697 @Override
6698 public int getLayoutDirection() {
6699 return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT;
6700 }
6701
6702 @Override
6703 public boolean canResolveTextDirection() {
6704 return true;
6705 }
6706
6707 @Override
6708 public boolean isTextDirectionResolved() {
6709 return true;
6710 }
6711
6712 @Override
6713 public int getTextDirection() {
6714 return View.TEXT_DIRECTION_RESOLVED_DEFAULT;
6715 }
6716
6717 @Override
6718 public boolean canResolveTextAlignment() {
6719 return true;
6720 }
6721
6722 @Override
6723 public boolean isTextAlignmentResolved() {
6724 return true;
6725 }
6726
6727 @Override
6728 public int getTextAlignment() {
6729 return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT;
6730 }
6731
Svetoslav Ganov42138042012-03-20 11:51:39 -07006732 private View getCommonPredecessor(View first, View second) {
Chris Craikd36a81f2014-07-17 10:16:51 -07006733 if (mTempHashSet == null) {
6734 mTempHashSet = new HashSet<View>();
Svetoslav Ganov42138042012-03-20 11:51:39 -07006735 }
Chris Craikd36a81f2014-07-17 10:16:51 -07006736 HashSet<View> seen = mTempHashSet;
6737 seen.clear();
6738 View firstCurrent = first;
6739 while (firstCurrent != null) {
6740 seen.add(firstCurrent);
6741 ViewParent firstCurrentParent = firstCurrent.mParent;
6742 if (firstCurrentParent instanceof View) {
6743 firstCurrent = (View) firstCurrentParent;
6744 } else {
6745 firstCurrent = null;
6746 }
6747 }
6748 View secondCurrent = second;
6749 while (secondCurrent != null) {
6750 if (seen.contains(secondCurrent)) {
6751 seen.clear();
6752 return secondCurrent;
6753 }
6754 ViewParent secondCurrentParent = secondCurrent.mParent;
6755 if (secondCurrentParent instanceof View) {
6756 secondCurrent = (View) secondCurrentParent;
6757 } else {
6758 secondCurrent = null;
6759 }
6760 }
6761 seen.clear();
Svetoslav Ganov42138042012-03-20 11:51:39 -07006762 return null;
6763 }
6764
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006765 void checkThread() {
6766 if (mThread != Thread.currentThread()) {
6767 throw new CalledFromWrongThreadException(
6768 "Only the original thread that created a view hierarchy can touch its views.");
6769 }
6770 }
6771
Igor Murashkina86ab6402013-08-30 12:58:36 -07006772 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006773 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Joe Onoratoc6cc0f82011-04-12 11:53:13 -07006774 // ViewAncestor never intercepts touch event, so this can be a no-op
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006775 }
6776
Igor Murashkina86ab6402013-08-30 12:58:36 -07006777 @Override
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07006778 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
Yigit Boyard62d5e92016-01-19 18:56:20 -08006779 if (rectangle == null) {
6780 return scrollToRectOrFocus(null, immediate);
6781 }
6782 rectangle.offset(child.getLeft() - child.getScrollX(),
6783 child.getTop() - child.getScrollY());
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07006784 final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
Yigit Boyard62d5e92016-01-19 18:56:20 -08006785 mTempRect.set(rectangle);
6786 mTempRect.offset(0, -mCurScrollY);
6787 mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
6788 try {
6789 mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect);
6790 } catch (RemoteException re) {
6791 /* ignore */
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07006792 }
6793 return scrolled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006794 }
Romain Guy8506ab42009-06-11 17:35:47 -07006795
Igor Murashkina86ab6402013-08-30 12:58:36 -07006796 @Override
Adam Powell539ee872012-02-03 19:00:49 -08006797 public void childHasTransientStateChanged(View child, boolean hasTransientState) {
6798 // Do nothing.
6799 }
6800
Adam Powell10ba2772014-04-15 09:46:51 -07006801 @Override
6802 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
6803 return false;
6804 }
6805
6806 @Override
6807 public void onStopNestedScroll(View target) {
6808 }
6809
6810 @Override
6811 public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
6812 }
6813
6814 @Override
6815 public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
6816 int dxUnconsumed, int dyUnconsumed) {
6817 }
6818
6819 @Override
6820 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
6821 }
6822
6823 @Override
Adam Powellb36e4f92014-05-01 10:23:33 -07006824 public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
Adam Powell10ba2772014-04-15 09:46:51 -07006825 return false;
6826 }
6827
Adam Powellb72be592014-07-16 21:41:31 -07006828 @Override
6829 public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
6830 return false;
6831 }
6832
Adam Powellb6ab0982015-01-07 17:00:12 -08006833 @Override
6834 public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
6835 return false;
6836 }
6837
Jorim Jaggib774e552015-08-24 14:52:45 -07006838 /**
6839 * Force the window to report its next draw.
6840 * <p>
6841 * This method is only supposed to be used to speed up the interaction from SystemUI and window
6842 * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE
6843 * unless you fully understand this interaction.
6844 * @hide
6845 */
6846 public void setReportNextDraw() {
6847 mReportNextDraw = true;
6848 invalidate();
6849 }
6850
Craig Mautnerbc57cd12013-08-19 15:47:42 -07006851 void changeCanvasOpacity(boolean opaque) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006852 Log.d(mTag, "changeCanvasOpacity: opaque=" + opaque);
John Reck63a06672014-05-07 13:45:54 -07006853 if (mAttachInfo.mHardwareRenderer != null) {
6854 mAttachInfo.mHardwareRenderer.setOpaque(opaque);
6855 }
Craig Mautnerbc57cd12013-08-19 15:47:42 -07006856 }
6857
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006858 class TakenSurfaceHolder extends BaseSurfaceHolder {
6859 @Override
6860 public boolean onAllowLockCanvas() {
6861 return mDrawingAllowed;
6862 }
6863
6864 @Override
6865 public void onRelayoutContainer() {
6866 // Not currently interesting -- from changing between fixed and layout size.
6867 }
6868
Igor Murashkina86ab6402013-08-30 12:58:36 -07006869 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006870 public void setFormat(int format) {
6871 ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
6872 }
6873
Igor Murashkina86ab6402013-08-30 12:58:36 -07006874 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006875 public void setType(int type) {
6876 ((RootViewSurfaceTaker)mView).setSurfaceType(type);
6877 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006878
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006879 @Override
6880 public void onUpdateSurface() {
6881 // We take care of format and type changes on our own.
6882 throw new IllegalStateException("Shouldn't be here");
6883 }
6884
Igor Murashkina86ab6402013-08-30 12:58:36 -07006885 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006886 public boolean isCreating() {
6887 return mIsCreating;
6888 }
6889
6890 @Override
6891 public void setFixedSize(int width, int height) {
6892 throw new UnsupportedOperationException(
6893 "Currently only support sizing from layout");
6894 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006895
6896 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006897 public void setKeepScreenOn(boolean screenOn) {
6898 ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
6899 }
6900 }
Romain Guy8506ab42009-06-11 17:35:47 -07006901
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006902 static class W extends IWindow.Stub {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006903 private final WeakReference<ViewRootImpl> mViewAncestor;
Jeff Brown98365d72012-08-19 20:30:52 -07006904 private final IWindowSession mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006905
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006906 W(ViewRootImpl viewAncestor) {
6907 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
Jeff Brown98365d72012-08-19 20:30:52 -07006908 mWindowSession = viewAncestor.mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006909 }
6910
Igor Murashkina86ab6402013-08-30 12:58:36 -07006911 @Override
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006912 public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Filip Gruszczynski2217f612015-05-26 11:32:08 -07006913 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08006914 Configuration newConfig, Rect backDropFrame, boolean forceLayout,
6915 boolean alwaysConsumeNavBar) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006916 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006917 if (viewAncestor != null) {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006918 viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
Jorim Jaggia4a58ef2016-01-27 02:10:08 -08006919 visibleInsets, stableInsets, outsets, reportDraw, newConfig, backDropFrame,
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08006920 forceLayout, alwaysConsumeNavBar);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006921 }
6922 }
6923
Craig Mautner5702d4d2012-06-30 14:10:16 -07006924 @Override
6925 public void moved(int newX, int newY) {
6926 final ViewRootImpl viewAncestor = mViewAncestor.get();
6927 if (viewAncestor != null) {
6928 viewAncestor.dispatchMoved(newX, newY);
6929 }
6930 }
6931
Igor Murashkina86ab6402013-08-30 12:58:36 -07006932 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006933 public void dispatchAppVisibility(boolean visible) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006934 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006935 if (viewAncestor != null) {
6936 viewAncestor.dispatchAppVisibility(visible);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006937 }
6938 }
6939
Igor Murashkina86ab6402013-08-30 12:58:36 -07006940 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006941 public void dispatchGetNewSurface() {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006942 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006943 if (viewAncestor != null) {
6944 viewAncestor.dispatchGetNewSurface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006945 }
6946 }
6947
Igor Murashkina86ab6402013-08-30 12:58:36 -07006948 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006949 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006950 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006951 if (viewAncestor != null) {
6952 viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006953 }
6954 }
6955
6956 private static int checkCallingPermission(String permission) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006957 try {
6958 return ActivityManagerNative.getDefault().checkPermission(
6959 permission, Binder.getCallingPid(), Binder.getCallingUid());
6960 } catch (RemoteException e) {
6961 return PackageManager.PERMISSION_DENIED;
6962 }
6963 }
6964
Igor Murashkina86ab6402013-08-30 12:58:36 -07006965 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006966 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006967 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006968 if (viewAncestor != null) {
6969 final View view = viewAncestor.mView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006970 if (view != null) {
6971 if (checkCallingPermission(Manifest.permission.DUMP) !=
6972 PackageManager.PERMISSION_GRANTED) {
6973 throw new SecurityException("Insufficient permissions to invoke"
6974 + " executeCommand() from pid=" + Binder.getCallingPid()
6975 + ", uid=" + Binder.getCallingUid());
6976 }
6977
6978 OutputStream clientStream = null;
6979 try {
6980 clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
6981 ViewDebug.dispatchCommand(view, command, parameters, clientStream);
6982 } catch (IOException e) {
6983 e.printStackTrace();
6984 } finally {
6985 if (clientStream != null) {
6986 try {
6987 clientStream.close();
6988 } catch (IOException e) {
6989 e.printStackTrace();
6990 }
6991 }
6992 }
6993 }
6994 }
6995 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006996
6997 @Override
Dianne Hackbornffa42482009-09-23 22:20:11 -07006998 public void closeSystemDialogs(String reason) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006999 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007000 if (viewAncestor != null) {
7001 viewAncestor.dispatchCloseSystemDialogs(reason);
Dianne Hackbornffa42482009-09-23 22:20:11 -07007002 }
7003 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07007004
7005 @Override
Marco Nelissenbf6956b2009-11-09 15:21:13 -08007006 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
7007 boolean sync) {
Dianne Hackborn19382ac2009-09-11 21:13:37 -07007008 if (sync) {
7009 try {
Jeff Brown98365d72012-08-19 20:30:52 -07007010 mWindowSession.wallpaperOffsetsComplete(asBinder());
Dianne Hackborn19382ac2009-09-11 21:13:37 -07007011 } catch (RemoteException e) {
7012 }
7013 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07007014 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007015
Igor Murashkina86ab6402013-08-30 12:58:36 -07007016 @Override
Dianne Hackborn75804932009-10-20 20:15:20 -07007017 public void dispatchWallpaperCommand(String action, int x, int y,
7018 int z, Bundle extras, boolean sync) {
7019 if (sync) {
7020 try {
Jeff Brown98365d72012-08-19 20:30:52 -07007021 mWindowSession.wallpaperCommandComplete(asBinder(), null);
Dianne Hackborn75804932009-10-20 20:15:20 -07007022 } catch (RemoteException e) {
7023 }
7024 }
7025 }
Christopher Tatea53146c2010-09-07 11:57:52 -07007026
7027 /* Drag/drop */
Igor Murashkina86ab6402013-08-30 12:58:36 -07007028 @Override
Christopher Tatea53146c2010-09-07 11:57:52 -07007029 public void dispatchDragEvent(DragEvent event) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007030 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007031 if (viewAncestor != null) {
7032 viewAncestor.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07007033 }
7034 }
Joe Onorato664644d2011-01-23 17:53:23 -08007035
Igor Murashkina86ab6402013-08-30 12:58:36 -07007036 @Override
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08007037 public void updatePointerIcon(float x, float y) {
7038 final ViewRootImpl viewAncestor = mViewAncestor.get();
7039 if (viewAncestor != null) {
7040 viewAncestor.updatePointerIcon(x, y);
7041 }
7042 }
7043
7044 @Override
Dianne Hackborn9a230e02011-10-06 11:51:27 -07007045 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
7046 int localValue, int localChanges) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007047 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007048 if (viewAncestor != null) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07007049 viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility,
7050 localValue, localChanges);
Joe Onorato664644d2011-01-23 17:53:23 -08007051 }
7052 }
Dianne Hackborn12d3a942012-04-27 14:16:30 -07007053
Igor Murashkina86ab6402013-08-30 12:58:36 -07007054 @Override
Craig Mautner9c795042014-10-28 19:59:59 -07007055 public void dispatchWindowShown() {
7056 final ViewRootImpl viewAncestor = mViewAncestor.get();
7057 if (viewAncestor != null) {
7058 viewAncestor.dispatchWindowShown();
7059 }
7060 }
Clara Bayarri75e09792015-07-29 16:20:40 +01007061
7062 @Override
7063 public void requestAppKeyboardShortcuts(IResultReceiver receiver) {
7064 ViewRootImpl viewAncestor = mViewAncestor.get();
7065 if (viewAncestor != null) {
7066 viewAncestor.dispatchRequestKeyboardShortcuts(receiver);
7067 }
7068 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007069 }
7070
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007071 public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
7072 public CalledFromWrongThreadException(String msg) {
7073 super(msg);
7074 }
7075 }
7076
Alan Viverettebea0c7da2015-09-01 16:00:20 -04007077 static HandlerActionQueue getRunQueue() {
7078 HandlerActionQueue rq = sRunQueues.get();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007079 if (rq != null) {
7080 return rq;
7081 }
Alan Viverettebea0c7da2015-09-01 16:00:20 -04007082 rq = new HandlerActionQueue();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007083 sRunQueues.set(rq);
7084 return rq;
7085 }
Romain Guy8506ab42009-06-11 17:35:47 -07007086
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007087 /**
Skuhneb8160872015-09-22 09:51:39 -07007088 * Start a drag resizing which will inform all listeners that a window resize is taking place.
7089 */
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08007090 private void startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets,
7091 Rect stableInsets) {
Skuhneb8160872015-09-22 09:51:39 -07007092 if (!mDragResizing) {
7093 mDragResizing = true;
Chong Zhangdcee1de2015-10-06 10:26:00 -07007094 synchronized (mWindowCallbacks) {
7095 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08007096 mWindowCallbacks.get(i).onWindowDragResizeStart(initialBounds, fullscreen,
7097 systemInsets, stableInsets);
Skuhneb8160872015-09-22 09:51:39 -07007098 }
7099 }
7100 mFullRedrawNeeded = true;
7101 }
7102 }
7103
7104 /**
7105 * End a drag resize which will inform all listeners that a window resize has ended.
7106 */
7107 private void endDragResizing() {
7108 if (mDragResizing) {
7109 mDragResizing = false;
Chong Zhangdcee1de2015-10-06 10:26:00 -07007110 synchronized (mWindowCallbacks) {
7111 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
7112 mWindowCallbacks.get(i).onWindowDragResizeEnd();
Skuhneb8160872015-09-22 09:51:39 -07007113 }
7114 }
7115 mFullRedrawNeeded = true;
7116 }
7117 }
7118
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07007119 private boolean updateContentDrawBounds() {
7120 boolean updated = false;
7121 synchronized (mWindowCallbacks) {
7122 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
7123 updated |= mWindowCallbacks.get(i).onContentDrawn(
7124 mWindowAttributes.surfaceInsets.left,
7125 mWindowAttributes.surfaceInsets.top,
7126 mWidth, mHeight);
7127 }
7128 }
7129 return updated | (mDragResizing && mReportNextDraw);
7130 }
7131
7132 private void requestDrawWindow() {
7133 if (mReportNextDraw) {
7134 mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size());
7135 }
7136 synchronized (mWindowCallbacks) {
7137 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
7138 mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw);
7139 }
7140 }
7141 }
7142
Skuhneb8160872015-09-22 09:51:39 -07007143 /**
Jorim Jaggi4846ee32016-01-07 17:39:12 +01007144 * Tells this instance that its corresponding activity has just relaunched. In this case, we
7145 * need to force a relayout of the window to make sure we get the correct bounds from window
7146 * manager.
7147 */
7148 public void reportActivityRelaunched() {
7149 mActivityRelaunched = true;
7150 }
7151
7152 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007153 * Class for managing the accessibility interaction connection
7154 * based on the global accessibility state.
7155 */
7156 final class AccessibilityInteractionConnectionManager
7157 implements AccessibilityStateChangeListener {
Igor Murashkina86ab6402013-08-30 12:58:36 -07007158 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007159 public void onAccessibilityStateChanged(boolean enabled) {
7160 if (enabled) {
7161 ensureConnection();
Chris Craikcce47eb2014-07-16 15:12:15 -07007162 if (mAttachInfo.mHasWindowFocus) {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08007163 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
7164 View focusedView = mView.findFocus();
7165 if (focusedView != null && focusedView != mView) {
7166 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
7167 }
7168 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007169 } else {
7170 ensureNoConnection();
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07007171 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007172 }
7173 }
7174
7175 public void ensureConnection() {
Chris Craikcce47eb2014-07-16 15:12:15 -07007176 final boolean registered =
Svetoslav8e3feb12014-02-24 13:46:47 -08007177 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
Chris Craikcce47eb2014-07-16 15:12:15 -07007178 if (!registered) {
7179 mAttachInfo.mAccessibilityWindowId =
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08007180 mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
7181 new AccessibilityInteractionConnection(ViewRootImpl.this));
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007182 }
7183 }
7184
7185 public void ensureNoConnection() {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08007186 final boolean registered =
Svetoslav8e3feb12014-02-24 13:46:47 -08007187 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007188 if (registered) {
Svetoslav8e3feb12014-02-24 13:46:47 -08007189 mAttachInfo.mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007190 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
7191 }
7192 }
7193 }
7194
Chris Craikcce47eb2014-07-16 15:12:15 -07007195 final class HighContrastTextManager implements HighTextContrastChangeListener {
7196 HighContrastTextManager() {
7197 mAttachInfo.mHighContrastText = mAccessibilityManager.isHighTextContrastEnabled();
7198 }
7199 @Override
7200 public void onHighTextContrastStateChanged(boolean enabled) {
7201 mAttachInfo.mHighContrastText = enabled;
7202
7203 // Destroy Displaylists so they can be recreated with high contrast recordings
7204 destroyHardwareResources();
Chris Craikd36a81f2014-07-17 10:16:51 -07007205
7206 // Schedule redraw, which will rerecord + redraw all text
7207 invalidate();
Chris Craikcce47eb2014-07-16 15:12:15 -07007208 }
7209 }
7210
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007211 /**
7212 * This class is an interface this ViewAncestor provides to the
7213 * AccessibilityManagerService to the latter can interact with
7214 * the view hierarchy in this ViewAncestor.
7215 */
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07007216 static final class AccessibilityInteractionConnection
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007217 extends IAccessibilityInteractionConnection.Stub {
Svetoslav Ganov02107852011-10-03 17:06:56 -07007218 private final WeakReference<ViewRootImpl> mViewRootImpl;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007219
Svetoslav Ganovf79f4762011-10-28 15:40:32 -07007220 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) {
7221 mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007222 }
7223
Svetoslav Ganov42138042012-03-20 11:51:39 -07007224 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07007225 public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07007226 Region interactiveRegion, int interactionId,
7227 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07007228 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07007229 ViewRootImpl viewRootImpl = mViewRootImpl.get();
7230 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07007231 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov02107852011-10-03 17:06:56 -07007232 .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07007233 interactiveRegion, interactionId, callback, flags, interrogatingPid,
7234 interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007235 } else {
7236 // We cannot make the call and notify the caller so it does not wait.
7237 try {
7238 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
7239 } catch (RemoteException re) {
7240 /* best effort - ignore */
7241 }
Svetoslav Ganov601ad802011-06-09 14:47:38 -07007242 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007243 }
7244
Svetoslav Ganov42138042012-03-20 11:51:39 -07007245 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07007246 public void performAccessibilityAction(long accessibilityNodeId, int action,
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07007247 Bundle arguments, int interactionId,
7248 IAccessibilityInteractionConnectionCallback callback, int flags,
Svet Ganov7498efd2014-09-03 21:33:00 -07007249 int interrogatingPid, long interrogatingTid) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07007250 ViewRootImpl viewRootImpl = mViewRootImpl.get();
7251 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07007252 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07007253 .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
Svet Ganov7498efd2014-09-03 21:33:00 -07007254 interactionId, callback, flags, interrogatingPid, interrogatingTid);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007255 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007256 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007257 try {
7258 callback.setPerformAccessibilityActionResult(false, interactionId);
7259 } catch (RemoteException re) {
7260 /* best effort - ignore */
7261 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007262 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007263 }
7264
Svetoslav Ganov42138042012-03-20 11:51:39 -07007265 @Override
Svetoslav Ganov80943d82013-01-02 10:25:37 -08007266 public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07007267 String viewId, Region interactiveRegion, int interactionId,
Svetoslav Ganov80943d82013-01-02 10:25:37 -08007268 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07007269 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07007270 ViewRootImpl viewRootImpl = mViewRootImpl.get();
7271 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07007272 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov80943d82013-01-02 10:25:37 -08007273 .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07007274 viewId, interactiveRegion, interactionId, callback, flags,
7275 interrogatingPid, interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007276 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007277 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007278 try {
7279 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
7280 } catch (RemoteException re) {
7281 /* best effort - ignore */
7282 }
7283 }
7284 }
7285
Svetoslav Ganov42138042012-03-20 11:51:39 -07007286 @Override
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007287 public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
Svetoslav9ae9ed22014-09-02 16:36:35 -07007288 Region interactiveRegion, int interactionId,
7289 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07007290 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007291 ViewRootImpl viewRootImpl = mViewRootImpl.get();
7292 if (viewRootImpl != null && viewRootImpl.mView != null) {
7293 viewRootImpl.getAccessibilityInteractionController()
7294 .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
Svetoslav9ae9ed22014-09-02 16:36:35 -07007295 interactiveRegion, interactionId, callback, flags, interrogatingPid,
7296 interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007297 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007298 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007299 try {
7300 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
7301 } catch (RemoteException re) {
7302 /* best effort - ignore */
7303 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007304 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007305 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007306
Svetoslav Ganov42138042012-03-20 11:51:39 -07007307 @Override
Svetoslav9ae9ed22014-09-02 16:36:35 -07007308 public void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion,
7309 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07007310 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007311 ViewRootImpl viewRootImpl = mViewRootImpl.get();
7312 if (viewRootImpl != null && viewRootImpl.mView != null) {
7313 viewRootImpl.getAccessibilityInteractionController()
Svetoslav9ae9ed22014-09-02 16:36:35 -07007314 .findFocusClientThread(accessibilityNodeId, focusType, interactiveRegion,
7315 interactionId, callback, flags, interrogatingPid, interrogatingTid,
7316 spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07007317 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007318 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007319 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007320 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007321 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007322 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007323 }
7324 }
7325 }
7326
Svetoslav Ganov42138042012-03-20 11:51:39 -07007327 @Override
Svetoslav9ae9ed22014-09-02 16:36:35 -07007328 public void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion,
7329 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07007330 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007331 ViewRootImpl viewRootImpl = mViewRootImpl.get();
7332 if (viewRootImpl != null && viewRootImpl.mView != null) {
7333 viewRootImpl.getAccessibilityInteractionController()
Svetoslav9ae9ed22014-09-02 16:36:35 -07007334 .focusSearchClientThread(accessibilityNodeId, direction, interactiveRegion,
7335 interactionId, callback, flags, interrogatingPid, interrogatingTid,
7336 spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07007337 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007338 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007339 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007340 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007341 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007342 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007343 }
7344 }
7345 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007346 }
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07007347
Svetoslav Ganova0156172011-06-26 17:55:44 -07007348 private class SendWindowContentChangedAccessibilityEvent implements Runnable {
Alan Viverette77e9a282013-09-12 17:16:09 -07007349 private int mChangeTypes = 0;
7350
Svetoslav Ganov42138042012-03-20 11:51:39 -07007351 public View mSource;
Svetoslav6254f482013-06-04 17:22:14 -07007352 public long mLastEventTimeMillis;
Svetoslav Ganova0156172011-06-26 17:55:44 -07007353
Igor Murashkina86ab6402013-08-30 12:58:36 -07007354 @Override
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07007355 public void run() {
Svetoslav8d820ecf2013-07-15 17:12:41 -07007356 // The accessibility may be turned off while we were waiting so check again.
7357 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
7358 mLastEventTimeMillis = SystemClock.uptimeMillis();
7359 AccessibilityEvent event = AccessibilityEvent.obtain();
7360 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
Alan Viverette77e9a282013-09-12 17:16:09 -07007361 event.setContentChangeTypes(mChangeTypes);
Svetoslav8d820ecf2013-07-15 17:12:41 -07007362 mSource.sendAccessibilityEventUnchecked(event);
7363 } else {
7364 mLastEventTimeMillis = 0;
7365 }
7366 // In any case reset to initial state.
Svetoslav6254f482013-06-04 17:22:14 -07007367 mSource.resetSubtreeAccessibilityStateChanged();
7368 mSource = null;
Alan Viverette77e9a282013-09-12 17:16:09 -07007369 mChangeTypes = 0;
Svetoslav6254f482013-06-04 17:22:14 -07007370 }
7371
Alan Viverette77e9a282013-09-12 17:16:09 -07007372 public void runOrPost(View source, int changeType) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007373 if (mSource != null) {
Svetoslav9dafebb2013-06-18 16:29:25 -07007374 // If there is no common predecessor, then mSource points to
7375 // a removed view, hence in this case always prefer the source.
7376 View predecessor = getCommonPredecessor(mSource, source);
7377 mSource = (predecessor != null) ? predecessor : source;
Alan Viverette77e9a282013-09-12 17:16:09 -07007378 mChangeTypes |= changeType;
Svetoslav6254f482013-06-04 17:22:14 -07007379 return;
7380 }
7381 mSource = source;
Alan Viverette77e9a282013-09-12 17:16:09 -07007382 mChangeTypes = changeType;
Svetoslav6254f482013-06-04 17:22:14 -07007383 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
7384 final long minEventIntevalMillis =
7385 ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
7386 if (timeSinceLastMillis >= minEventIntevalMillis) {
Svetoslav9dafebb2013-06-18 16:29:25 -07007387 mSource.removeCallbacks(this);
Svetoslav6254f482013-06-04 17:22:14 -07007388 run();
7389 } else {
7390 mSource.postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007391 }
7392 }
7393 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007394}