blob: 239185e5c25d6a3e09d4293c2051b676cee75f7f [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
Andrii Kulian44607962017-03-16 11:06:24 -070019import static android.view.Display.INVALID_DISPLAY;
Chris Craik9de95db2017-01-18 17:59:23 -080020import static android.view.View.PFLAG_DRAW_ANIMATION;
Jorim Jaggic39c7b02016-03-24 10:47:07 -070021import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
22import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
Adrian Roosfa02da62018-01-15 16:01:18 +010023import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -080024import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
Chong Zhangf6525ce2016-01-14 17:09:56 -080025import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
26import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
27import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -080028
Romain Guy6b7bd242010-10-06 19:49:23 -070029import android.Manifest;
Chet Haasecca2c982011-05-20 14:34:18 -070030import android.animation.LayoutTransition;
Adam Lesinski4ece3d62016-06-16 18:05:41 -070031import android.annotation.NonNull;
Dake Gud9dbd272018-03-13 11:38:42 -070032import android.annotation.Nullable;
Sudheer Shankadc589ac2016-11-10 15:30:17 -080033import android.app.ActivityManager;
Andrii Kulian44607962017-03-16 11:06:24 -070034import android.app.ActivityThread;
Adam Lesinski4ece3d62016-06-16 18:05:41 -070035import android.app.ResourcesManager;
Vadim Trysheva61efa42016-09-28 15:15:52 -070036import android.content.ClipData;
Romain Guy6b7bd242010-10-06 19:49:23 -070037import android.content.ClipDescription;
Romain Guy6b7bd242010-10-06 19:49:23 -070038import android.content.Context;
Romain Guy26a2b972017-04-17 09:39:51 -070039import android.content.pm.ActivityInfo;
Romain Guy6b7bd242010-10-06 19:49:23 -070040import android.content.pm.PackageManager;
41import android.content.res.CompatibilityInfo;
42import android.content.res.Configuration;
43import android.content.res.Resources;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.graphics.Canvas;
John Reck3e04f092017-06-02 15:50:09 -070045import android.graphics.Color;
Alan Viverettefed3f722013-11-14 14:48:20 -080046import android.graphics.Matrix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.graphics.PixelFormat;
Christopher Tate2c095f32010-10-04 14:13:40 -070048import android.graphics.Point;
Christopher Tatea53146c2010-09-07 11:57:52 -070049import android.graphics.PointF;
Romain Guy6b7bd242010-10-06 19:49:23 -070050import android.graphics.PorterDuff;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.graphics.Rect;
52import android.graphics.Region;
Doris Liu718cd3e2016-05-17 16:50:31 -070053import android.graphics.drawable.AnimatedVectorDrawable;
Svetoslav Ganov42138042012-03-20 11:51:39 -070054import android.graphics.drawable.Drawable;
Jeff Brownd912e1f2014-04-11 18:46:22 -070055import android.hardware.display.DisplayManager;
56import android.hardware.display.DisplayManager.DisplayListener;
Jun Mukai347e5d42015-12-03 01:13:31 -080057import android.hardware.input.InputManager;
Romain Guy6b7bd242010-10-06 19:49:23 -070058import android.media.AudioManager;
59import android.os.Binder;
Michael Wright5bd69e62015-05-14 14:48:08 +010060import android.os.Build;
Romain Guy6b7bd242010-10-06 19:49:23 -070061import android.os.Bundle;
62import android.os.Debug;
63import android.os.Handler;
Romain Guy6b7bd242010-10-06 19:49:23 -070064import android.os.Looper;
65import android.os.Message;
66import android.os.ParcelFileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import android.os.Process;
Romain Guy6b7bd242010-10-06 19:49:23 -070068import android.os.RemoteException;
Romain Guy6b7bd242010-10-06 19:49:23 -070069import android.os.SystemClock;
Romain Guy59a12ca2011-06-09 17:48:21 -070070import android.os.SystemProperties;
Jeff Brown481c1572012-03-09 14:41:15 -080071import android.os.Trace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.util.AndroidRuntimeException;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070073import android.util.DisplayMetrics;
Romain Guy6b7bd242010-10-06 19:49:23 -070074import android.util.Log;
Svetoslav Ganov24c90452017-12-27 15:17:14 -080075import android.util.LongArray;
Andrii Kulian44607962017-03-16 11:06:24 -070076import android.util.MergedConfiguration;
Chet Haase949dbf72010-08-11 18:41:06 -070077import android.util.Slog;
Siarhei Vishniakou461faf92017-06-26 11:24:25 -070078import android.util.SparseArray;
Evan Rosky5e29c072017-06-02 17:31:22 -070079import android.util.SparseBooleanArray;
John Reckba6adf62015-02-19 14:36:50 -080080import android.util.TimeUtils;
Dianne Hackborn711e62a2010-11-29 16:38:22 -080081import android.util.TypedValue;
John Reck44fd8d22014-02-26 11:00:11 -080082import android.view.Surface.OutOfResourcesException;
Jeff Browna175a5b2012-02-15 19:18:31 -080083import android.view.View.AttachInfo;
Evan Rosky57223312017-02-08 14:42:45 -080084import android.view.View.FocusDirection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.view.View.MeasureSpec;
Yohei Yukawa22dac1c2017-02-12 16:54:16 -080086import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
svetoslavganov75986cf2009-05-14 22:28:01 -070087import android.view.accessibility.AccessibilityEvent;
88import android.view.accessibility.AccessibilityManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070089import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
Chris Craikcce47eb2014-07-16 15:12:15 -070090import android.view.accessibility.AccessibilityManager.HighTextContrastChangeListener;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070091import android.view.accessibility.AccessibilityNodeInfo;
Alan Viverette25acc7e2015-05-19 11:32:08 -070092import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
Svetoslav Ganov02107852011-10-03 17:06:56 -070093import android.view.accessibility.AccessibilityNodeProvider;
Phil Weaverf00cd142017-03-03 13:44:00 -080094import android.view.accessibility.AccessibilityWindowInfo;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070095import android.view.accessibility.IAccessibilityInteractionConnection;
96import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
Dianne Hackborn0f761d62010-11-30 22:06:10 -080097import android.view.animation.AccelerateDecelerateInterpolator;
98import android.view.animation.Interpolator;
Dake Gub0fa3782018-02-26 12:25:14 -080099import android.view.autofill.AutofillManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100import android.view.inputmethod.InputMethodManager;
101import android.widget.Scroller;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700102
Svetoslav Ganov42138042012-03-20 11:51:39 -0700103import com.android.internal.R;
Jorim Jaggi16b63192016-03-25 18:32:19 -0700104import com.android.internal.annotations.GuardedBy;
Clara Bayarri75e09792015-07-29 16:20:40 +0100105import com.android.internal.os.IResultReceiver;
Svetoslav Ganov758143e2012-08-06 16:40:27 -0700106import com.android.internal.os.SomeArgs;
Adam Powell6711f3b2015-05-06 15:57:09 -0700107import com.android.internal.policy.PhoneFallbackEventHandler;
Phil Weaver63e45032017-05-11 10:54:37 -0700108import com.android.internal.util.Preconditions;
Romain Guy6b7bd242010-10-06 19:49:23 -0700109import com.android.internal.view.BaseSurfaceHolder;
Romain Guy6b7bd242010-10-06 19:49:23 -0700110import com.android.internal.view.RootViewSurfaceTaker;
Robert Carr25cfa132016-11-16 13:24:09 -0800111import com.android.internal.view.SurfaceCallbackHelper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112
Jeff Brown5182c782013-10-15 20:31:52 -0700113import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114import java.io.IOException;
115import java.io.OutputStream;
Jeff Brown5182c782013-10-15 20:31:52 -0700116import java.io.PrintWriter;
Romain Guy6b7bd242010-10-06 19:49:23 -0700117import java.lang.ref.WeakReference;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118import java.util.ArrayList;
Eugene Susla72c510f2018-01-23 21:12:11 +0000119import java.util.HashSet;
Svetoslav Ganov24c90452017-12-27 15:17:14 -0800120import java.util.LinkedList;
121import java.util.Queue;
Jorim Jaggic39c7b02016-03-24 10:47:07 -0700122import java.util.concurrent.CountDownLatch;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124/**
125 * The top of a view hierarchy, implementing the needed protocol between View
126 * and the WindowManager. This is for the most part an internal implementation
Jeff Brown98365d72012-08-19 20:30:52 -0700127 * detail of {@link WindowManagerGlobal}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 *
129 * {@hide}
130 */
Romain Guy812ccbe2010-06-01 14:07:24 -0700131@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
Jeff Browna175a5b2012-02-15 19:18:31 -0800132public final class ViewRootImpl implements ViewParent,
Stan Iliev45faba52016-06-28 13:33:15 -0400133 View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
Dianne Hackborn70a3f672011-08-08 14:32:41 -0700134 private static final String TAG = "ViewRootImpl";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 private static final boolean DBG = false;
Romain Guy812ccbe2010-06-01 14:07:24 -0700136 private static final boolean LOCAL_LOGV = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 /** @noinspection PointlessBooleanExpression*/
138 private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
139 private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800140 private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
142 private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
143 private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
144 private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700145 private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
Chet Haase2f2022a2011-10-11 06:41:59 -0700146 private static final boolean DEBUG_FPS = false;
Michael Wright06a79252014-05-05 17:45:29 -0700147 private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV;
Chong Zhang44aabe42016-05-10 11:20:14 -0700148 private static final boolean DEBUG_KEEP_SCREEN_ON = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149
Romain Guy59a12ca2011-06-09 17:48:21 -0700150 /**
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +0900151 * Set to false if we do not want to use the multi threaded renderer even though
152 * threaded renderer (aka hardware renderering) is used. Note that by disabling
Skuhneb8160872015-09-22 09:51:39 -0700153 * this, WindowCallbacks will not fire.
154 */
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +0900155 private static final boolean MT_RENDERER_AVAILABLE = true;
Skuhneb8160872015-09-22 09:51:39 -0700156
157 /**
Romain Guy59a12ca2011-06-09 17:48:21 -0700158 * Set this system property to true to force the view hierarchy to render
159 * at 60 Hz. This can be used to measure the potential framerate.
160 */
Romain Guye9bc11f2013-05-23 12:47:26 -0700161 private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering";
Michael Chan53071d62009-05-13 17:29:48 -0700162
Griff Hazena0938022015-03-13 10:01:41 -0700163 // properties used by emulator to determine display shape
Griff Hazena0938022015-03-13 10:01:41 -0700164 public static final String PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX =
165 "ro.emu.win_outset_bottom_px";
Michael Kolb437d3132014-06-20 13:28:44 -0700166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 /**
168 * Maximum time we allow the user to roll the trackball enough to generate
169 * a key event, before resetting the counters.
170 */
171 static final int MAX_TRACKBALL_DELAY = 250;
172
Alan Viverettebea0c7da2015-09-01 16:00:20 -0400173 static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174
Skuhneb8160872015-09-22 09:51:39 -0700175 static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList();
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800176 static boolean sFirstDrawComplete = false;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700177
Andrii Kulian44607962017-03-16 11:06:24 -0700178 /**
179 * Callback for notifying about global configuration changes.
180 */
181 public interface ConfigChangedCallback {
182
183 /** Notifies about global config change. */
184 void onConfigurationChanged(Configuration globalConfig);
185 }
186
187 private static final ArrayList<ConfigChangedCallback> sConfigCallbacks = new ArrayList<>();
188
189 /**
190 * Callback for notifying activities about override configuration changes.
191 */
192 public interface ActivityConfigCallback {
193
194 /**
195 * Notifies about override config change and/or move to different display.
196 * @param overrideConfig New override config to apply to activity.
197 * @param newDisplayId New display id, {@link Display#INVALID_DISPLAY} if not changed.
198 */
199 void onConfigurationChanged(Configuration overrideConfig, int newDisplayId);
200 }
201
202 /**
203 * Callback used to notify corresponding activity about override configuration change and make
204 * sure that all resources are set correctly before updating the ViewRootImpl's internal state.
205 */
206 private ActivityConfigCallback mActivityConfigCallback;
207
208 /**
209 * Used when configuration change first updates the config of corresponding activity.
210 * In that case we receive a call back from {@link ActivityThread} and this flag is used to
211 * preserve the initial value.
212 *
213 * @see #performConfigurationChange(Configuration, Configuration, boolean, int)
214 */
215 private boolean mForceNextConfigUpdate;
Romain Guy59a12ca2011-06-09 17:48:21 -0700216
Jorim Jaggi16b63192016-03-25 18:32:19 -0700217 /**
Evan Rosky37df2db2017-01-24 16:35:52 -0800218 * Signals that compatibility booleans have been initialized according to
219 * target SDK versions.
220 */
221 private static boolean sCompatibilityDone = false;
222
223 /**
224 * Always assign focus if a focusable View is available.
225 */
Evan Roskyc5420ea2017-07-13 15:24:16 -0700226 private static boolean sAlwaysAssignFocus;
Evan Rosky37df2db2017-01-24 16:35:52 -0800227
228 /**
Jorim Jaggi16b63192016-03-25 18:32:19 -0700229 * This list must only be modified by the main thread, so a lock is only needed when changing
230 * the list or when accessing the list from a non-main thread.
231 */
232 @GuardedBy("mWindowCallbacks")
233 final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList<>();
Jeff Brownf9e989d2013-04-04 23:04:03 -0700234 final Context mContext;
Jeff Brown98365d72012-08-19 20:30:52 -0700235 final IWindowSession mWindowSession;
Adam Lesinski4ece3d62016-06-16 18:05:41 -0700236 @NonNull Display mDisplay;
Jeff Brownd912e1f2014-04-11 18:46:22 -0700237 final DisplayManager mDisplayManager;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800238 final String mBasePackageName;
Jeff Brown98365d72012-08-19 20:30:52 -0700239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 final int[] mTmpLocation = new int[2];
Romain Guy8506ab42009-06-11 17:35:47 -0700241
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800242 final TypedValue mTmpValue = new TypedValue();
Jeff Brownf9e989d2013-04-04 23:04:03 -0700243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 final Thread mThread;
245
246 final WindowLeaked mLocation;
247
Mihai Popa0450a162018-04-27 13:09:12 +0100248 public final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249
250 final W mWindow;
251
Dianne Hackborn180c4842011-09-13 12:39:25 -0700252 final int mTargetSdkVersion;
253
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700254 int mSeq;
255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256 View mView;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700257
258 View mAccessibilityFocusedHost;
259 AccessibilityNodeInfo mAccessibilityFocusedVirtualView;
260
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -0800261 // True if the window currently has pointer capture enabled.
262 boolean mPointerCapture;
Jun Mukai347e5d42015-12-03 01:13:31 -0800263
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 int mViewVisibility;
265 boolean mAppVisible = true;
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800266 // For recents to freeform transition we need to keep drawing after the app receives information
267 // that it became invisible. This will ignore that information and depend on the decor view
268 // visibility to control drawing. The decor view visibility will get adjusted when the app get
269 // stopped and that's when the app will stop drawing further frames.
270 private boolean mForceDecorViewVisibility = false;
Andrii Kulian74b561a2017-08-11 09:06:46 -0700271 // Used for tracking app visibility updates separately in case we get double change. This will
272 // make sure that we always call relayout for the corresponding window.
273 private boolean mAppVisibilityChanged;
Dianne Hackborn180c4842011-09-13 12:39:25 -0700274 int mOrigWindowType = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275
Alan Viverette64bf97a2015-09-18 16:42:00 -0400276 /** Whether the window had focus during the most recent traversal. */
277 boolean mHadWindowFocus;
278
279 /**
280 * Whether the window lost focus during a previous traversal and has not
281 * yet gained it back. Used to determine whether a WINDOW_STATE_CHANGE
282 * accessibility events should be sent during traversal.
283 */
284 boolean mLostWindowFocus;
285
Dianne Hackbornce418e62011-03-01 14:31:38 -0800286 // Set to true if the owner of this window is in the stopped state,
287 // so the window should no longer be active.
288 boolean mStopped = false;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700289
Daniel Koulomzin087ae472015-12-16 17:52:25 -0500290 // Set to true if the owner of this window is in ambient mode,
291 // which means it won't receive input events.
292 boolean mIsAmbientMode = false;
293
George Mount41725de2015-04-09 08:23:05 -0700294 // Set to true to stop input during an Activity Transition.
295 boolean mPausedForTransition = false;
296
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700297 boolean mLastInCompatMode = false;
298
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700299 SurfaceHolder.Callback2 mSurfaceHolderCallback;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700300 BaseSurfaceHolder mSurfaceHolder;
301 boolean mIsCreating;
302 boolean mDrawingAllowed;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700303
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 final Region mTransparentRegion;
305 final Region mPreviousTransparentRegion;
306
307 int mWidth;
308 int mHeight;
Romain Guy7d7b5492011-01-24 16:33:45 -0800309 Rect mDirty;
Chris Craik3f06c6d2017-01-09 18:19:48 +0000310 public boolean mIsAnimating;
Romain Guy8506ab42009-06-11 17:35:47 -0700311
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +0900312 private boolean mUseMTRenderer;
Chong Zhang0275e392015-09-17 10:41:44 -0700313 private boolean mDragResizing;
Jorim Jaggic39c7b02016-03-24 10:47:07 -0700314 private boolean mInvalidateRootRequested;
Jorim Jaggi4846ee32016-01-07 17:39:12 +0100315 private int mResizeMode;
Chong Zhang0275e392015-09-17 10:41:44 -0700316 private int mCanvasOffsetX;
317 private int mCanvasOffsetY;
Jorim Jaggi4846ee32016-01-07 17:39:12 +0100318 private boolean mActivityRelaunched;
Chong Zhang0275e392015-09-17 10:41:44 -0700319
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700320 CompatibilityInfo.Translator mTranslator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321
322 final View.AttachInfo mAttachInfo;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700323 InputChannel mInputChannel;
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -0700324 InputQueue.Callback mInputQueueCallback;
325 InputQueue mInputQueue;
Joe Onorato86f67862010-11-05 18:57:34 -0700326 FallbackEventHandler mFallbackEventHandler;
Jeff Brown96e942d2011-11-30 19:55:01 -0800327 Choreographer mChoreographer;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 final Rect mTempRect; // used in the transaction to not thrash the heap.
330 final Rect mVisRect; // used to retrieve visible rect of focused view.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800332 // This is used to reduce the race between window focus changes being dispatched from
333 // the window manager and input events coming through the input system.
334 @GuardedBy("this")
Dianne Hackborn011944c2017-12-15 15:44:55 -0800335 boolean mWindowFocusChanged;
336 @GuardedBy("this")
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800337 boolean mUpcomingWindowFocus;
338 @GuardedBy("this")
339 boolean mUpcomingInTouchMode;
340
Chris Craik3f06c6d2017-01-09 18:19:48 +0000341 public boolean mTraversalScheduled;
Jeff Browne0dbd002012-02-15 19:34:58 -0800342 int mTraversalBarrier;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343 boolean mWillDrawSoon;
Craig Mautnerdf2390a2012-08-29 20:59:22 -0700344 /** Set to true while in performTraversals for detecting when die(true) is called from internal
345 * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */
346 boolean mIsInTraversal;
Adrian Roosfa104232014-06-20 16:10:14 -0700347 boolean mApplyInsetsRequested;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 boolean mLayoutRequested;
349 boolean mFirst;
350 boolean mReportNextDraw;
351 boolean mFullRedrawNeeded;
352 boolean mNewSurfaceNeeded;
353 boolean mHasHadWindowFocus;
354 boolean mLastWasImTarget;
Jorim Jaggia4a58ef2016-01-27 02:10:08 -0800355 boolean mForceNextWindowRelayout;
Chong Zhang8dbd9ad2015-10-09 10:06:11 -0700356 CountDownLatch mWindowDrawCountDown;
Jorim Jaggi827e0fa2015-05-07 11:41:41 -0700357
Romain Guy1f59e5c2012-05-06 14:11:16 -0700358 boolean mIsDrawing;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700359 int mLastSystemUiVisibility;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700360 int mClientWindowLayoutFlags;
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800361 boolean mLastOverscanRequested;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800362
363 // Pool of queued input events.
364 private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
365 private QueuedInputEvent mQueuedInputEventPool;
366 private int mQueuedInputEventPoolSize;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800367
Michael Wrightc8a7e542013-03-20 17:58:33 -0700368 /* Input event queue.
Jeff Brownf9e989d2013-04-04 23:04:03 -0700369 * Pending input events are input events waiting to be delivered to the input stages
370 * and handled by the application.
Michael Wrightc8a7e542013-03-20 17:58:33 -0700371 */
372 QueuedInputEvent mPendingInputEventHead;
373 QueuedInputEvent mPendingInputEventTail;
Michael Wright95ae9422013-03-14 10:58:50 -0700374 int mPendingInputEventCount;
Jeff Brown96e942d2011-11-30 19:55:01 -0800375 boolean mProcessInputEventsScheduled;
Michael Wright9d744c72014-02-18 21:27:42 -0800376 boolean mUnbufferedInputDispatch;
Michael Wright95ae9422013-03-14 10:58:50 -0700377 String mPendingInputEventQueueLengthCounterName = "pq";
Jeff Brownf9e989d2013-04-04 23:04:03 -0700378
379 InputStage mFirstInputStage;
380 InputStage mFirstPostImeInputStage;
Michael Wright899d7052014-04-23 17:23:39 -0700381 InputStage mSyntheticInputStage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382
Evan Rosky4807ae22018-03-22 16:04:15 -0700383 private final UnhandledKeyManager mUnhandledKeyManager = new UnhandledKeyManager();
Evan Rosky5e29c072017-06-02 17:31:22 -0700384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 boolean mWindowAttributesChanged = false;
Romain Guyf21c9b02011-09-06 16:56:54 -0700386 int mWindowAttributesChangesFlag = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387
388 // These can be accessed by any thread, must be protected with a lock.
Mathias Agopian5583dc62009-07-09 16:28:11 -0700389 // Surface can never be reassigned or cleared (use Surface.clear()).
Andrei Stingaceanud2eadfa2017-09-22 15:32:13 +0100390 public final Surface mSurface = new Surface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391
392 boolean mAdded;
393 boolean mAddedTouchMode;
394
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 // These are accessed by multiple threads.
396 final Rect mWinFrame; // frame given by window manager.
397
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800398 final Rect mPendingOverscanInsets = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 final Rect mPendingVisibleInsets = new Rect();
Adrian Roosfa104232014-06-20 16:10:14 -0700400 final Rect mPendingStableInsets = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 final Rect mPendingContentInsets = new Rect();
Filip Gruszczynski2217f612015-05-26 11:32:08 -0700402 final Rect mPendingOutsets = new Rect();
Jorim Jaggia7262a82015-11-03 15:15:40 +0100403 final Rect mPendingBackDropFrame = new Rect();
Adrian Roos5c6b6222017-11-07 17:36:10 +0100404 final DisplayCutout.ParcelableWrapper mPendingDisplayCutout =
405 new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT);
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -0800406 boolean mPendingAlwaysConsumeNavBar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407 final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
408 = new ViewTreeObserver.InternalInsetsInfo();
409
Adrian Roosfa104232014-06-20 16:10:14 -0700410 final Rect mDispatchContentInsets = new Rect();
411 final Rect mDispatchStableInsets = new Rect();
Adrian Roos5c6b6222017-11-07 17:36:10 +0100412 DisplayCutout mDispatchDisplayCutout = DisplayCutout.NO_CUTOUT;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700413
Filip Gruszczynski954289d2015-02-26 15:46:47 -0800414 private WindowInsets mLastWindowInsets;
415
Andrii Kulian44607962017-03-16 11:06:24 -0700416 /** Last applied configuration obtained from resources. */
417 private final Configuration mLastConfigurationFromResources = new Configuration();
418 /** Last configuration reported from WM or via {@link #MSG_UPDATE_CONFIGURATION}. */
419 private final MergedConfiguration mLastReportedMergedConfiguration = new MergedConfiguration();
420 /** Configurations waiting to be applied. */
421 private final MergedConfiguration mPendingMergedConfiguration = new MergedConfiguration();
Romain Guy59a12ca2011-06-09 17:48:21 -0700422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 boolean mScrollMayChange;
Yohei Yukawa22dac1c2017-02-12 16:54:16 -0800424 @SoftInputModeFlags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800425 int mSoftInputMode;
Svetoslav Ganov149567f2013-01-08 15:23:34 -0800426 WeakReference<View> mLastScrolledFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 int mScrollY;
428 int mCurScrollY;
429 Scroller mScroller;
John Recke56e9df2014-02-21 15:45:10 -0800430 static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
Chet Haasecca2c982011-05-20 14:34:18 -0700431 private ArrayList<LayoutTransition> mPendingTransitions;
Romain Guy8506ab42009-06-11 17:35:47 -0700432
Romain Guy8506ab42009-06-11 17:35:47 -0700433 final ViewConfiguration mViewConfiguration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434
Christopher Tatea53146c2010-09-07 11:57:52 -0700435 /* Drag/drop */
436 ClipDescription mDragDescription;
437 View mCurrentDragView;
Christopher Tate7fb8b562011-01-20 13:46:41 -0800438 volatile Object mLocalDragState;
Christopher Tatea53146c2010-09-07 11:57:52 -0700439 final PointF mDragPoint = new PointF();
Christopher Tate2c095f32010-10-04 14:13:40 -0700440 final PointF mLastTouchPoint = new PointF();
Vladislav Kaznacheevba761122016-01-22 12:09:45 -0800441 int mLastTouchSource;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700442
443 private boolean mProfileRendering;
Romain Guyd0750312012-11-29 11:34:43 -0800444 private Choreographer.FrameCallback mRenderProfiler;
445 private boolean mRenderProfilingEnabled;
Christopher Tatea53146c2010-09-07 11:57:52 -0700446
Chet Haase2f2022a2011-10-11 06:41:59 -0700447 // Variables to track frames per second, enabled via DEBUG_FPS flag
448 private long mFpsStartTime = -1;
449 private long mFpsPrevTime = -1;
450 private int mFpsNumFrames;
451
Michael Wrightf9d9ce772016-05-13 17:44:16 +0100452 private int mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
Jun Mukaid4eaef72015-10-30 15:54:33 -0700453 private PointerIcon mCustomPointerIcon = null;
Jun Mukai1db53972015-09-11 18:08:31 -0700454
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 /**
456 * see {@link #playSoundEffect(int)}
457 */
458 AudioManager mAudioManager;
459
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700460 final AccessibilityManager mAccessibilityManager;
461
Gilles Debunne5ac84422011-10-19 09:35:58 -0700462 AccessibilityInteractionController mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700463
Phil Weaver26d709f2017-04-20 17:19:14 -0700464 final AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager =
465 new AccessibilityInteractionConnectionManager();
466 final HighContrastTextManager mHighContrastTextManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700467
Eugene Susla72c510f2018-01-23 21:12:11 +0000468 SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
469
470 HashSet<View> mTempHashSet;
471
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700472 private final int mDensity;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700473 private final int mNoncompatDensity;
Adam Powellb08013c2010-09-16 16:28:11 -0700474
Chet Haase97140572012-09-13 14:56:47 -0700475 private boolean mInLayout = false;
476 ArrayList<View> mLayoutRequesters = new ArrayList<View>();
477 boolean mHandlingLayoutInLayoutRequest = false;
478
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700479 private int mViewLayoutDirectionInitial;
Chet Haase97140572012-09-13 14:56:47 -0700480
Craig Mautner8f303ad2013-06-14 11:32:22 -0700481 /** Set to true once doDie() has been called. */
482 private boolean mRemoved;
483
Stan Iliev45faba52016-06-28 13:33:15 -0400484 private boolean mNeedsRendererSetup;
Robert Carr1bccabf2016-04-28 13:27:08 -0700485
Jeff Brown21bc5c92011-02-28 18:27:14 -0800486 /**
487 * Consistency verifier for debugging purposes.
488 */
489 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
490 InputEventConsistencyVerifier.isInstrumentationEnabled() ?
491 new InputEventConsistencyVerifier(this, 0) : null;
492
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700493 static final class SystemUiVisibilityInfo {
494 int seq;
495 int globalVisibility;
496 int localValue;
497 int localChanges;
498 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700499
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800500 private String mTag = TAG;
501
Jeff Brown98365d72012-08-19 20:30:52 -0700502 public ViewRootImpl(Context context, Display display) {
Jeff Brownf9e989d2013-04-04 23:04:03 -0700503 mContext = context;
504 mWindowSession = WindowManagerGlobal.getWindowSession();
Jeff Brown98365d72012-08-19 20:30:52 -0700505 mDisplay = display;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800506 mBasePackageName = context.getBasePackageName();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 mThread = Thread.currentThread();
508 mLocation = new WindowLeaked(null);
509 mLocation.fillInStackTrace();
510 mWidth = -1;
511 mHeight = -1;
512 mDirty = new Rect();
513 mTempRect = new Rect();
514 mVisRect = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515 mWinFrame = new Rect();
Romain Guyfb8b7632010-08-23 21:05:08 -0700516 mWindow = new W(this);
Dianne Hackborn180c4842011-09-13 12:39:25 -0700517 mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 mViewVisibility = View.GONE;
519 mTransparentRegion = new Region();
520 mPreviousTransparentRegion = new Region();
521 mFirst = true; // true for the first time the view is added
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 mAdded = false;
John Reckd94094e2016-09-08 14:12:26 -0700523 mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
524 context);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700525 mAccessibilityManager = AccessibilityManager.getInstance(context);
Svetoslav Ganov00d0c142012-02-24 11:30:49 -0800526 mAccessibilityManager.addAccessibilityStateChangeListener(
Phil Weaver26d709f2017-04-20 17:19:14 -0700527 mAccessibilityInteractionConnectionManager, mHandler);
Chris Craikcce47eb2014-07-16 15:12:15 -0700528 mHighContrastTextManager = new HighContrastTextManager();
529 mAccessibilityManager.addHighTextContrastStateChangeListener(
Phil Weaver26d709f2017-04-20 17:19:14 -0700530 mHighContrastTextManager, mHandler);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 mViewConfiguration = ViewConfiguration.get(context);
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700532 mDensity = context.getResources().getDisplayMetrics().densityDpi;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700533 mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
Jorim Jaggib10e33f2015-02-04 21:57:40 +0100534 mFallbackEventHandler = new PhoneFallbackEventHandler(context);
Jeff Brown96e942d2011-11-30 19:55:01 -0800535 mChoreographer = Choreographer.getInstance();
Jeff Brownd912e1f2014-04-11 18:46:22 -0700536 mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
Evan Rosky37df2db2017-01-24 16:35:52 -0800537
538 if (!sCompatibilityDone) {
Evan Roskybdc66cb2017-09-08 14:27:24 -0700539 sAlwaysAssignFocus = mTargetSdkVersion < Build.VERSION_CODES.P;
Evan Rosky37df2db2017-01-24 16:35:52 -0800540
541 sCompatibilityDone = true;
542 }
543
Dianne Hackborna53de062012-05-08 18:53:51 -0700544 loadSystemProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 }
546
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800547 public static void addFirstDrawHandler(Runnable callback) {
548 synchronized (sFirstDrawHandlers) {
549 if (!sFirstDrawComplete) {
550 sFirstDrawHandlers.add(callback);
551 }
552 }
553 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700554
Andrii Kulian44607962017-03-16 11:06:24 -0700555 /** Add static config callback to be notified about global config changes. */
556 public static void addConfigCallback(ConfigChangedCallback callback) {
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800557 synchronized (sConfigCallbacks) {
558 sConfigCallbacks.add(callback);
559 }
560 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700561
Andrii Kulian44607962017-03-16 11:06:24 -0700562 /** Add activity config callback to be notified about override config changes. */
563 public void setActivityConfigCallback(ActivityConfigCallback callback) {
564 mActivityConfigCallback = callback;
565 }
566
Chong Zhangdcee1de2015-10-06 10:26:00 -0700567 public void addWindowCallbacks(WindowCallbacks callback) {
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +0900568 synchronized (mWindowCallbacks) {
569 mWindowCallbacks.add(callback);
Skuhneb8160872015-09-22 09:51:39 -0700570 }
571 }
572
Chong Zhangdcee1de2015-10-06 10:26:00 -0700573 public void removeWindowCallbacks(WindowCallbacks callback) {
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +0900574 synchronized (mWindowCallbacks) {
575 mWindowCallbacks.remove(callback);
Skuhneb8160872015-09-22 09:51:39 -0700576 }
577 }
578
Chong Zhang8dbd9ad2015-10-09 10:06:11 -0700579 public void reportDrawFinish() {
580 if (mWindowDrawCountDown != null) {
581 mWindowDrawCountDown.countDown();
582 }
583 }
584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 // FIXME for perf testing only
586 private boolean mProfile = false;
587
588 /**
589 * Call this to profile the next traversal call.
590 * FIXME for perf testing only. Remove eventually
591 */
592 public void profile() {
593 mProfile = true;
594 }
595
596 /**
597 * Indicates whether we are in touch mode. Calling this method triggers an IPC
598 * call and should be avoided whenever possible.
599 *
600 * @return True, if the device is in touch mode, false otherwise.
601 *
602 * @hide
603 */
604 static boolean isInTouchMode() {
Jeff Brown98365d72012-08-19 20:30:52 -0700605 IWindowSession windowSession = WindowManagerGlobal.peekWindowSession();
606 if (windowSession != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 try {
Jeff Brown98365d72012-08-19 20:30:52 -0700608 return windowSession.getInTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 } catch (RemoteException e) {
610 }
611 }
612 return false;
613 }
614
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 /**
Robert Carrb2594852016-04-25 16:21:13 -0700616 * Notifies us that our child has been rebuilt, following
617 * a window preservation operation. In these cases we
618 * keep the same DecorView, but the activity controlling it
619 * is a different instance, and we need to update our
620 * callbacks.
621 *
622 * @hide
623 */
624 public void notifyChildRebuilt() {
625 if (mView instanceof RootViewSurfaceTaker) {
Robert Carr25cfa132016-11-16 13:24:09 -0800626 if (mSurfaceHolderCallback != null) {
627 mSurfaceHolder.removeCallback(mSurfaceHolderCallback);
628 }
629
Robert Carrb2594852016-04-25 16:21:13 -0700630 mSurfaceHolderCallback =
631 ((RootViewSurfaceTaker)mView).willYouTakeTheSurface();
Robert Carr25cfa132016-11-16 13:24:09 -0800632
Robert Carrb2594852016-04-25 16:21:13 -0700633 if (mSurfaceHolderCallback != null) {
634 mSurfaceHolder = new TakenSurfaceHolder();
635 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
Robert Carr25cfa132016-11-16 13:24:09 -0800636 mSurfaceHolder.addCallback(mSurfaceHolderCallback);
Robert Carrb2594852016-04-25 16:21:13 -0700637 } else {
638 mSurfaceHolder = null;
639 }
640
641 mInputQueueCallback =
642 ((RootViewSurfaceTaker)mView).willYouTakeTheInputQueue();
643 if (mInputQueueCallback != null) {
644 mInputQueueCallback.onInputQueueCreated(mInputQueue);
645 }
646 }
647 }
648
649 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 * We have one child
651 */
Romain Guye4d01122010-06-16 18:44:05 -0700652 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 synchronized (this) {
654 if (mView == null) {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700655 mView = view;
Jeff Brownd912e1f2014-04-11 18:46:22 -0700656
657 mAttachInfo.mDisplayState = mDisplay.getState();
658 mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
659
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700660 mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
Joe Onorato86f67862010-11-05 18:57:34 -0700661 mFallbackEventHandler.setView(view);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700662 mWindowAttributes.copyFrom(attrs);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800663 if (mWindowAttributes.packageName == null) {
664 mWindowAttributes.packageName = mBasePackageName;
665 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700666 attrs = mWindowAttributes;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800667 setTag();
Chong Zhang4ffc3182016-05-04 15:06:02 -0700668
Chong Zhang44aabe42016-05-10 11:20:14 -0700669 if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
670 & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
Chong Zhang4ffc3182016-05-04 15:06:02 -0700671 && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) {
Chong Zhang44aabe42016-05-10 11:20:14 -0700672 Slog.d(mTag, "setView: FLAG_KEEP_SCREEN_ON changed from true to false!");
Chong Zhang4ffc3182016-05-04 15:06:02 -0700673 }
Dianne Hackborn9d090892012-06-11 18:35:41 -0700674 // Keep track of the actual window flags supplied by the client.
675 mClientWindowLayoutFlags = attrs.flags;
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700676
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700677 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700678
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700679 if (view instanceof RootViewSurfaceTaker) {
680 mSurfaceHolderCallback =
681 ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
682 if (mSurfaceHolderCallback != null) {
683 mSurfaceHolder = new TakenSurfaceHolder();
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700684 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
Robert Carr25cfa132016-11-16 13:24:09 -0800685 mSurfaceHolder.addCallback(mSurfaceHolderCallback);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700686 }
687 }
Romain Guy1aec9a22011-01-05 09:37:12 -0800688
Alan Viverette49a22e82014-07-12 20:01:27 -0700689 // Compute surface insets required to draw at specified Z value.
690 // TODO: Use real shadow insets for a constant max Z.
Alan Viverette5435a302015-01-29 10:25:34 -0800691 if (!attrs.hasManualSurfaceInsets) {
Wale Ogunwale246c2092016-04-07 14:12:44 -0700692 attrs.setSurfaceInsets(view, false /*manual*/, true /*preservePrevious*/);
Alan Viverette5435a302015-01-29 10:25:34 -0800693 }
Alan Viverette49a22e82014-07-12 20:01:27 -0700694
Adam Lesinski4ece3d62016-06-16 18:05:41 -0700695 CompatibilityInfo compatibilityInfo =
696 mDisplay.getDisplayAdjustments().getCompatibilityInfo();
Romain Guy856d4e12011-10-14 15:47:55 -0700697 mTranslator = compatibilityInfo.getTranslator();
698
Romain Guy1aec9a22011-01-05 09:37:12 -0800699 // If the application owns the surface, don't enable hardware acceleration
700 if (mSurfaceHolder == null) {
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +0900701 // While this is supposed to enable only, it can effectively disable
702 // the acceleration too.
Romain Guy3b748a42013-04-17 18:54:38 -0700703 enableHardwareAcceleration(attrs);
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +0900704 final boolean useMTRenderer = MT_RENDERER_AVAILABLE
705 && mAttachInfo.mThreadedRenderer != null;
706 if (mUseMTRenderer != useMTRenderer) {
707 // Shouldn't be resizing, as it's done only in window setup,
708 // but end just in case.
709 endDragResizing();
710 mUseMTRenderer = useMTRenderer;
711 }
Romain Guy1aec9a22011-01-05 09:37:12 -0800712 }
713
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700714 boolean restore = false;
Romain Guy35b38ce2009-10-07 13:38:55 -0700715 if (mTranslator != null) {
Romain Guy856d4e12011-10-14 15:47:55 -0700716 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700717 restore = true;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700718 attrs.backup();
719 mTranslator.translateWindowLayout(attrs);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700720 }
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800721 if (DEBUG_LAYOUT) Log.d(mTag, "WindowLayout in setView:" + attrs);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700722
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700723 if (!compatibilityInfo.supportsScreen()) {
Adam Lesinski95c42972013-10-02 10:13:27 -0700724 attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700725 mLastInCompatMode = true;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700726 }
727
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800728 mSoftInputMode = attrs.softInputMode;
729 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -0700730 mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731 mAttachInfo.mRootView = view;
Romain Guy35b38ce2009-10-07 13:38:55 -0700732 mAttachInfo.mScalingRequired = mTranslator != null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700733 mAttachInfo.mApplicationScale =
734 mTranslator == null ? 1.0f : mTranslator.applicationScale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800735 if (panelParentView != null) {
736 mAttachInfo.mPanelParentWindowToken
737 = panelParentView.getApplicationWindowToken();
738 }
739 mAdded = true;
740 int res; /* = WindowManagerImpl.ADD_OKAY; */
Romain Guy8506ab42009-06-11 17:35:47 -0700741
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800742 // Schedule the first layout -before- adding to the window
743 // manager, to make sure we do the relayout before receiving
744 // any other events from the system.
745 requestLayout();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700746 if ((mWindowAttributes.inputFeatures
747 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
748 mInputChannel = new InputChannel();
749 }
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800750 mForceDecorViewVisibility = (mWindowAttributes.privateFlags
751 & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752 try {
Dianne Hackborn180c4842011-09-13 12:39:25 -0700753 mOrigWindowType = mWindowAttributes.type;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700754 mAttachInfo.mRecomputeGlobalAttributes = true;
755 collectViewAttributes();
Jeff Brown98365d72012-08-19 20:30:52 -0700756 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
Adrian Roos9e370f22018-03-06 18:19:45 +0100757 getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
Filip Gruszczynski0ec13282015-06-25 11:26:01 -0700758 mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
Adrian Roos5c6b6222017-11-07 17:36:10 +0100759 mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 } catch (RemoteException e) {
761 mAdded = false;
762 mView = null;
763 mAttachInfo.mRootView = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700764 mInputChannel = null;
Joe Onorato86f67862010-11-05 18:57:34 -0700765 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700767 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 throw new RuntimeException("Adding window failed", e);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700769 } finally {
770 if (restore) {
771 attrs.restore();
772 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700774
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700775 if (mTranslator != null) {
776 mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700777 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800778 mPendingOverscanInsets.set(0, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779 mPendingContentInsets.set(mAttachInfo.mContentInsets);
Adrian Roosfa104232014-06-20 16:10:14 -0700780 mPendingStableInsets.set(mAttachInfo.mStableInsets);
Adrian Roos5c6b6222017-11-07 17:36:10 +0100781 mPendingDisplayCutout.set(mAttachInfo.mDisplayCutout);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782 mPendingVisibleInsets.set(0, 0, 0, 0);
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -0800783 mAttachInfo.mAlwaysConsumeNavBar =
784 (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR) != 0;
785 mPendingAlwaysConsumeNavBar = mAttachInfo.mAlwaysConsumeNavBar;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800786 if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
Jeff Brown98365d72012-08-19 20:30:52 -0700787 if (res < WindowManagerGlobal.ADD_OKAY) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 mAttachInfo.mRootView = null;
789 mAdded = false;
Joe Onorato86f67862010-11-05 18:57:34 -0700790 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800791 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700792 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 switch (res) {
Jeff Brown98365d72012-08-19 20:30:52 -0700794 case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
795 case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
796 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800797 "Unable to add window -- token " + attrs.token
798 + " is not valid; is your activity running?");
Jeff Brown98365d72012-08-19 20:30:52 -0700799 case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
800 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800801 "Unable to add window -- token " + attrs.token
802 + " is not for an application");
Jeff Brown98365d72012-08-19 20:30:52 -0700803 case WindowManagerGlobal.ADD_APP_EXITING:
804 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800805 "Unable to add window -- app for token " + attrs.token
806 + " is exiting");
Jeff Brown98365d72012-08-19 20:30:52 -0700807 case WindowManagerGlobal.ADD_DUPLICATE_ADD:
808 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800809 "Unable to add window -- window " + mWindow
810 + " has already been added");
Jeff Brown98365d72012-08-19 20:30:52 -0700811 case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 // Silently ignore -- we would have just removed it
813 // right away, anyway.
814 return;
Jeff Brown98365d72012-08-19 20:30:52 -0700815 case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
Alan Viverette73f6d602015-09-14 16:01:19 -0400816 throw new WindowManager.BadTokenException("Unable to add window "
817 + mWindow + " -- another window of type "
818 + mWindowAttributes.type + " already exists");
Jeff Brown98365d72012-08-19 20:30:52 -0700819 case WindowManagerGlobal.ADD_PERMISSION_DENIED:
Alan Viverette73f6d602015-09-14 16:01:19 -0400820 throw new WindowManager.BadTokenException("Unable to add window "
821 + mWindow + " -- permission denied for window type "
822 + mWindowAttributes.type);
Craig Mautner6018aee2012-10-23 14:27:49 -0700823 case WindowManagerGlobal.ADD_INVALID_DISPLAY:
Alan Viverette73f6d602015-09-14 16:01:19 -0400824 throw new WindowManager.InvalidDisplayException("Unable to add window "
825 + mWindow + " -- the specified display can not be found");
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800826 case WindowManagerGlobal.ADD_INVALID_TYPE:
Alan Viverette73f6d602015-09-14 16:01:19 -0400827 throw new WindowManager.InvalidDisplayException("Unable to add window "
828 + mWindow + " -- the specified window type "
829 + mWindowAttributes.type + " is not valid");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800830 }
831 throw new RuntimeException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800832 "Unable to add window -- unknown error code " + res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800833 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700834
Jeff Brown00fa7bd2010-07-02 15:37:36 -0700835 if (view instanceof RootViewSurfaceTaker) {
836 mInputQueueCallback =
837 ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
838 }
Jeff Browncc4f7db2011-08-30 20:34:48 -0700839 if (mInputChannel != null) {
840 if (mInputQueueCallback != null) {
Michael Wrighta44dd262013-04-10 21:12:00 -0700841 mInputQueue = new InputQueue();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700842 mInputQueueCallback.onInputQueueCreated(mInputQueue);
Jeff Browncc4f7db2011-08-30 20:34:48 -0700843 }
Michael Wrighta44dd262013-04-10 21:12:00 -0700844 mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
845 Looper.myLooper());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700846 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700847
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 view.assignParent(this);
Jeff Brown98365d72012-08-19 20:30:52 -0700849 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
850 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700851
852 if (mAccessibilityManager.isEnabled()) {
853 mAccessibilityInteractionConnectionManager.ensureConnection();
854 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700855
856 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
857 view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
858 }
Michael Wright95ae9422013-03-14 10:58:50 -0700859
Jeff Brownf9e989d2013-04-04 23:04:03 -0700860 // Set up the input pipeline.
861 CharSequence counterSuffix = attrs.getTitle();
Michael Wright899d7052014-04-23 17:23:39 -0700862 mSyntheticInputStage = new SyntheticInputStage();
863 InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
Jeff Brownf9e989d2013-04-04 23:04:03 -0700864 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
865 "aq:native-post-ime:" + counterSuffix);
866 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
867 InputStage imeStage = new ImeInputStage(earlyPostImeStage,
868 "aq:ime:" + counterSuffix);
869 InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
870 InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
871 "aq:native-pre-ime:" + counterSuffix);
872
873 mFirstInputStage = nativePreImeStage;
874 mFirstPostImeInputStage = earlyPostImeStage;
875 mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 }
877 }
878 }
879
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800880 private void setTag() {
881 final String[] split = mWindowAttributes.getTitle().toString().split("\\.");
882 if (split.length > 0) {
883 mTag = TAG + "[" + split[split.length - 1] + "]";
884 }
885 }
886
keunyoung30f420f2013-08-02 14:23:10 -0700887 /** Whether the window is in local focus mode or not */
888 private boolean isInLocalFocusMode() {
889 return (mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0;
890 }
891
Dianne Hackborn49b043f2015-05-07 14:21:38 -0700892 public int getWindowFlags() {
893 return mWindowAttributes.flags;
894 }
895
Dianne Hackbornece0f4f2015-06-11 13:29:01 -0700896 public int getDisplayId() {
897 return mDisplay.getDisplayId();
898 }
899
Dianne Hackborna7bb6fb2015-02-03 18:13:40 -0800900 public CharSequence getTitle() {
901 return mWindowAttributes.getTitle();
902 }
903
Mihai Popa3589c2c2018-01-25 19:26:30 +0000904 /**
905 * @return the width of the root view. Note that this will return {@code -1} until the first
906 * layout traversal, when the width is set.
907 *
908 * @hide
909 */
910 public int getWidth() {
911 return mWidth;
912 }
913
914 /**
915 * @return the height of the root view. Note that this will return {@code -1} until the first
916 * layout traversal, when the height is set.
917 *
918 * @hide
919 */
920 public int getHeight() {
921 return mHeight;
922 }
923
Romain Guy8ff6b9e2011-11-09 20:10:18 -0800924 void destroyHardwareResources() {
Stan Iliev45faba52016-06-28 13:33:15 -0400925 if (mAttachInfo.mThreadedRenderer != null) {
926 mAttachInfo.mThreadedRenderer.destroyHardwareResources(mView);
927 mAttachInfo.mThreadedRenderer.destroy();
Romain Guy31f2c2e2011-11-21 10:55:41 -0800928 }
929 }
930
Bo Liu845535a2014-03-21 12:06:23 -0700931 public void detachFunctor(long functor) {
Stan Iliev45faba52016-06-28 13:33:15 -0400932 if (mAttachInfo.mThreadedRenderer != null) {
John Reck44ac42a2014-05-16 14:46:07 -0700933 // Fence so that any pending invokeFunctor() messages will be processed
934 // before we return from detachFunctor.
Stan Iliev45faba52016-06-28 13:33:15 -0400935 mAttachInfo.mThreadedRenderer.stopDrawing();
John Reck44ac42a2014-05-16 14:46:07 -0700936 }
Romain Guyba6be8a2012-04-23 18:22:09 -0700937 }
938
John Reck3b202512014-06-23 13:13:08 -0700939 /**
940 * Schedules the functor for execution in either kModeProcess or
941 * kModeProcessNoContext, depending on whether or not there is an EGLContext.
942 *
943 * @param functor The native functor to invoke
944 * @param waitForCompletion If true, this will not return until the functor
945 * has invoked. If false, the functor may be invoked
946 * asynchronously.
947 */
John Reck44b49f02016-03-25 14:29:48 -0700948 public static void invokeFunctor(long functor, boolean waitForCompletion) {
John Reck3b202512014-06-23 13:13:08 -0700949 ThreadedRenderer.invokeFunctor(functor, waitForCompletion);
Bo Liuae738a72014-04-27 16:22:04 -0700950 }
951
John Reck119907c2014-08-14 09:02:01 -0700952 public void registerAnimatingRenderNode(RenderNode animator) {
Stan Iliev45faba52016-06-28 13:33:15 -0400953 if (mAttachInfo.mThreadedRenderer != null) {
954 mAttachInfo.mThreadedRenderer.registerAnimatingRenderNode(animator);
John Reck119907c2014-08-14 09:02:01 -0700955 } else {
956 if (mAttachInfo.mPendingAnimatingRenderNodes == null) {
957 mAttachInfo.mPendingAnimatingRenderNodes = new ArrayList<RenderNode>();
958 }
959 mAttachInfo.mPendingAnimatingRenderNodes.add(animator);
960 }
961 }
962
Doris Liu718cd3e2016-05-17 16:50:31 -0700963 public void registerVectorDrawableAnimator(
964 AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) {
Stan Iliev45faba52016-06-28 13:33:15 -0400965 if (mAttachInfo.mThreadedRenderer != null) {
966 mAttachInfo.mThreadedRenderer.registerVectorDrawableAnimator(animator);
Doris Liu718cd3e2016-05-17 16:50:31 -0700967 }
968 }
969
Romain Guy3b748a42013-04-17 18:54:38 -0700970 private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800971 mAttachInfo.mHardwareAccelerated = false;
972 mAttachInfo.mHardwareAccelerationRequested = false;
Romain Guy4f6aff32011-01-12 16:21:41 -0800973
Romain Guy856d4e12011-10-14 15:47:55 -0700974 // Don't enable hardware acceleration when the application is in compatibility mode
John Reckdd58e792014-04-02 16:54:28 +0000975 if (mTranslator != null) return;
Romain Guy856d4e12011-10-14 15:47:55 -0700976
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800977 // Try to enable hardware acceleration if requested
Igor Murashkina86ab6402013-08-30 12:58:36 -0700978 final boolean hardwareAccelerated =
Jim Miller1b365922011-03-09 19:38:07 -0800979 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
980
John Reckdd58e792014-04-02 16:54:28 +0000981 if (hardwareAccelerated) {
John Reck51aaf902015-12-02 15:08:07 -0800982 if (!ThreadedRenderer.isAvailable()) {
Romain Guy1af23a32011-03-24 16:03:55 -0700983 return;
984 }
985
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700986 // Persistent processes (including the system) should not do
987 // accelerated rendering on low-end devices. In that case,
988 // sRendererDisabled will be set. In addition, the system process
989 // itself should never do accelerated rendering. In that case, both
990 // sRendererDisabled and sSystemRendererDisabled are set. When
991 // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
992 // can be used by code on the system process to escape that and enable
993 // HW accelerated drawing. (This is basically for the lock screen.)
Jim Miller1b365922011-03-09 19:38:07 -0800994
John Reck61375a82014-09-18 19:27:48 +0000995 final boolean fakeHwAccelerated = (attrs.privateFlags &
996 WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700997 final boolean forceHwAccelerated = (attrs.privateFlags &
998 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
Jim Miller1b365922011-03-09 19:38:07 -0800999
John Reck61375a82014-09-18 19:27:48 +00001000 if (fakeHwAccelerated) {
1001 // This is exclusively for the preview windows the window manager
1002 // shows for launching applications, so they will look more like
1003 // the app being launched.
1004 mAttachInfo.mHardwareAccelerationRequested = true;
John Reck51aaf902015-12-02 15:08:07 -08001005 } else if (!ThreadedRenderer.sRendererDisabled
1006 || (ThreadedRenderer.sSystemRendererDisabled && forceHwAccelerated)) {
Stan Iliev45faba52016-06-28 13:33:15 -04001007 if (mAttachInfo.mThreadedRenderer != null) {
1008 mAttachInfo.mThreadedRenderer.destroy();
Romain Guy211370f2012-02-01 16:10:55 -08001009 }
1010
Alan Viverette2b12b582014-10-29 11:11:40 -07001011 final Rect insets = attrs.surfaceInsets;
Alan Viverette2cd23e62014-11-04 17:04:02 -08001012 final boolean hasSurfaceInsets = insets.left != 0 || insets.right != 0
1013 || insets.top != 0 || insets.bottom != 0;
Alan Viverette2b12b582014-10-29 11:11:40 -07001014 final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;
Romain Guy26a2b972017-04-17 09:39:51 -07001015 final boolean wideGamut =
Romain Guye89d0bb2017-06-20 12:23:42 -07001016 mContext.getResources().getConfiguration().isScreenWideColorGamut()
1017 && attrs.getColorMode() == ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT;
Romain Guy26a2b972017-04-17 09:39:51 -07001018
John Reckdf1742e2017-01-19 15:56:21 -08001019 mAttachInfo.mThreadedRenderer = ThreadedRenderer.create(mContext, translucent,
1020 attrs.getTitle().toString());
Romain Guy26a2b972017-04-17 09:39:51 -07001021 mAttachInfo.mThreadedRenderer.setWideGamut(wideGamut);
Stan Iliev45faba52016-06-28 13:33:15 -04001022 if (mAttachInfo.mThreadedRenderer != null) {
Romain Guye55945e2013-04-04 15:26:04 -07001023 mAttachInfo.mHardwareAccelerated =
1024 mAttachInfo.mHardwareAccelerationRequested = true;
1025 }
Romain Guye4d01122010-06-16 18:44:05 -07001026 }
1027 }
1028 }
1029
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001030 public View getView() {
1031 return mView;
1032 }
1033
1034 final WindowLeaked getLocation() {
1035 return mLocation;
1036 }
1037
1038 void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
1039 synchronized (this) {
Alan Viverettedbed8932014-08-06 17:54:52 -07001040 final int oldInsetLeft = mWindowAttributes.surfaceInsets.left;
1041 final int oldInsetTop = mWindowAttributes.surfaceInsets.top;
1042 final int oldInsetRight = mWindowAttributes.surfaceInsets.right;
1043 final int oldInsetBottom = mWindowAttributes.surfaceInsets.bottom;
1044 final int oldSoftInputMode = mWindowAttributes.softInputMode;
Alan Viverette5435a302015-01-29 10:25:34 -08001045 final boolean oldHasManualSurfaceInsets = mWindowAttributes.hasManualSurfaceInsets;
Chong Zhang44aabe42016-05-10 11:20:14 -07001046
1047 if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
1048 & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
Chong Zhang4ffc3182016-05-04 15:06:02 -07001049 && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) {
Chong Zhang44aabe42016-05-10 11:20:14 -07001050 Slog.d(mTag, "setLayoutParams: FLAG_KEEP_SCREEN_ON from true to false!");
Chong Zhang4ffc3182016-05-04 15:06:02 -07001051 }
Alan Viverettedbed8932014-08-06 17:54:52 -07001052
Dianne Hackborn9d090892012-06-11 18:35:41 -07001053 // Keep track of the actual window flags supplied by the client.
1054 mClientWindowLayoutFlags = attrs.flags;
Alan Viverettedbed8932014-08-06 17:54:52 -07001055
1056 // Preserve compatible window flag if exists.
1057 final int compatibleWindowFlag = mWindowAttributes.privateFlags
Adam Lesinski95c42972013-10-02 10:13:27 -07001058 & WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Alan Viverettedbed8932014-08-06 17:54:52 -07001059
1060 // Transfer over system UI visibility values as they carry current state.
Craig Mautner3fe38c02012-05-03 17:28:09 -07001061 attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
1062 attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
Alan Viverettedbed8932014-08-06 17:54:52 -07001063
Romain Guyf21c9b02011-09-06 16:56:54 -07001064 mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
John Spurlockbd957402013-10-03 11:38:39 -04001065 if ((mWindowAttributesChangesFlag
1066 & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) {
1067 // Recompute system ui visibility.
1068 mAttachInfo.mRecomputeGlobalAttributes = true;
1069 }
Teng-Hui Zhu27571282016-05-12 15:53:53 -07001070 if ((mWindowAttributesChangesFlag
1071 & WindowManager.LayoutParams.LAYOUT_CHANGED) != 0) {
1072 // Request to update light center.
1073 mAttachInfo.mNeedsUpdateLightCenter = true;
1074 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001075 if (mWindowAttributes.packageName == null) {
1076 mWindowAttributes.packageName = mBasePackageName;
1077 }
Adam Lesinski95c42972013-10-02 10:13:27 -07001078 mWindowAttributes.privateFlags |= compatibleWindowFlag;
Dianne Hackborn9d090892012-06-11 18:35:41 -07001079
Wale Ogunwale246c2092016-04-07 14:12:44 -07001080 if (mWindowAttributes.preservePreviousSurfaceInsets) {
1081 // Restore old surface insets.
1082 mWindowAttributes.surfaceInsets.set(
1083 oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
1084 mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
Robert Carr1bccabf2016-04-28 13:27:08 -07001085 } else if (mWindowAttributes.surfaceInsets.left != oldInsetLeft
1086 || mWindowAttributes.surfaceInsets.top != oldInsetTop
1087 || mWindowAttributes.surfaceInsets.right != oldInsetRight
1088 || mWindowAttributes.surfaceInsets.bottom != oldInsetBottom) {
Stan Iliev45faba52016-06-28 13:33:15 -04001089 mNeedsRendererSetup = true;
Wale Ogunwale246c2092016-04-07 14:12:44 -07001090 }
Alan Viverettedbed8932014-08-06 17:54:52 -07001091
Dianne Hackborn9d090892012-06-11 18:35:41 -07001092 applyKeepScreenOnFlag(mWindowAttributes);
1093
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 if (newView) {
1095 mSoftInputMode = attrs.softInputMode;
1096 requestLayout();
1097 }
Alan Viverettedbed8932014-08-06 17:54:52 -07001098
The Android Open Source Project10592532009-03-18 17:39:46 -07001099 // Don't lose the mode we last auto-computed.
Alan Viverettedbed8932014-08-06 17:54:52 -07001100 if ((attrs.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
The Android Open Source Project10592532009-03-18 17:39:46 -07001101 == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
1102 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
1103 & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
Alan Viverettedbed8932014-08-06 17:54:52 -07001104 | (oldSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
The Android Open Source Project10592532009-03-18 17:39:46 -07001105 }
Alan Viverettedbed8932014-08-06 17:54:52 -07001106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107 mWindowAttributesChanged = true;
1108 scheduleTraversals();
1109 }
1110 }
1111
1112 void handleAppVisibility(boolean visible) {
1113 if (mAppVisible != visible) {
1114 mAppVisible = visible;
Andrii Kulian74b561a2017-08-11 09:06:46 -07001115 mAppVisibilityChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001116 scheduleTraversals();
John Reck73840ea2014-09-22 07:39:18 -07001117 if (!mAppVisible) {
1118 WindowManagerGlobal.trimForeground();
1119 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 }
1121 }
1122
1123 void handleGetNewSurface() {
1124 mNewSurfaceNeeded = true;
1125 mFullRedrawNeeded = true;
1126 scheduleTraversals();
1127 }
1128
Jeff Brownd912e1f2014-04-11 18:46:22 -07001129 private final DisplayListener mDisplayListener = new DisplayListener() {
1130 @Override
1131 public void onDisplayChanged(int displayId) {
1132 if (mView != null && mDisplay.getDisplayId() == displayId) {
1133 final int oldDisplayState = mAttachInfo.mDisplayState;
1134 final int newDisplayState = mDisplay.getState();
1135 if (oldDisplayState != newDisplayState) {
1136 mAttachInfo.mDisplayState = newDisplayState;
Jeff Brownc2932a12014-11-20 18:04:05 -08001137 pokeDrawLockIfNeeded();
Jeff Brownd912e1f2014-04-11 18:46:22 -07001138 if (oldDisplayState != Display.STATE_UNKNOWN) {
1139 final int oldScreenState = toViewScreenState(oldDisplayState);
1140 final int newScreenState = toViewScreenState(newDisplayState);
1141 if (oldScreenState != newScreenState) {
1142 mView.dispatchScreenStateChanged(newScreenState);
1143 }
1144 if (oldDisplayState == Display.STATE_OFF) {
1145 // Draw was suppressed so we need to for it to happen here.
1146 mFullRedrawNeeded = true;
1147 scheduleTraversals();
1148 }
1149 }
1150 }
Romain Guy7e4e5612012-03-05 14:37:29 -08001151 }
1152 }
Jeff Brownd912e1f2014-04-11 18:46:22 -07001153
1154 @Override
1155 public void onDisplayRemoved(int displayId) {
1156 }
1157
1158 @Override
1159 public void onDisplayAdded(int displayId) {
1160 }
1161
1162 private int toViewScreenState(int displayState) {
1163 return displayState == Display.STATE_OFF ?
1164 View.SCREEN_STATE_OFF : View.SCREEN_STATE_ON;
1165 }
1166 };
Romain Guy7e4e5612012-03-05 14:37:29 -08001167
Andrii Kulianb047b8b2017-02-08 18:38:26 -08001168 /**
1169 * Notify about move to a different display.
1170 * @param displayId The id of the display where this view root is moved to.
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07001171 * @param config Configuration of the resources on new display after move.
Andrii Kulianb047b8b2017-02-08 18:38:26 -08001172 *
1173 * @hide
1174 */
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07001175 public void onMovedToDisplay(int displayId, Configuration config) {
Andrii Kulianb047b8b2017-02-08 18:38:26 -08001176 if (mDisplay.getDisplayId() == displayId) {
1177 return;
1178 }
1179
1180 // Get new instance of display based on current display adjustments. It may be updated later
1181 // if moving between the displays also involved a configuration change.
Bryce Lee609bf652017-02-09 16:50:13 -08001182 mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(displayId,
1183 mView.getResources());
Andrii Kulianb047b8b2017-02-08 18:38:26 -08001184 mAttachInfo.mDisplayState = mDisplay.getState();
1185 // Internal state updated, now notify the view hierarchy.
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07001186 mView.dispatchMovedToDisplay(mDisplay, config);
Andrii Kulianb047b8b2017-02-08 18:38:26 -08001187 }
1188
Jeff Brownc2932a12014-11-20 18:04:05 -08001189 void pokeDrawLockIfNeeded() {
1190 final int displayState = mAttachInfo.mDisplayState;
1191 if (mView != null && mAdded && mTraversalScheduled
1192 && (displayState == Display.STATE_DOZE
1193 || displayState == Display.STATE_DOZE_SUSPEND)) {
1194 try {
1195 mWindowSession.pokeDrawLock(mWindow);
1196 } catch (RemoteException ex) {
1197 // System server died, oh well.
1198 }
1199 }
1200 }
1201
Craig Mautner6018aee2012-10-23 14:27:49 -07001202 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001203 public void requestFitSystemWindows() {
1204 checkThread();
Adrian Roosfa104232014-06-20 16:10:14 -07001205 mApplyInsetsRequested = true;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001206 scheduleTraversals();
1207 }
1208
Craig Mautner6018aee2012-10-23 14:27:49 -07001209 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210 public void requestLayout() {
Chet Haase3efa7b52012-12-03 08:33:17 -08001211 if (!mHandlingLayoutInLayoutRequest) {
1212 checkThread();
1213 mLayoutRequested = true;
1214 scheduleTraversals();
1215 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216 }
1217
Craig Mautner6018aee2012-10-23 14:27:49 -07001218 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001219 public boolean isLayoutRequested() {
1220 return mLayoutRequested;
1221 }
1222
Chris Craik9de95db2017-01-18 17:59:23 -08001223 @Override
1224 public void onDescendantInvalidated(@NonNull View child, @NonNull View descendant) {
1225 if ((descendant.mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) {
1226 mIsAnimating = true;
1227 }
1228 invalidate();
1229 }
1230
Romain Guycfef1232012-02-23 13:50:37 -08001231 void invalidate() {
1232 mDirty.set(0, 0, mWidth, mHeight);
John Recke4267ea2014-06-03 15:53:15 -07001233 if (!mWillDrawSoon) {
1234 scheduleTraversals();
1235 }
Romain Guycfef1232012-02-23 13:50:37 -08001236 }
1237
Dianne Hackborna53de062012-05-08 18:53:51 -07001238 void invalidateWorld(View view) {
1239 view.invalidate();
1240 if (view instanceof ViewGroup) {
Romain Guyf84208f2012-09-13 22:50:18 -07001241 ViewGroup parent = (ViewGroup) view;
1242 for (int i = 0; i < parent.getChildCount(); i++) {
Dianne Hackborna53de062012-05-08 18:53:51 -07001243 invalidateWorld(parent.getChildAt(i));
1244 }
1245 }
1246 }
1247
Craig Mautner6018aee2012-10-23 14:27:49 -07001248 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001249 public void invalidateChild(View child, Rect dirty) {
Romain Guycfef1232012-02-23 13:50:37 -08001250 invalidateChildInParent(null, dirty);
1251 }
1252
Craig Mautner8f303ad2013-06-14 11:32:22 -07001253 @Override
Romain Guycfef1232012-02-23 13:50:37 -08001254 public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255 checkThread();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001256 if (DEBUG_DRAW) Log.v(mTag, "Invalidate child: " + dirty);
Romain Guycfef1232012-02-23 13:50:37 -08001257
Chet Haase70d4ba12010-10-06 09:46:45 -07001258 if (dirty == null) {
Chet Haase70d4ba12010-10-06 09:46:45 -07001259 invalidate();
Romain Guycfef1232012-02-23 13:50:37 -08001260 return null;
Chet Haase3561d062012-10-23 12:54:51 -07001261 } else if (dirty.isEmpty() && !mIsAnimating) {
Chet Haase05e91ed2012-07-03 14:17:57 -07001262 return null;
Chet Haase70d4ba12010-10-06 09:46:45 -07001263 }
Romain Guycfef1232012-02-23 13:50:37 -08001264
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001265 if (mCurScrollY != 0 || mTranslator != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266 mTempRect.set(dirty);
Romain Guy1e095972009-07-07 11:22:45 -07001267 dirty = mTempRect;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001268 if (mCurScrollY != 0) {
Romain Guycfef1232012-02-23 13:50:37 -08001269 dirty.offset(0, -mCurScrollY);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001270 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001271 if (mTranslator != null) {
Romain Guy1e095972009-07-07 11:22:45 -07001272 mTranslator.translateRectInAppWindowToScreen(dirty);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001273 }
Romain Guy1e095972009-07-07 11:22:45 -07001274 if (mAttachInfo.mScalingRequired) {
1275 dirty.inset(-1, -1);
1276 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001277 }
Romain Guycfef1232012-02-23 13:50:37 -08001278
Alan Viverettea7ea65e2015-05-15 11:30:21 -07001279 invalidateRectOnScreen(dirty);
1280
1281 return null;
1282 }
1283
1284 private void invalidateRectOnScreen(Rect dirty) {
Romain Guycfef1232012-02-23 13:50:37 -08001285 final Rect localDirty = mDirty;
1286 if (!localDirty.isEmpty() && !localDirty.contains(dirty)) {
Romain Guy02ccac62011-06-24 13:20:23 -07001287 mAttachInfo.mSetIgnoreDirtyState = true;
Romain Guy7d695942010-12-01 17:22:29 -08001288 mAttachInfo.mIgnoreDirtyState = true;
1289 }
Romain Guycfef1232012-02-23 13:50:37 -08001290
1291 // Add the new dirty rect to the current one
1292 localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
1293 // Intersect with the bounds of the window to skip
1294 // updates that lie outside of the visible region
Romain Guy7b2f8b82012-03-19 17:18:54 -07001295 final float appScale = mAttachInfo.mApplicationScale;
Chet Haase3561d062012-10-23 12:54:51 -07001296 final boolean intersected = localDirty.intersect(0, 0,
1297 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
1298 if (!intersected) {
Chet Haaseb78ee0e2012-10-17 11:32:01 -07001299 localDirty.setEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001300 }
Chet Haase3561d062012-10-23 12:54:51 -07001301 if (!mWillDrawSoon && (intersected || mIsAnimating)) {
1302 scheduleTraversals();
1303 }
Romain Guy0d9275e2010-10-26 14:22:30 -07001304 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001305
Daniel Koulomzin087ae472015-12-16 17:52:25 -05001306 public void setIsAmbientMode(boolean ambient) {
1307 mIsAmbientMode = ambient;
1308 }
1309
Robert Carr414ebc62017-04-12 12:01:00 -07001310 interface WindowStoppedCallback {
1311 public void windowStopped(boolean stopped);
1312 }
1313 private final ArrayList<WindowStoppedCallback> mWindowStoppedCallbacks = new ArrayList<>();
1314
1315 void addWindowStoppedCallback(WindowStoppedCallback c) {
1316 mWindowStoppedCallbacks.add(c);
1317 }
1318
1319 void removeWindowStoppedCallback(WindowStoppedCallback c) {
1320 mWindowStoppedCallbacks.remove(c);
1321 }
1322
George Mount41725de2015-04-09 08:23:05 -07001323 void setWindowStopped(boolean stopped) {
Dianne Hackbornce418e62011-03-01 14:31:38 -08001324 if (mStopped != stopped) {
1325 mStopped = stopped;
Stan Iliev45faba52016-06-28 13:33:15 -04001326 final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer;
John Reck8afcc762016-04-13 10:24:06 -07001327 if (renderer != null) {
1328 if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped);
1329 renderer.setStopped(mStopped);
1330 }
George Mount41725de2015-04-09 08:23:05 -07001331 if (!mStopped) {
Dianne Hackbornce418e62011-03-01 14:31:38 -08001332 scheduleTraversals();
John Reckd9b16072016-02-23 10:35:19 -08001333 } else {
John Reck8afcc762016-04-13 10:24:06 -07001334 if (renderer != null) {
1335 renderer.destroyHardwareResources(mView);
John Reckf4db3d22016-02-26 12:58:17 -08001336 }
Dianne Hackbornce418e62011-03-01 14:31:38 -08001337 }
Robert Carr414ebc62017-04-12 12:01:00 -07001338
1339 for (int i = 0; i < mWindowStoppedCallbacks.size(); i++) {
1340 mWindowStoppedCallbacks.get(i).windowStopped(stopped);
1341 }
Robert Carr6858bb92018-04-16 11:09:49 -07001342
1343 if (mStopped) {
1344 mSurface.release();
1345 }
Dianne Hackbornce418e62011-03-01 14:31:38 -08001346 }
1347 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001348
George Mount41725de2015-04-09 08:23:05 -07001349 /**
1350 * Block the input events during an Activity Transition. The KEYCODE_BACK event is allowed
1351 * through to allow quick reversal of the Activity Transition.
1352 *
1353 * @param paused true to pause, false to resume.
1354 */
1355 public void setPausedForTransition(boolean paused) {
1356 mPausedForTransition = paused;
1357 }
1358
Craig Mautner8f303ad2013-06-14 11:32:22 -07001359 @Override
Romain Guycfef1232012-02-23 13:50:37 -08001360 public ViewParent getParent() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001361 return null;
1362 }
1363
Craig Mautner8f303ad2013-06-14 11:32:22 -07001364 @Override
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001365 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366 if (child != mView) {
1367 throw new RuntimeException("child is not mine, honest!");
1368 }
1369 // Note: don't apply scroll offset, because we want to know its
1370 // visibility in the virtual canvas being given to the view hierarchy.
1371 return r.intersect(0, 0, mWidth, mHeight);
1372 }
1373
Igor Murashkina86ab6402013-08-30 12:58:36 -07001374 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001375 public void bringChildToFront(View child) {
1376 }
1377
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378 int getHostVisibility() {
Bryce Lee16e50892017-04-11 01:59:37 +00001379 return (mAppVisible || mForceDecorViewVisibility) ? mView.getVisibility() : View.GONE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001380 }
Romain Guy8506ab42009-06-11 17:35:47 -07001381
Chet Haasecca2c982011-05-20 14:34:18 -07001382 /**
1383 * Add LayoutTransition to the list of transitions to be started in the next traversal.
1384 * This list will be cleared after the transitions on the list are start()'ed. These
1385 * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
1386 * happens during the layout phase of traversal, which we want to complete before any of the
1387 * animations are started (because those animations may side-effect properties that layout
1388 * depends upon, like the bounding rectangles of the affected views). So we add the transition
1389 * to the list and it is started just prior to starting the drawing phase of traversal.
1390 *
1391 * @param transition The LayoutTransition to be started on the next traversal.
1392 *
1393 * @hide
1394 */
1395 public void requestTransitionStart(LayoutTransition transition) {
1396 if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
1397 if (mPendingTransitions == null) {
1398 mPendingTransitions = new ArrayList<LayoutTransition>();
1399 }
1400 mPendingTransitions.add(transition);
1401 }
1402 }
1403
John Recka5dda642014-05-22 15:43:54 -07001404 /**
1405 * Notifies the HardwareRenderer that a new frame will be coming soon.
1406 * Currently only {@link ThreadedRenderer} cares about this, and uses
1407 * this knowledge to adjust the scheduling of off-thread animations
1408 */
1409 void notifyRendererOfFramePending() {
Stan Iliev45faba52016-06-28 13:33:15 -04001410 if (mAttachInfo.mThreadedRenderer != null) {
1411 mAttachInfo.mThreadedRenderer.notifyFramePending();
John Recka5dda642014-05-22 15:43:54 -07001412 }
1413 }
1414
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001415 void scheduleTraversals() {
1416 if (!mTraversalScheduled) {
1417 mTraversalScheduled = true;
Jeff Brown3d4e7efe2015-02-26 15:34:16 -08001418 mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001419 mChoreographer.postCallback(
1420 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
Michael Wright9d744c72014-02-18 21:27:42 -08001421 if (!mUnbufferedInputDispatch) {
1422 scheduleConsumeBatchedInput();
1423 }
John Recka5dda642014-05-22 15:43:54 -07001424 notifyRendererOfFramePending();
Jeff Brownc2932a12014-11-20 18:04:05 -08001425 pokeDrawLockIfNeeded();
Jeff Brown96e942d2011-11-30 19:55:01 -08001426 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001427 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001428
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001429 void unscheduleTraversals() {
1430 if (mTraversalScheduled) {
1431 mTraversalScheduled = false;
Jeff Brown3d4e7efe2015-02-26 15:34:16 -08001432 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001433 mChoreographer.removeCallbacks(
1434 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
1435 }
1436 }
1437
1438 void doTraversal() {
1439 if (mTraversalScheduled) {
1440 mTraversalScheduled = false;
Jeff Brown3d4e7efe2015-02-26 15:34:16 -08001441 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001442
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001443 if (mProfile) {
1444 Debug.startMethodTracing("ViewAncestor");
Jeff Brown96e942d2011-11-30 19:55:01 -08001445 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001446
Chris Craike22c59b2015-05-21 18:33:37 -07001447 performTraversals();
Jeff Brown96e942d2011-11-30 19:55:01 -08001448
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001449 if (mProfile) {
1450 Debug.stopMethodTracing();
1451 mProfile = false;
1452 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001453 }
1454 }
1455
Dianne Hackborn9d090892012-06-11 18:35:41 -07001456 private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) {
1457 // Update window's global keep screen on flag: if a view has requested
1458 // that the screen be kept on, then it is always set; otherwise, it is
1459 // set to whatever the client last requested for the global state.
1460 if (mAttachInfo.mKeepScreenOn) {
1461 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
1462 } else {
1463 params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
1464 | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1465 }
1466 }
1467
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001468 private boolean collectViewAttributes() {
Chris Craikd36a81f2014-07-17 10:16:51 -07001469 if (mAttachInfo.mRecomputeGlobalAttributes) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001470 //Log.i(mTag, "Computing view hierarchy attributes!");
Chris Craikd36a81f2014-07-17 10:16:51 -07001471 mAttachInfo.mRecomputeGlobalAttributes = false;
1472 boolean oldScreenOn = mAttachInfo.mKeepScreenOn;
1473 mAttachInfo.mKeepScreenOn = false;
1474 mAttachInfo.mSystemUiVisibility = 0;
1475 mAttachInfo.mHasSystemUiListeners = false;
1476 mView.dispatchCollectViewAttributes(mAttachInfo, 0);
1477 mAttachInfo.mSystemUiVisibility &= ~mAttachInfo.mDisabledSystemUiVisibility;
Craig Mautner7eac0f52012-09-13 13:14:14 -07001478 WindowManager.LayoutParams params = mWindowAttributes;
Chris Craikd36a81f2014-07-17 10:16:51 -07001479 mAttachInfo.mSystemUiVisibility |= getImpliedSystemUiVisibility(params);
1480 if (mAttachInfo.mKeepScreenOn != oldScreenOn
1481 || mAttachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
1482 || mAttachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
Dianne Hackborn9d090892012-06-11 18:35:41 -07001483 applyKeepScreenOnFlag(params);
Chris Craikd36a81f2014-07-17 10:16:51 -07001484 params.subtreeSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
1485 params.hasSystemUiListeners = mAttachInfo.mHasSystemUiListeners;
1486 mView.dispatchWindowSystemUiVisiblityChanged(mAttachInfo.mSystemUiVisibility);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001487 return true;
1488 }
1489 }
1490 return false;
1491 }
1492
John Spurlockbd957402013-10-03 11:38:39 -04001493 private int getImpliedSystemUiVisibility(WindowManager.LayoutParams params) {
1494 int vis = 0;
1495 // Translucent decor window flags imply stable system ui visibility.
1496 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) != 0) {
1497 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
1498 }
1499 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) != 0) {
1500 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
1501 }
1502 return vis;
1503 }
1504
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001505 private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
1506 final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
1507 int childWidthMeasureSpec;
1508 int childHeightMeasureSpec;
1509 boolean windowSizeMayChange = false;
1510
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001511 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(mTag,
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001512 "Measuring " + host + " in display " + desiredWindowWidth
1513 + "x" + desiredWindowHeight + "...");
1514
1515 boolean goodMeasure = false;
1516 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
1517 // On large screens, we don't want to allow dialogs to just
1518 // stretch to fill the entire width of the screen to display
1519 // one line of text. First try doing the layout at a smaller
1520 // size to see if it will fit.
1521 final DisplayMetrics packageMetrics = res.getDisplayMetrics();
1522 res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
1523 int baseSize = 0;
1524 if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
1525 baseSize = (int)mTmpValue.getDimension(packageMetrics);
1526 }
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08001527 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": baseSize=" + baseSize
1528 + ", desiredWindowWidth=" + desiredWindowWidth);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001529 if (baseSize != 0 && desiredWindowWidth > baseSize) {
1530 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
1531 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001532 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001533 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08001534 + host.getMeasuredWidth() + "," + host.getMeasuredHeight()
1535 + ") from width spec: " + MeasureSpec.toString(childWidthMeasureSpec)
1536 + " and height spec: " + MeasureSpec.toString(childHeightMeasureSpec));
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001537 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1538 goodMeasure = true;
1539 } else {
1540 // Didn't fit in that size... try expanding a bit.
1541 baseSize = (baseSize+desiredWindowWidth)/2;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001542 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": next baseSize="
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001543 + baseSize);
1544 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001545 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001546 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001547 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1548 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001549 if (DEBUG_DIALOG) Log.v(mTag, "Good!");
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001550 goodMeasure = true;
1551 }
1552 }
1553 }
1554 }
1555
1556 if (!goodMeasure) {
1557 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
1558 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001559 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001560 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
1561 windowSizeMayChange = true;
1562 }
1563 }
1564
1565 if (DBG) {
1566 System.out.println("======================================");
1567 System.out.println("performTraversals -- after measure");
1568 host.debug();
1569 }
1570
1571 return windowSizeMayChange;
1572 }
1573
Alan Viverettefed3f722013-11-14 14:48:20 -08001574 /**
1575 * Modifies the input matrix such that it maps view-local coordinates to
1576 * on-screen coordinates.
1577 *
1578 * @param m input matrix to modify
1579 */
1580 void transformMatrixToGlobal(Matrix m) {
Dake Gu7bf379c2014-07-15 16:29:38 -07001581 m.preTranslate(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
Alan Viverettefed3f722013-11-14 14:48:20 -08001582 }
1583
1584 /**
1585 * Modifies the input matrix such that it maps on-screen coordinates to
1586 * view-local coordinates.
1587 *
1588 * @param m input matrix to modify
1589 */
1590 void transformMatrixToLocal(Matrix m) {
Dake Gu7bf379c2014-07-15 16:29:38 -07001591 m.postTranslate(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
Alan Viverettefed3f722013-11-14 14:48:20 -08001592 }
1593
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001594 /* package */ WindowInsets getWindowInsets(boolean forceConstruct) {
1595 if (mLastWindowInsets == null || forceConstruct) {
1596 mDispatchContentInsets.set(mAttachInfo.mContentInsets);
1597 mDispatchStableInsets.set(mAttachInfo.mStableInsets);
Adrian Roos5c6b6222017-11-07 17:36:10 +01001598 mDispatchDisplayCutout = mAttachInfo.mDisplayCutout.get();
1599
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001600 Rect contentInsets = mDispatchContentInsets;
1601 Rect stableInsets = mDispatchStableInsets;
Adrian Roos5c6b6222017-11-07 17:36:10 +01001602 DisplayCutout displayCutout = mDispatchDisplayCutout;
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001603 // For dispatch we preserve old logic, but for direct requests from Views we allow to
1604 // immediately use pending insets.
1605 if (!forceConstruct
1606 && (!mPendingContentInsets.equals(contentInsets) ||
Adrian Roos5c6b6222017-11-07 17:36:10 +01001607 !mPendingStableInsets.equals(stableInsets) ||
1608 !mPendingDisplayCutout.get().equals(displayCutout))) {
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001609 contentInsets = mPendingContentInsets;
1610 stableInsets = mPendingStableInsets;
Adrian Roos5c6b6222017-11-07 17:36:10 +01001611 displayCutout = mPendingDisplayCutout.get();
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001612 }
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001613 Rect outsets = mAttachInfo.mOutsets;
1614 if (outsets.left > 0 || outsets.top > 0 || outsets.right > 0 || outsets.bottom > 0) {
1615 contentInsets = new Rect(contentInsets.left + outsets.left,
1616 contentInsets.top + outsets.top, contentInsets.right + outsets.right,
1617 contentInsets.bottom + outsets.bottom);
1618 }
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001619 mLastWindowInsets = new WindowInsets(contentInsets,
Adam Powell01f280d2015-05-18 16:07:42 -07001620 null /* windowDecorInsets */, stableInsets,
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08001621 mContext.getResources().getConfiguration().isScreenRound(),
Adrian Roos5c6b6222017-11-07 17:36:10 +01001622 mAttachInfo.mAlwaysConsumeNavBar, displayCutout);
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001623 }
1624 return mLastWindowInsets;
1625 }
1626
Adam Powell2accbf92014-04-16 23:14:57 +00001627 void dispatchApplyInsets(View host) {
Adrian Roos2b0dcb32017-12-12 16:07:55 +01001628 WindowInsets insets = getWindowInsets(true /* forceConstruct */);
Adrian Roosfa02da62018-01-15 16:01:18 +01001629 final boolean dispatchCutout = (mWindowAttributes.layoutInDisplayCutoutMode
1630 == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS);
1631 if (!dispatchCutout) {
Adrian Roos2b0dcb32017-12-12 16:07:55 +01001632 // Window is either not laid out in cutout or the status bar inset takes care of
1633 // clearing the cutout, so we don't need to dispatch the cutout to the hierarchy.
Adrian Roosd07bafd2017-12-11 17:30:56 +01001634 insets = insets.consumeDisplayCutout();
Adrian Roos2b0dcb32017-12-12 16:07:55 +01001635 }
1636 host.dispatchApplyWindowInsets(insets);
Adam Powell2accbf92014-04-16 23:14:57 +00001637 }
1638
Chong Zhangf6525ce2016-01-14 17:09:56 -08001639 private static boolean shouldUseDisplaySize(final WindowManager.LayoutParams lp) {
1640 return lp.type == TYPE_STATUS_BAR_PANEL
1641 || lp.type == TYPE_INPUT_METHOD
1642 || lp.type == TYPE_VOLUME_OVERLAY;
1643 }
1644
1645 private int dipToPx(int dip) {
1646 final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
1647 return (int) (displayMetrics.density * dip + 0.5f);
1648 }
1649
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001650 private void performTraversals() {
1651 // cache mView since it is used so much below...
1652 final View host = mView;
1653
1654 if (DBG) {
1655 System.out.println("======================================");
1656 System.out.println("performTraversals");
1657 host.debug();
1658 }
1659
1660 if (host == null || !mAdded)
1661 return;
1662
Craig Mautnerdf2390a2012-08-29 20:59:22 -07001663 mIsInTraversal = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001664 mWillDrawSoon = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001665 boolean windowSizeMayChange = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001666 boolean newSurface = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001667 boolean surfaceChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001668 WindowManager.LayoutParams lp = mWindowAttributes;
1669
1670 int desiredWindowWidth;
1671 int desiredWindowHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001672
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001673 final int viewVisibility = getHostVisibility();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001674 final boolean viewVisibilityChanged = !mFirst
Andrii Kulian74b561a2017-08-11 09:06:46 -07001675 && (mViewVisibility != viewVisibility || mNewSurfaceNeeded
1676 // Also check for possible double visibility update, which will make current
1677 // viewVisibility value equal to mViewVisibility and we may miss it.
1678 || mAppVisibilityChanged);
1679 mAppVisibilityChanged = false;
Adam Powell06f9eb82016-08-24 17:09:01 -07001680 final boolean viewUserVisibilityChanged = !mFirst &&
1681 ((mViewVisibility == View.VISIBLE) != (viewVisibility == View.VISIBLE));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001682
1683 WindowManager.LayoutParams params = null;
1684 if (mWindowAttributesChanged) {
1685 mWindowAttributesChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001686 surfaceChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001687 params = lp;
1688 }
Adam Lesinski4ece3d62016-06-16 18:05:41 -07001689 CompatibilityInfo compatibilityInfo =
1690 mDisplay.getDisplayAdjustments().getCompatibilityInfo();
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001691 if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
1692 params = lp;
Jeff Brown96e942d2011-11-30 19:55:01 -08001693 mFullRedrawNeeded = true;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001694 mLayoutRequested = true;
1695 if (mLastInCompatMode) {
Adam Lesinski95c42972013-10-02 10:13:27 -07001696 params.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001697 mLastInCompatMode = false;
1698 } else {
Adam Lesinski95c42972013-10-02 10:13:27 -07001699 params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001700 mLastInCompatMode = true;
1701 }
1702 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001703
Romain Guyf21c9b02011-09-06 16:56:54 -07001704 mWindowAttributesChangesFlag = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -07001705
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001706 Rect frame = mWinFrame;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001707 if (mFirst) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001708 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001709 mLayoutRequested = true;
1710
Andrii Kulian44607962017-03-16 11:06:24 -07001711 final Configuration config = mContext.getResources().getConfiguration();
Chong Zhangf6525ce2016-01-14 17:09:56 -08001712 if (shouldUseDisplaySize(lp)) {
Dianne Hackborna239c842011-06-01 12:28:20 -07001713 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001714 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001715 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001716 desiredWindowWidth = size.x;
1717 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001718 } else {
Adrian Roos9e370f22018-03-06 18:19:45 +01001719 desiredWindowWidth = mWinFrame.width();
1720 desiredWindowHeight = mWinFrame.height();
Dianne Hackborna239c842011-06-01 12:28:20 -07001721 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001722
Romain Guyc5d55862011-01-21 19:01:46 -08001723 // We used to use the following condition to choose 32 bits drawing caches:
1724 // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
1725 // However, windows are now always 32 bits by default, so choose 32 bits
Chris Craikd36a81f2014-07-17 10:16:51 -07001726 mAttachInfo.mUse32BitDrawingCache = true;
1727 mAttachInfo.mHasWindowFocus = false;
1728 mAttachInfo.mWindowVisibility = viewVisibility;
1729 mAttachInfo.mRecomputeGlobalAttributes = false;
Andrii Kulian44607962017-03-16 11:06:24 -07001730 mLastConfigurationFromResources.setTo(config);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001731 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Fabrice Di Megliob003e282012-10-17 17:20:19 -07001732 // Set the layout direction if it has not been set before (inherit is the default)
1733 if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
Andrii Kulian44607962017-03-16 11:06:24 -07001734 host.setLayoutDirection(config.getLayoutDirection());
Fabrice Di Megliob003e282012-10-17 17:20:19 -07001735 }
Chris Craikd36a81f2014-07-17 10:16:51 -07001736 host.dispatchAttachedToWindow(mAttachInfo, 0);
1737 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
Adam Powell2accbf92014-04-16 23:14:57 +00001738 dispatchApplyInsets(host);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001739 } else {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001740 desiredWindowWidth = frame.width();
1741 desiredWindowHeight = frame.height();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001743 if (DEBUG_ORIENTATION) Log.v(mTag, "View " + host + " resized to: " + frame);
Jeff Brown96e942d2011-11-30 19:55:01 -08001744 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001745 mLayoutRequested = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001746 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001747 }
1748 }
1749
1750 if (viewVisibilityChanged) {
Bryce Lee16e50892017-04-11 01:59:37 +00001751 mAttachInfo.mWindowVisibility = viewVisibility;
1752 host.dispatchWindowVisibilityChanged(viewVisibility);
Adam Powell06f9eb82016-08-24 17:09:01 -07001753 if (viewUserVisibilityChanged) {
Adam Powell64e1ba42016-08-22 09:09:44 -07001754 host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE);
1755 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001756 if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
Skuhneb8160872015-09-22 09:51:39 -07001757 endDragResizing();
Romain Guy65b345f2011-07-27 18:51:50 -07001758 destroyHardwareResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001759 }
1760 if (viewVisibility == View.GONE) {
1761 // After making a window gone, we will count it as being
1762 // shown for the first time the next time it gets focus.
1763 mHasHadWindowFocus = false;
1764 }
1765 }
1766
Alan Viverette7dbc3bf2015-01-28 16:14:36 -08001767 // Non-visible windows can't hold accessibility focus.
1768 if (mAttachInfo.mWindowVisibility != View.VISIBLE) {
1769 host.clearAccessibilityFocus();
1770 }
1771
Chet Haaseb78c2842012-04-19 13:39:50 -07001772 // Execute enqueued actions on every traversal in case a detached view enqueued an action
Chris Craikd36a81f2014-07-17 10:16:51 -07001773 getRunQueue().executeActions(mAttachInfo.mHandler);
Chet Haaseb78c2842012-04-19 13:39:50 -07001774
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001775 boolean insetsChanged = false;
Romain Guy8506ab42009-06-11 17:35:47 -07001776
Craig Mautner72d6f212015-02-19 16:33:09 -08001777 boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001778 if (layoutRequested) {
Romain Guy15df6702009-08-17 20:17:30 -07001779
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001780 final Resources res = mView.getContext().getResources();
1781
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001782 if (mFirst) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001783 // make sure touch mode code executes by setting cached value
1784 // to opposite of the added touch mode.
1785 mAttachInfo.mInTouchMode = !mAddedTouchMode;
Romain Guy2d4cff62010-04-09 15:39:00 -07001786 ensureTouchModeLocally(mAddedTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001787 } else {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001788 if (!mPendingOverscanInsets.equals(mAttachInfo.mOverscanInsets)) {
1789 insetsChanged = true;
1790 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001791 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001792 insetsChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001793 }
Adrian Roosfa104232014-06-20 16:10:14 -07001794 if (!mPendingStableInsets.equals(mAttachInfo.mStableInsets)) {
1795 insetsChanged = true;
1796 }
Adrian Roos5c6b6222017-11-07 17:36:10 +01001797 if (!mPendingDisplayCutout.equals(mAttachInfo.mDisplayCutout)) {
1798 insetsChanged = true;
1799 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001800 if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001801 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001802 if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001803 + mAttachInfo.mVisibleInsets);
1804 }
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001805 if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) {
1806 insetsChanged = true;
1807 }
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08001808 if (mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar) {
1809 insetsChanged = true;
1810 }
Chong Zhangf6525ce2016-01-14 17:09:56 -08001811 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
1812 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001813 windowSizeMayChange = true;
Chong Zhangf6525ce2016-01-14 17:09:56 -08001814
1815 if (shouldUseDisplaySize(lp)) {
1816 // NOTE -- system code, won't try to do compat mode.
1817 Point size = new Point();
1818 mDisplay.getRealSize(size);
1819 desiredWindowWidth = size.x;
1820 desiredWindowHeight = size.y;
1821 } else {
1822 Configuration config = res.getConfiguration();
1823 desiredWindowWidth = dipToPx(config.screenWidthDp);
1824 desiredWindowHeight = dipToPx(config.screenHeightDp);
1825 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001826 }
1827 }
1828
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001829 // Ask host how big it wants to be
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001830 windowSizeMayChange |= measureHierarchy(host, lp, res,
1831 desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001832 }
1833
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001834 if (collectViewAttributes()) {
1835 params = lp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001836 }
Chris Craikd36a81f2014-07-17 10:16:51 -07001837 if (mAttachInfo.mForceReportNewAttributes) {
1838 mAttachInfo.mForceReportNewAttributes = false;
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001839 params = lp;
1840 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001841
Chris Craikd36a81f2014-07-17 10:16:51 -07001842 if (mFirst || mAttachInfo.mViewVisibilityChanged) {
1843 mAttachInfo.mViewVisibilityChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001844 int resizeMode = mSoftInputMode &
1845 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
1846 // If we are in auto resize mode, then we need to determine
1847 // what mode to use now.
1848 if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001849 final int N = mAttachInfo.mScrollContainers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850 for (int i=0; i<N; i++) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001851 if (mAttachInfo.mScrollContainers.get(i).isShown()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001852 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
1853 }
1854 }
1855 if (resizeMode == 0) {
1856 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
1857 }
1858 if ((lp.softInputMode &
1859 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
1860 lp.softInputMode = (lp.softInputMode &
1861 ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
1862 resizeMode;
1863 params = lp;
1864 }
1865 }
1866 }
Romain Guy8506ab42009-06-11 17:35:47 -07001867
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001868 if (params != null) {
1869 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
1870 if (!PixelFormat.formatHasAlpha(params.format)) {
1871 params.format = PixelFormat.TRANSLUCENT;
1872 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001873 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001874 mAttachInfo.mOverscanRequested = (params.flags
1875 & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876 }
1877
Adrian Roosfa104232014-06-20 16:10:14 -07001878 if (mApplyInsetsRequested) {
1879 mApplyInsetsRequested = false;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001880 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Adam Powell2accbf92014-04-16 23:14:57 +00001881 dispatchApplyInsets(host);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001882 if (mLayoutRequested) {
1883 // Short-circuit catching a new layout request here, so
1884 // we don't need to go through two layout passes when things
1885 // change due to fitting system windows, which can happen a lot.
1886 windowSizeMayChange |= measureHierarchy(host, lp,
1887 mView.getContext().getResources(),
1888 desiredWindowWidth, desiredWindowHeight);
1889 }
1890 }
1891
1892 if (layoutRequested) {
1893 // Clear this now, so that if anything requests a layout in the
1894 // rest of this function we will catch it and re-run a full
1895 // layout pass.
1896 mLayoutRequested = false;
1897 }
1898
1899 boolean windowShouldResize = layoutRequested && windowSizeMayChange
Dianne Hackborn189ee182010-12-02 21:48:53 -08001900 && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
Romain Guy2e4f4262010-04-06 11:07:52 -07001901 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
1902 frame.width() < desiredWindowWidth && frame.width() != mWidth)
1903 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
1904 frame.height() < desiredWindowHeight && frame.height() != mHeight));
Jorim Jaggi4846ee32016-01-07 17:39:12 +01001905 windowShouldResize |= mDragResizing && mResizeMode == RESIZE_MODE_FREEFORM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001906
Jorim Jaggi4846ee32016-01-07 17:39:12 +01001907 // If the activity was just relaunched, it might have unfrozen the task bounds (while
1908 // relaunching), so we need to force a call into window manager to pick up the latest
1909 // bounds.
1910 windowShouldResize |= mActivityRelaunched;
1911
Jeff Brown2e05ec32013-09-30 15:57:43 -07001912 // Determine whether to compute insets.
1913 // If there are no inset listeners remaining then we may still need to compute
1914 // insets in case the old insets were non-empty and must be reset.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001915 final boolean computesInternalInsets =
Chris Craikd36a81f2014-07-17 10:16:51 -07001916 mAttachInfo.mTreeObserver.hasComputeInternalInsetsListeners()
1917 || mAttachInfo.mHasNonEmptyGivenInternalInsets;
Romain Guy812ccbe2010-06-01 14:07:24 -07001918
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001919 boolean insetsPending = false;
1920 int relayoutResult = 0;
Chet Haased86fb2c2016-05-04 07:26:02 -07001921 boolean updatedConfiguration = false;
Romain Guy812ccbe2010-06-01 14:07:24 -07001922
Robert Carrb2594852016-04-25 16:21:13 -07001923 final int surfaceGenerationId = mSurface.getGenerationId();
1924
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08001925 final boolean isViewVisible = viewVisibility == View.VISIBLE;
Andrii Kulianb2e37802017-01-11 00:36:44 -08001926 final boolean windowRelayoutWasForced = mForceNextWindowRelayout;
Bryce Lee46b01652017-06-07 23:01:56 +00001927 if (mFirst || windowShouldResize || insetsChanged ||
1928 viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
Jorim Jaggia4a58ef2016-01-27 02:10:08 -08001929 mForceNextWindowRelayout = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001930
Alan Viverette64bf97a2015-09-18 16:42:00 -04001931 if (isViewVisible) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001932 // If this window is giving internal insets to the window
1933 // manager, and it is being added or changing its visibility,
1934 // then we want to first give the window manager "fake"
1935 // insets to cause it to effectively ignore the content of
1936 // the window during layout. This avoids it briefly causing
1937 // other windows to resize/move based on the raw frame of the
1938 // window, waiting until we can finish laying out this window
1939 // and get back to the window manager with the ultimately
1940 // computed insets.
Romain Guy812ccbe2010-06-01 14:07:24 -07001941 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001942 }
1943
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001944 if (mSurfaceHolder != null) {
1945 mSurfaceHolder.mSurfaceLock.lock();
1946 mDrawingAllowed = true;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001947 }
Romain Guy812ccbe2010-06-01 14:07:24 -07001948
Romain Guyc361da82010-10-25 15:29:10 -07001949 boolean hwInitialized = false;
Chong Zhang75eccbd2016-07-12 19:25:08 -07001950 boolean contentInsetsChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001951 boolean hadSurface = mSurface.isValid();
Romain Guy812ccbe2010-06-01 14:07:24 -07001952
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001953 try {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001954 if (DEBUG_LAYOUT) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001955 Log.i(mTag, "host=w:" + host.getMeasuredWidth() + ", h:" +
Dianne Hackborn189ee182010-12-02 21:48:53 -08001956 host.getMeasuredHeight() + ", params=" + params);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001957 }
Romain Guy2a83f002011-01-18 18:28:21 -08001958
Stan Iliev45faba52016-06-28 13:33:15 -04001959 if (mAttachInfo.mThreadedRenderer != null) {
John Reckf7d9c1d2014-04-09 10:01:03 -07001960 // relayoutWindow may decide to destroy mSurface. As that decision
1961 // happens in WindowManager service, we need to be defensive here
1962 // and stop using the surface in case it gets destroyed.
Stan Iliev45faba52016-06-28 13:33:15 -04001963 if (mAttachInfo.mThreadedRenderer.pauseSurface(mSurface)) {
John Reck01a5ea32014-12-03 13:01:07 -08001964 // Animations were running so we need to push a frame
1965 // to resume them
1966 mDirty.set(0, 0, mWidth, mHeight);
1967 }
John Reckba6adf62015-02-19 14:36:50 -08001968 mChoreographer.mFrameInfo.addFlags(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED);
John Reckf7d9c1d2014-04-09 10:01:03 -07001969 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001970 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
1971
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001972 if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001973 + " overscan=" + mPendingOverscanInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001974 + " content=" + mPendingContentInsets.toShortString()
1975 + " visible=" + mPendingVisibleInsets.toShortString()
Adrian Roos5c6b6222017-11-07 17:36:10 +01001976 + " stable=" + mPendingStableInsets.toShortString()
1977 + " cutout=" + mPendingDisplayCutout.get().toString()
Filip Gruszczynski0ec13282015-06-25 11:26:01 -07001978 + " outsets=" + mPendingOutsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001979 + " surface=" + mSurface);
Romain Guy8506ab42009-06-11 17:35:47 -07001980
Bryce Leef858b572017-06-29 14:03:33 -07001981 // If the pending {@link MergedConfiguration} handed back from
1982 // {@link #relayoutWindow} does not match the one last reported,
1983 // WindowManagerService has reported back a frame from a configuration not yet
1984 // handled by the client. In this case, we need to accept the configuration so we
1985 // do not lay out and draw with the wrong configuration.
1986 if (!mPendingMergedConfiguration.equals(mLastReportedMergedConfiguration)) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001987 if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: "
Bryce Leef858b572017-06-29 14:03:33 -07001988 + mPendingMergedConfiguration.getMergedConfiguration());
Andrii Kulian44607962017-03-16 11:06:24 -07001989 performConfigurationChange(mPendingMergedConfiguration, !mFirst,
1990 INVALID_DISPLAY /* same display */);
Chet Haased86fb2c2016-05-04 07:26:02 -07001991 updatedConfiguration = true;
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001992 }
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001993
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001994 final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
1995 mAttachInfo.mOverscanInsets);
Chong Zhang75eccbd2016-07-12 19:25:08 -07001996 contentInsetsChanged = !mPendingContentInsets.equals(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001997 mAttachInfo.mContentInsets);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001998 final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001999 mAttachInfo.mVisibleInsets);
Adrian Roosfa104232014-06-20 16:10:14 -07002000 final boolean stableInsetsChanged = !mPendingStableInsets.equals(
2001 mAttachInfo.mStableInsets);
Adrian Roos5c6b6222017-11-07 17:36:10 +01002002 final boolean cutoutChanged = !mPendingDisplayCutout.equals(
2003 mAttachInfo.mDisplayCutout);
Filip Gruszczynski2217f612015-05-26 11:32:08 -07002004 final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets);
Chong Zhangf4abc2b2015-11-12 23:40:58 -08002005 final boolean surfaceSizeChanged = (relayoutResult
2006 & WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
Adrian Roosdcf50a4f2018-01-29 18:31:34 +01002007 surfaceChanged |= surfaceSizeChanged;
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08002008 final boolean alwaysConsumeNavBarChanged =
2009 mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002010 if (contentInsetsChanged) {
2011 mAttachInfo.mContentInsets.set(mPendingContentInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002012 if (DEBUG_LAYOUT) Log.v(mTag, "Content insets changing to: "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002013 + mAttachInfo.mContentInsets);
2014 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08002015 if (overscanInsetsChanged) {
2016 mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002017 if (DEBUG_LAYOUT) Log.v(mTag, "Overscan insets changing to: "
Dianne Hackbornc4aad012013-02-22 15:05:25 -08002018 + mAttachInfo.mOverscanInsets);
2019 // Need to relayout with content insets.
2020 contentInsetsChanged = true;
2021 }
Adrian Roosfa104232014-06-20 16:10:14 -07002022 if (stableInsetsChanged) {
2023 mAttachInfo.mStableInsets.set(mPendingStableInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002024 if (DEBUG_LAYOUT) Log.v(mTag, "Decor insets changing to: "
Adrian Roosfa104232014-06-20 16:10:14 -07002025 + mAttachInfo.mStableInsets);
2026 // Need to relayout with content insets.
2027 contentInsetsChanged = true;
2028 }
Adrian Roos5c6b6222017-11-07 17:36:10 +01002029 if (cutoutChanged) {
2030 mAttachInfo.mDisplayCutout.set(mPendingDisplayCutout);
2031 if (DEBUG_LAYOUT) {
2032 Log.v(mTag, "DisplayCutout changing to: " + mAttachInfo.mDisplayCutout);
2033 }
2034 // Need to relayout with content insets.
2035 contentInsetsChanged = true;
2036 }
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08002037 if (alwaysConsumeNavBarChanged) {
2038 mAttachInfo.mAlwaysConsumeNavBar = mPendingAlwaysConsumeNavBar;
2039 contentInsetsChanged = true;
2040 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002041 if (contentInsetsChanged || mLastSystemUiVisibility !=
Adrian Roosfa104232014-06-20 16:10:14 -07002042 mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested
Filip Gruszczynski2217f612015-05-26 11:32:08 -07002043 || mLastOverscanRequested != mAttachInfo.mOverscanRequested
2044 || outsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002045 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08002046 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Filip Gruszczynski2217f612015-05-26 11:32:08 -07002047 mAttachInfo.mOutsets.set(mPendingOutsets);
Adrian Roosfa104232014-06-20 16:10:14 -07002048 mApplyInsetsRequested = false;
Adam Powell2accbf92014-04-16 23:14:57 +00002049 dispatchApplyInsets(host);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002050 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002051 if (visibleInsetsChanged) {
2052 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002053 if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 + mAttachInfo.mVisibleInsets);
2055 }
2056
2057 if (!hadSurface) {
2058 if (mSurface.isValid()) {
2059 // If we are creating a new surface, then we need to
2060 // completely redraw it. Also, when we get to the
2061 // point of drawing it we will hold off and schedule
2062 // a new traversal instead. This is so we can tell the
2063 // window manager about all of the windows being displayed
2064 // before actually drawing them, so it can display then
2065 // all at once.
2066 newSurface = true;
Jeff Brown96e942d2011-11-30 19:55:01 -08002067 mFullRedrawNeeded = true;
Jack Palevich61a6e682009-10-09 17:37:50 -07002068 mPreviousTransparentRegion.setEmpty();
Romain Guy8506ab42009-06-11 17:35:47 -07002069
John Reck63005e62015-05-19 15:00:13 -07002070 // Only initialize up-front if transparent regions are not
2071 // requested, otherwise defer to see if the entire window
2072 // will be transparent
Stan Iliev45faba52016-06-28 13:33:15 -04002073 if (mAttachInfo.mThreadedRenderer != null) {
Dianne Hackborn64825172011-03-02 21:32:58 -08002074 try {
Stan Iliev45faba52016-06-28 13:33:15 -04002075 hwInitialized = mAttachInfo.mThreadedRenderer.initialize(
John Reck79d81e62013-11-05 13:26:57 -08002076 mSurface);
John Reck63005e62015-05-19 15:00:13 -07002077 if (hwInitialized && (host.mPrivateFlags
2078 & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
2079 // Don't pre-allocate if transparent regions
2080 // are requested as they may not be needed
2081 mSurface.allocateBuffers();
2082 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07002083 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002084 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08002085 return;
2086 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002087 }
2088 }
2089 } else if (!mSurface.isValid()) {
2090 // If the surface has been removed, then reset the scroll
2091 // positions.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002092 if (mLastScrolledFocus != null) {
2093 mLastScrolledFocus.clear();
2094 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002095 mScrollY = mCurScrollY = 0;
Adrian Roos0e7ae4e2014-10-01 15:33:22 +02002096 if (mView instanceof RootViewSurfaceTaker) {
2097 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
2098 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002099 if (mScroller != null) {
2100 mScroller.abortAnimation();
2101 }
Romain Guy1d0c7082011-08-03 16:22:24 -07002102 // Our surface is gone
Stan Iliev45faba52016-06-28 13:33:15 -04002103 if (mAttachInfo.mThreadedRenderer != null &&
2104 mAttachInfo.mThreadedRenderer.isEnabled()) {
2105 mAttachInfo.mThreadedRenderer.destroy();
Romain Guy1d0c7082011-08-03 16:22:24 -07002106 }
Chong Zhangf4abc2b2015-11-12 23:40:58 -08002107 } else if ((surfaceGenerationId != mSurface.getGenerationId()
Andrii Kulianb2e37802017-01-11 00:36:44 -08002108 || surfaceSizeChanged || windowRelayoutWasForced)
Chong Zhangf4abc2b2015-11-12 23:40:58 -08002109 && mSurfaceHolder == null
Stan Iliev45faba52016-06-28 13:33:15 -04002110 && mAttachInfo.mThreadedRenderer != null) {
Jeff Brown96e942d2011-11-30 19:55:01 -08002111 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08002112 try {
Chong Zhangf4abc2b2015-11-12 23:40:58 -08002113 // Need to do updateSurface (which leads to CanvasContext::setSurface and
2114 // re-create the EGLSurface) if either the Surface changed (as indicated by
2115 // generation id), or WindowManager changed the surface size. The latter is
2116 // because on some chips, changing the consumer side's BufferQueue size may
2117 // not take effect immediately unless we create a new EGLSurface.
2118 // Note that frame size change doesn't always imply surface size change (eg.
2119 // drag resizing uses fullscreen surface), need to check surfaceSizeChanged
2120 // flag from WindowManager.
Stan Iliev45faba52016-06-28 13:33:15 -04002121 mAttachInfo.mThreadedRenderer.updateSurface(mSurface);
Igor Murashkina86ab6402013-08-30 12:58:36 -07002122 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002123 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08002124 return;
2125 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002126 }
Chong Zhang0275e392015-09-17 10:41:44 -07002127
Jorim Jaggi4846ee32016-01-07 17:39:12 +01002128 final boolean freeformResizing = (relayoutResult
2129 & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFORM) != 0;
2130 final boolean dockedResizing = (relayoutResult
2131 & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_DOCKED) != 0;
2132 final boolean dragResizing = freeformResizing || dockedResizing;
Chong Zhang0275e392015-09-17 10:41:44 -07002133 if (mDragResizing != dragResizing) {
Skuhneb8160872015-09-22 09:51:39 -07002134 if (dragResizing) {
Jorim Jaggi4846ee32016-01-07 17:39:12 +01002135 mResizeMode = freeformResizing
2136 ? RESIZE_MODE_FREEFORM
2137 : RESIZE_MODE_DOCKED_DIVIDER;
Adrian Roos5c6b6222017-11-07 17:36:10 +01002138 // TODO: Need cutout?
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002139 startDragResizing(mPendingBackDropFrame,
2140 mWinFrame.equals(mPendingBackDropFrame), mPendingVisibleInsets,
2141 mPendingStableInsets, mResizeMode);
Skuhneb8160872015-09-22 09:51:39 -07002142 } else {
2143 // We shouldn't come here, but if we come we should end the resize.
2144 endDragResizing();
2145 }
Chong Zhang0275e392015-09-17 10:41:44 -07002146 }
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09002147 if (!mUseMTRenderer) {
Skuhneb8160872015-09-22 09:51:39 -07002148 if (dragResizing) {
2149 mCanvasOffsetX = mWinFrame.left;
2150 mCanvasOffsetY = mWinFrame.top;
2151 } else {
2152 mCanvasOffsetX = mCanvasOffsetY = 0;
2153 }
Chong Zhang0275e392015-09-17 10:41:44 -07002154 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002155 } catch (RemoteException e) {
2156 }
Romain Guy1d0c7082011-08-03 16:22:24 -07002157
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002158 if (DEBUG_ORIENTATION) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07002159 TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002160
Chris Craikd36a81f2014-07-17 10:16:51 -07002161 mAttachInfo.mWindowLeft = frame.left;
2162 mAttachInfo.mWindowTop = frame.top;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002163
2164 // !!FIXME!! This next section handles the case where we did not get the
2165 // window size we asked for. We should avoid this by getting a maximum size from
2166 // the window session beforehand.
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07002167 if (mWidth != frame.width() || mHeight != frame.height()) {
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07002168 mWidth = frame.width();
2169 mHeight = frame.height();
2170 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002171
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002172 if (mSurfaceHolder != null) {
2173 // The app owns the surface; tell it about what is going on.
2174 if (mSurface.isValid()) {
2175 // XXX .copyFrom() doesn't work!
2176 //mSurfaceHolder.mSurface.copyFrom(mSurface);
2177 mSurfaceHolder.mSurface = mSurface;
2178 }
Jeff Brown30bc34f2011-01-25 12:56:56 -08002179 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002180 mSurfaceHolder.mSurfaceLock.unlock();
2181 if (mSurface.isValid()) {
John Reck208c47c2016-06-09 16:26:21 -07002182 if (!hadSurface) {
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002183 mSurfaceHolder.ungetCallbacks();
2184
2185 mIsCreating = true;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002186 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
2187 if (callbacks != null) {
2188 for (SurfaceHolder.Callback c : callbacks) {
2189 c.surfaceCreated(mSurfaceHolder);
2190 }
2191 }
2192 surfaceChanged = true;
2193 }
John Reck208c47c2016-06-09 16:26:21 -07002194 if (surfaceChanged || surfaceGenerationId != mSurface.getGenerationId()) {
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002195 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
2196 if (callbacks != null) {
2197 for (SurfaceHolder.Callback c : callbacks) {
2198 c.surfaceChanged(mSurfaceHolder, lp.format,
2199 mWidth, mHeight);
2200 }
2201 }
2202 }
2203 mIsCreating = false;
2204 } else if (hadSurface) {
2205 mSurfaceHolder.ungetCallbacks();
2206 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002207 if (callbacks != null) {
2208 for (SurfaceHolder.Callback c : callbacks) {
2209 c.surfaceDestroyed(mSurfaceHolder);
2210 }
2211 }
2212 mSurfaceHolder.mSurfaceLock.lock();
Jozef BABJAK93c5b6a2011-02-22 09:33:19 +01002213 try {
2214 mSurfaceHolder.mSurface = new Surface();
2215 } finally {
2216 mSurfaceHolder.mSurfaceLock.unlock();
2217 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002218 }
2219 }
Romain Guy53389bd2010-09-07 17:16:32 -07002220
Stan Iliev45faba52016-06-28 13:33:15 -04002221 final ThreadedRenderer threadedRenderer = mAttachInfo.mThreadedRenderer;
2222 if (threadedRenderer != null && threadedRenderer.isEnabled()) {
Alan Viverette50210d92015-05-14 18:05:36 -07002223 if (hwInitialized
Stan Iliev45faba52016-06-28 13:33:15 -04002224 || mWidth != threadedRenderer.getWidth()
2225 || mHeight != threadedRenderer.getHeight()
2226 || mNeedsRendererSetup) {
2227 threadedRenderer.setup(mWidth, mHeight, mAttachInfo,
Alan Viverette50210d92015-05-14 18:05:36 -07002228 mWindowAttributes.surfaceInsets);
Stan Iliev45faba52016-06-28 13:33:15 -04002229 mNeedsRendererSetup = false;
Romain Guy03985752011-07-11 15:33:51 -07002230 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002231 }
2232
Craig Mautner72d6f212015-02-19 16:33:09 -08002233 if (!mStopped || mReportNextDraw) {
Dianne Hackbornce418e62011-03-01 14:31:38 -08002234 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
Jeff Brown98365d72012-08-19 20:30:52 -07002235 (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
Dianne Hackbornce418e62011-03-01 14:31:38 -08002236 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
Chong Zhang75eccbd2016-07-12 19:25:08 -07002237 || mHeight != host.getMeasuredHeight() || contentInsetsChanged ||
Chet Haased86fb2c2016-05-04 07:26:02 -07002238 updatedConfiguration) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002239 int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
2240 int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
Igor Murashkina86ab6402013-08-30 12:58:36 -07002241
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002242 if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed! mWidth="
Dianne Hackbornce418e62011-03-01 14:31:38 -08002243 + mWidth + " measuredWidth=" + host.getMeasuredWidth()
2244 + " mHeight=" + mHeight
2245 + " measuredHeight=" + host.getMeasuredHeight()
Chong Zhang75eccbd2016-07-12 19:25:08 -07002246 + " coveredInsetsChanged=" + contentInsetsChanged);
Igor Murashkina86ab6402013-08-30 12:58:36 -07002247
Dianne Hackbornce418e62011-03-01 14:31:38 -08002248 // Ask host how big it wants to be
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002249 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Igor Murashkina86ab6402013-08-30 12:58:36 -07002250
Dianne Hackbornce418e62011-03-01 14:31:38 -08002251 // Implementation of weights from WindowManager.LayoutParams
2252 // We just grow the dimensions as needed and re-measure if
2253 // needs be
2254 int width = host.getMeasuredWidth();
2255 int height = host.getMeasuredHeight();
2256 boolean measureAgain = false;
Igor Murashkina86ab6402013-08-30 12:58:36 -07002257
Dianne Hackbornce418e62011-03-01 14:31:38 -08002258 if (lp.horizontalWeight > 0.0f) {
2259 width += (int) ((mWidth - width) * lp.horizontalWeight);
2260 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
2261 MeasureSpec.EXACTLY);
2262 measureAgain = true;
2263 }
2264 if (lp.verticalWeight > 0.0f) {
2265 height += (int) ((mHeight - height) * lp.verticalWeight);
2266 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
2267 MeasureSpec.EXACTLY);
2268 measureAgain = true;
2269 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07002270
Dianne Hackbornce418e62011-03-01 14:31:38 -08002271 if (measureAgain) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002272 if (DEBUG_LAYOUT) Log.v(mTag,
Dianne Hackbornce418e62011-03-01 14:31:38 -08002273 "And hey let's measure once more: width=" + width
2274 + " height=" + height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002275 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackbornce418e62011-03-01 14:31:38 -08002276 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07002277
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002278 layoutRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002279 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002280 }
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07002281 } else {
2282 // Not the first pass and no window/insets/visibility change but the window
2283 // may have moved and we need check that and if so to update the left and right
2284 // in the attach info. We translate only the window frame since on window move
2285 // the window manager tells us only for the new frame but the insets are the
2286 // same and we do not want to translate them more than once.
Jorim Jaggi2e95a482016-01-14 17:36:55 -08002287 maybeHandleWindowMove(frame);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002288 }
2289
Craig Mautner72d6f212015-02-19 16:33:09 -08002290 final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002291 boolean triggerGlobalLayoutListener = didLayout
Chris Craikd36a81f2014-07-17 10:16:51 -07002292 || mAttachInfo.mRecomputeGlobalAttributes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002293 if (didLayout) {
Jorim Jaggi26d02d22016-02-24 18:37:51 -05002294 performLayout(lp, mWidth, mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002295
Mathias Agopian54e3d3842013-04-12 15:13:12 -07002296 // By this point all views have been sized and positioned
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002297 // We can compute the transparent area
2298
Dianne Hackborn4702a852012-08-17 15:18:29 -07002299 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002300 // start out transparent
2301 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
2302 host.getLocationInWindow(mTmpLocation);
2303 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
2304 mTmpLocation[0] + host.mRight - host.mLeft,
2305 mTmpLocation[1] + host.mBottom - host.mTop);
2306
2307 host.gatherTransparentRegion(mTransparentRegion);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07002308 if (mTranslator != null) {
2309 mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
2310 }
2311
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002312 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
2313 mPreviousTransparentRegion.set(mTransparentRegion);
Mathias Agopian54e3d3842013-04-12 15:13:12 -07002314 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002315 // reconfigure window manager
2316 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002317 mWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002318 } catch (RemoteException e) {
2319 }
2320 }
2321 }
2322
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002323 if (DBG) {
2324 System.out.println("======================================");
Chet Haase4610eef2015-12-03 07:38:11 -08002325 System.out.println("performTraversals -- after setFrame");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002326 host.debug();
2327 }
2328 }
2329
2330 if (triggerGlobalLayoutListener) {
Chris Craikd36a81f2014-07-17 10:16:51 -07002331 mAttachInfo.mRecomputeGlobalAttributes = false;
2332 mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002333 }
2334
2335 if (computesInternalInsets) {
Jeff Brownfbf09772011-01-16 14:06:57 -08002336 // Clear the original insets.
Chris Craikd36a81f2014-07-17 10:16:51 -07002337 final ViewTreeObserver.InternalInsetsInfo insets = mAttachInfo.mGivenInternalInsets;
Jeff Brownfbf09772011-01-16 14:06:57 -08002338 insets.reset();
2339
2340 // Compute new insets in place.
Chris Craikd36a81f2014-07-17 10:16:51 -07002341 mAttachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
2342 mAttachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty();
Jeff Brownfbf09772011-01-16 14:06:57 -08002343
2344 // Tell the window manager.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002345 if (insetsPending || !mLastGivenInsets.equals(insets)) {
2346 mLastGivenInsets.set(insets);
Jeff Brownfbf09772011-01-16 14:06:57 -08002347
2348 // Translate insets to screen coordinates if needed.
2349 final Rect contentInsets;
2350 final Rect visibleInsets;
2351 final Region touchableRegion;
2352 if (mTranslator != null) {
2353 contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
2354 visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
2355 touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
2356 } else {
2357 contentInsets = insets.contentInsets;
2358 visibleInsets = insets.visibleInsets;
2359 touchableRegion = insets.touchableRegion;
2360 }
2361
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002362 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002363 mWindowSession.setInsets(mWindow, insets.mTouchableInsets,
Jeff Brownfbf09772011-01-16 14:06:57 -08002364 contentInsets, visibleInsets, touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002365 } catch (RemoteException e) {
2366 }
2367 }
2368 }
Romain Guy8506ab42009-06-11 17:35:47 -07002369
Evan Roskyadf5bec2017-10-19 10:24:07 -07002370 if (mFirst) {
Evan Roskybdc66cb2017-09-08 14:27:24 -07002371 if (sAlwaysAssignFocus || !isInTouchMode()) {
Evan Roskyadf5bec2017-10-19 10:24:07 -07002372 // handle first focus request
2373 if (DEBUG_INPUT_RESIZE) {
2374 Log.v(mTag, "First: mView.hasFocus()=" + mView.hasFocus());
2375 }
2376 if (mView != null) {
2377 if (!mView.hasFocus()) {
2378 mView.restoreDefaultFocus();
2379 if (DEBUG_INPUT_RESIZE) {
2380 Log.v(mTag, "First: requested focused view=" + mView.findFocus());
2381 }
2382 } else {
2383 if (DEBUG_INPUT_RESIZE) {
2384 Log.v(mTag, "First: existing focused view=" + mView.findFocus());
2385 }
2386 }
2387 }
2388 } else {
2389 // Some views (like ScrollView) won't hand focus to descendants that aren't within
2390 // their viewport. Before layout, there's a good change these views are size 0
2391 // which means no children can get focus. After layout, this view now has size, but
2392 // is not guaranteed to hand-off focus to a focusable child (specifically, the edge-
2393 // case where the child has a size prior to layout and thus won't trigger
2394 // focusableViewAvailable).
2395 View focused = mView.findFocus();
2396 if (focused instanceof ViewGroup
2397 && ((ViewGroup) focused).getDescendantFocusability()
2398 == ViewGroup.FOCUS_AFTER_DESCENDANTS) {
2399 focused.restoreDefaultFocus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002400 }
2401 }
2402 }
2403
Alan Viverette64bf97a2015-09-18 16:42:00 -04002404 final boolean changedVisibility = (viewVisibilityChanged || mFirst) && isViewVisible;
2405 final boolean hasWindowFocus = mAttachInfo.mHasWindowFocus && isViewVisible;
2406 final boolean regainedFocus = hasWindowFocus && mLostWindowFocus;
2407 if (regainedFocus) {
2408 mLostWindowFocus = false;
2409 } else if (!hasWindowFocus && mHadWindowFocus) {
2410 mLostWindowFocus = true;
2411 }
2412
2413 if (changedVisibility || regainedFocus) {
Phil Weaver532c7992016-08-29 15:59:03 -07002414 // Toasts are presented as notifications - don't present them as windows as well
2415 boolean isToast = (mWindowAttributes == null) ? false
2416 : (mWindowAttributes.type == WindowManager.LayoutParams.TYPE_TOAST);
2417 if (!isToast) {
2418 host.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
2419 }
Alan Viverette64bf97a2015-09-18 16:42:00 -04002420 }
2421
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002422 mFirst = false;
2423 mWillDrawSoon = false;
2424 mNewSurfaceNeeded = false;
Jorim Jaggi4846ee32016-01-07 17:39:12 +01002425 mActivityRelaunched = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002426 mViewVisibility = viewVisibility;
Alan Viverette64bf97a2015-09-18 16:42:00 -04002427 mHadWindowFocus = hasWindowFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002428
Alan Viverette64bf97a2015-09-18 16:42:00 -04002429 if (hasWindowFocus && !isInLocalFocusMode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002430 final boolean imTarget = WindowManager.LayoutParams
2431 .mayUseInputMethod(mWindowAttributes.flags);
2432 if (imTarget != mLastWasImTarget) {
2433 mLastWasImTarget = imTarget;
2434 InputMethodManager imm = InputMethodManager.peekInstance();
2435 if (imm != null && imTarget) {
Alan Viverette64bf97a2015-09-18 16:42:00 -04002436 imm.onPreWindowFocus(mView, hasWindowFocus);
Yohei Yukawa5f059652015-05-14 22:16:41 -07002437 imm.onPostWindowFocus(mView, mView.findFocus(),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002438 mWindowAttributes.softInputMode,
2439 !mHasHadWindowFocus, mWindowAttributes.flags);
2440 }
2441 }
2442 }
Romain Guy8506ab42009-06-11 17:35:47 -07002443
Jeff Brown96e942d2011-11-30 19:55:01 -08002444 // Remember if we must report the next draw.
Jeff Brown98365d72012-08-19 20:30:52 -07002445 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
Robert Carr49cd9f82017-05-25 18:24:42 -07002446 reportNextDraw();
Jeff Brown96e942d2011-11-30 19:55:01 -08002447 }
2448
Alan Viverette64bf97a2015-09-18 16:42:00 -04002449 boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002450
Jorim Jaggi75c21ca2016-03-28 19:26:09 -04002451 if (!cancelDraw && !newSurface) {
Chet Haase9c450412015-10-01 13:25:58 -07002452 if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
2453 for (int i = 0; i < mPendingTransitions.size(); ++i) {
2454 mPendingTransitions.get(i).startChangingAnimations();
Chet Haased56c6952011-09-07 08:46:23 -07002455 }
Chet Haase9c450412015-10-01 13:25:58 -07002456 mPendingTransitions.clear();
Chet Haased56c6952011-09-07 08:46:23 -07002457 }
Chet Haase9c450412015-10-01 13:25:58 -07002458
2459 performDraw();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002460 } else {
Alan Viverette64bf97a2015-09-18 16:42:00 -04002461 if (isViewVisible) {
Chris Wren78cb7cf2012-05-15 12:36:44 -04002462 // Try again
2463 scheduleTraversals();
2464 } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
Chet Haased56c6952011-09-07 08:46:23 -07002465 for (int i = 0; i < mPendingTransitions.size(); ++i) {
2466 mPendingTransitions.get(i).endChangingAnimations();
2467 }
2468 mPendingTransitions.clear();
2469 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002470 }
Craig Mautnerdf2390a2012-08-29 20:59:22 -07002471
2472 mIsInTraversal = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002473 }
2474
Jorim Jaggi2e95a482016-01-14 17:36:55 -08002475 private void maybeHandleWindowMove(Rect frame) {
2476
2477 // TODO: Well, we are checking whether the frame has changed similarly
2478 // to how this is done for the insets. This is however incorrect since
2479 // the insets and the frame are translated. For example, the old frame
2480 // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new
2481 // reported frame is (2, 2 - 2, 2) which implies no change but this is not
2482 // true since we are comparing a not translated value to a translated one.
2483 // This scenario is rare but we may want to fix that.
2484
2485 final boolean windowMoved = mAttachInfo.mWindowLeft != frame.left
2486 || mAttachInfo.mWindowTop != frame.top;
2487 if (windowMoved) {
2488 if (mTranslator != null) {
2489 mTranslator.translateRectInScreenToAppWinFrame(frame);
2490 }
2491 mAttachInfo.mWindowLeft = frame.left;
2492 mAttachInfo.mWindowTop = frame.top;
Teng-Hui Zhu27571282016-05-12 15:53:53 -07002493 }
2494 if (windowMoved || mAttachInfo.mNeedsUpdateLightCenter) {
2495 // Update the light position for the new offsets.
Stan Iliev45faba52016-06-28 13:33:15 -04002496 if (mAttachInfo.mThreadedRenderer != null) {
2497 mAttachInfo.mThreadedRenderer.setLightCenter(mAttachInfo);
Jorim Jaggi2e95a482016-01-14 17:36:55 -08002498 }
Teng-Hui Zhu27571282016-05-12 15:53:53 -07002499 mAttachInfo.mNeedsUpdateLightCenter = false;
Jorim Jaggi2e95a482016-01-14 17:36:55 -08002500 }
2501 }
Teng-Hui Zhu27571282016-05-12 15:53:53 -07002502
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08002503 private void handleWindowFocusChanged() {
2504 final boolean hasWindowFocus;
2505 final boolean inTouchMode;
2506 synchronized (this) {
Dianne Hackborn011944c2017-12-15 15:44:55 -08002507 if (!mWindowFocusChanged) {
2508 return;
2509 }
2510 mWindowFocusChanged = false;
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08002511 hasWindowFocus = mUpcomingWindowFocus;
2512 inTouchMode = mUpcomingInTouchMode;
2513 }
2514
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08002515 if (mAdded) {
2516 profileRendering(hasWindowFocus);
2517
2518 if (hasWindowFocus) {
2519 ensureTouchModeLocally(inTouchMode);
2520 if (mAttachInfo.mThreadedRenderer != null && mSurface.isValid()) {
2521 mFullRedrawNeeded = true;
2522 try {
2523 final WindowManager.LayoutParams lp = mWindowAttributes;
2524 final Rect surfaceInsets = lp != null ? lp.surfaceInsets : null;
2525 mAttachInfo.mThreadedRenderer.initializeIfNeeded(
2526 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
2527 } catch (OutOfResourcesException e) {
2528 Log.e(mTag, "OutOfResourcesException locking surface", e);
2529 try {
2530 if (!mWindowSession.outOfMemory(mWindow)) {
2531 Slog.w(mTag, "No processes killed for memory;"
2532 + " killing self");
2533 Process.killProcess(Process.myPid());
2534 }
2535 } catch (RemoteException ex) {
2536 }
2537 // Retry in a bit.
2538 mHandler.sendMessageDelayed(mHandler.obtainMessage(
2539 MSG_WINDOW_FOCUS_CHANGED), 500);
2540 return;
2541 }
2542 }
2543 }
2544
2545 mAttachInfo.mHasWindowFocus = hasWindowFocus;
2546
2547 mLastWasImTarget = WindowManager.LayoutParams
2548 .mayUseInputMethod(mWindowAttributes.flags);
2549
2550 InputMethodManager imm = InputMethodManager.peekInstance();
2551 if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
2552 imm.onPreWindowFocus(mView, hasWindowFocus);
2553 }
2554 if (mView != null) {
2555 mAttachInfo.mKeyDispatchState.reset();
2556 mView.dispatchWindowFocusChanged(hasWindowFocus);
2557 mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
2558
2559 if (mAttachInfo.mTooltipHost != null) {
2560 mAttachInfo.mTooltipHost.hideTooltip();
2561 }
2562 }
2563
2564 // Note: must be done after the focus change callbacks,
2565 // so all of the view state is set up correctly.
2566 if (hasWindowFocus) {
2567 if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
2568 imm.onPostWindowFocus(mView, mView.findFocus(),
2569 mWindowAttributes.softInputMode,
2570 !mHasHadWindowFocus, mWindowAttributes.flags);
2571 }
2572 // Clear the forward bit. We can just do this directly, since
2573 // the window manager doesn't care about it.
2574 mWindowAttributes.softInputMode &=
2575 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
2576 ((WindowManager.LayoutParams) mView.getLayoutParams())
2577 .softInputMode &=
2578 ~WindowManager.LayoutParams
2579 .SOFT_INPUT_IS_FORWARD_NAVIGATION;
2580 mHasHadWindowFocus = true;
Svetoslav Ganov24c90452017-12-27 15:17:14 -08002581
2582 // Refocusing a window that has a focused view should fire a
2583 // focus event for the view since the global focused view changed.
2584 fireAccessibilityFocusEventIfHasFocusedNode();
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08002585 } else {
2586 if (mPointerCapture) {
2587 handlePointerCaptureChanged(false);
2588 }
2589 }
2590 }
2591 mFirstInputStage.onWindowFocusChanged(hasWindowFocus);
2592 }
2593
Svetoslav Ganov24c90452017-12-27 15:17:14 -08002594 private void fireAccessibilityFocusEventIfHasFocusedNode() {
2595 if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
2596 return;
2597 }
2598 final View focusedView = mView.findFocus();
2599 if (focusedView == null) {
2600 return;
2601 }
2602 final AccessibilityNodeProvider provider = focusedView.getAccessibilityNodeProvider();
2603 if (provider == null) {
2604 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
2605 } else {
2606 final AccessibilityNodeInfo focusedNode = findFocusedVirtualNode(provider);
2607 if (focusedNode != null) {
2608 final int virtualId = AccessibilityNodeInfo.getVirtualDescendantId(
2609 focusedNode.getSourceNodeId());
2610 // This is a best effort since clearing and setting the focus via the
2611 // provider APIs could have side effects. We don't have a provider API
2612 // similar to that on View to ask a given event to be fired.
2613 final AccessibilityEvent event = AccessibilityEvent.obtain(
2614 AccessibilityEvent.TYPE_VIEW_FOCUSED);
2615 event.setSource(focusedView, virtualId);
2616 event.setPackageName(focusedNode.getPackageName());
2617 event.setChecked(focusedNode.isChecked());
2618 event.setContentDescription(focusedNode.getContentDescription());
2619 event.setPassword(focusedNode.isPassword());
2620 event.getText().add(focusedNode.getText());
2621 event.setEnabled(focusedNode.isEnabled());
2622 focusedView.getParent().requestSendAccessibilityEvent(focusedView, event);
2623 focusedNode.recycle();
2624 }
2625 }
2626 }
2627
2628 private AccessibilityNodeInfo findFocusedVirtualNode(AccessibilityNodeProvider provider) {
2629 AccessibilityNodeInfo focusedNode = provider.findFocus(
2630 AccessibilityNodeInfo.FOCUS_INPUT);
2631 if (focusedNode != null) {
2632 return focusedNode;
2633 }
2634
2635 if (!mContext.isAutofillCompatibilityEnabled()) {
2636 return null;
2637 }
2638
2639 // Unfortunately some provider implementations don't properly
2640 // implement AccessibilityNodeProvider#findFocus
2641 AccessibilityNodeInfo current = provider.createAccessibilityNodeInfo(
2642 AccessibilityNodeProvider.HOST_VIEW_ID);
2643 if (current.isFocused()) {
2644 return current;
2645 }
2646
2647 final Queue<AccessibilityNodeInfo> fringe = new LinkedList<>();
2648 fringe.offer(current);
2649
2650 while (!fringe.isEmpty()) {
2651 current = fringe.poll();
2652 final LongArray childNodeIds = current.getChildNodeIds();
2653 if (childNodeIds== null || childNodeIds.size() <= 0) {
2654 continue;
2655 }
2656 final int childCount = childNodeIds.size();
2657 for (int i = 0; i < childCount; i++) {
2658 final int virtualId = AccessibilityNodeInfo.getVirtualDescendantId(
2659 childNodeIds.get(i));
2660 final AccessibilityNodeInfo child = provider.createAccessibilityNodeInfo(virtualId);
2661 if (child != null) {
2662 if (child.isFocused()) {
2663 return child;
2664 }
2665 fringe.offer(child);
2666 }
2667 }
2668 current.recycle();
2669 }
2670
2671 return null;
2672 }
2673
Romain Guy3696779b2013-01-28 14:04:07 -08002674 private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002675 Log.e(mTag, "OutOfResourcesException initializing HW surface", e);
Romain Guy3696779b2013-01-28 14:04:07 -08002676 try {
2677 if (!mWindowSession.outOfMemory(mWindow) &&
2678 Process.myUid() != Process.SYSTEM_UID) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002679 Slog.w(mTag, "No processes killed for memory; killing self");
Romain Guy3696779b2013-01-28 14:04:07 -08002680 Process.killProcess(Process.myPid());
2681 }
2682 } catch (RemoteException ex) {
2683 }
2684 mLayoutRequested = true; // ask wm for a new surface next time.
2685 }
2686
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002687 private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
Robert Carr001e55a2017-05-15 17:21:38 -07002688 if (mView == null) {
2689 return;
2690 }
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002691 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
2692 try {
2693 mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
2694 } finally {
2695 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2696 }
2697 }
2698
Chet Haase97140572012-09-13 14:56:47 -07002699 /**
2700 * Called by {@link android.view.View#isInLayout()} to determine whether the view hierarchy
2701 * is currently undergoing a layout pass.
2702 *
2703 * @return whether the view hierarchy is currently undergoing a layout pass
2704 */
2705 boolean isInLayout() {
2706 return mInLayout;
2707 }
2708
2709 /**
Chet Haasecc699b42012-12-13 09:06:55 -08002710 * Called by {@link android.view.View#requestLayout()} if the view hierarchy is currently
2711 * undergoing a layout pass. requestLayout() should not generally be called during layout,
2712 * unless the container hierarchy knows what it is doing (i.e., it is fine as long as
2713 * all children in that container hierarchy are measured and laid out at the end of the layout
2714 * pass for that container). If requestLayout() is called anyway, we handle it correctly
2715 * by registering all requesters during a frame as it proceeds. At the end of the frame,
2716 * we check all of those views to see if any still have pending layout requests, which
2717 * indicates that they were not correctly handled by their container hierarchy. If that is
2718 * the case, we clear all such flags in the tree, to remove the buggy flag state that leads
2719 * to blank containers, and force a second request/measure/layout pass in this frame. If
Chet Haase97140572012-09-13 14:56:47 -07002720 * more requestLayout() calls are received during that second layout pass, we post those
Chet Haasecc699b42012-12-13 09:06:55 -08002721 * requests to the next frame to avoid possible infinite loops.
2722 *
2723 * <p>The return value from this method indicates whether the request should proceed
2724 * (if it is a request during the first layout pass) or should be skipped and posted to the
2725 * next frame (if it is a request during the second layout pass).</p>
Chet Haase97140572012-09-13 14:56:47 -07002726 *
2727 * @param view the view that requested the layout.
Chet Haasecc699b42012-12-13 09:06:55 -08002728 *
2729 * @return true if request should proceed, false otherwise.
Chet Haase97140572012-09-13 14:56:47 -07002730 */
Chet Haasecc699b42012-12-13 09:06:55 -08002731 boolean requestLayoutDuringLayout(final View view) {
2732 if (view.mParent == null || view.mAttachInfo == null) {
2733 // Would not normally trigger another layout, so just let it pass through as usual
2734 return true;
2735 }
Chet Haase107a4822013-03-13 06:46:50 -07002736 if (!mLayoutRequesters.contains(view)) {
2737 mLayoutRequesters.add(view);
2738 }
Chet Haase97140572012-09-13 14:56:47 -07002739 if (!mHandlingLayoutInLayoutRequest) {
Chet Haase107a4822013-03-13 06:46:50 -07002740 // Let the request proceed normally; it will be processed in a second layout pass
2741 // if necessary
Chet Haasecc699b42012-12-13 09:06:55 -08002742 return true;
Chet Haase97140572012-09-13 14:56:47 -07002743 } else {
Chet Haase107a4822013-03-13 06:46:50 -07002744 // Don't let the request proceed during the second layout pass.
2745 // It will post to the next frame instead.
Chet Haasecc699b42012-12-13 09:06:55 -08002746 return false;
Chet Haase97140572012-09-13 14:56:47 -07002747 }
2748 }
2749
Chet Haase3efa7b52012-12-03 08:33:17 -08002750 private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
2751 int desiredWindowHeight) {
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002752 mLayoutRequested = false;
2753 mScrollMayChange = true;
Chet Haase97140572012-09-13 14:56:47 -07002754 mInLayout = true;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002755
2756 final View host = mView;
Robert Carr32f37ab2017-06-15 12:39:34 -07002757 if (host == null) {
2758 return;
2759 }
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002760 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002761 Log.v(mTag, "Laying out " + host + " to (" +
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002762 host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
2763 }
2764
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002765 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
2766 try {
2767 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haasecc699b42012-12-13 09:06:55 -08002768
Chet Haased5a83522012-11-21 16:24:44 -08002769 mInLayout = false;
Chet Haase97140572012-09-13 14:56:47 -07002770 int numViewsRequestingLayout = mLayoutRequesters.size();
2771 if (numViewsRequestingLayout > 0) {
Chet Haasecc699b42012-12-13 09:06:55 -08002772 // requestLayout() was called during layout.
2773 // If no layout-request flags are set on the requesting views, there is no problem.
2774 // If some requests are still pending, then we need to clear those flags and do
2775 // a full request/measure/layout pass to handle this situation.
Chet Haase107a4822013-03-13 06:46:50 -07002776 ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
2777 false);
2778 if (validLayoutRequesters != null) {
2779 // Set this flag to indicate that any further requests are happening during
2780 // the second pass, which may result in posting those requests to the next
2781 // frame instead
Chet Haasecc699b42012-12-13 09:06:55 -08002782 mHandlingLayoutInLayoutRequest = true;
Chet Haase107a4822013-03-13 06:46:50 -07002783
2784 // Process fresh layout requests, then measure and layout
2785 int numValidRequests = validLayoutRequesters.size();
Chet Haasecc699b42012-12-13 09:06:55 -08002786 for (int i = 0; i < numValidRequests; ++i) {
Chet Haase107a4822013-03-13 06:46:50 -07002787 final View view = validLayoutRequesters.get(i);
2788 Log.w("View", "requestLayout() improperly called by " + view +
2789 " during layout: running second layout pass");
2790 view.requestLayout();
Chet Haasecc699b42012-12-13 09:06:55 -08002791 }
2792 measureHierarchy(host, lp, mView.getContext().getResources(),
2793 desiredWindowWidth, desiredWindowHeight);
2794 mInLayout = true;
2795 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haase107a4822013-03-13 06:46:50 -07002796
Chet Haasecc699b42012-12-13 09:06:55 -08002797 mHandlingLayoutInLayoutRequest = false;
Chet Haase107a4822013-03-13 06:46:50 -07002798
2799 // Check the valid requests again, this time without checking/clearing the
2800 // layout flags, since requests happening during the second pass get noop'd
2801 validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);
2802 if (validLayoutRequesters != null) {
2803 final ArrayList<View> finalRequesters = validLayoutRequesters;
2804 // Post second-pass requests to the next frame
2805 getRunQueue().post(new Runnable() {
2806 @Override
2807 public void run() {
2808 int numValidRequests = finalRequesters.size();
2809 for (int i = 0; i < numValidRequests; ++i) {
2810 final View view = finalRequesters.get(i);
2811 Log.w("View", "requestLayout() improperly called by " + view +
2812 " during second layout pass: posting in next frame");
2813 view.requestLayout();
2814 }
2815 }
2816 });
2817 }
Chet Haasecc699b42012-12-13 09:06:55 -08002818 }
Chet Haase107a4822013-03-13 06:46:50 -07002819
Chet Haase97140572012-09-13 14:56:47 -07002820 }
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002821 } finally {
2822 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2823 }
Chet Haase97140572012-09-13 14:56:47 -07002824 mInLayout = false;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002825 }
2826
Chet Haase107a4822013-03-13 06:46:50 -07002827 /**
2828 * This method is called during layout when there have been calls to requestLayout() during
2829 * layout. It walks through the list of views that requested layout to determine which ones
2830 * still need it, based on visibility in the hierarchy and whether they have already been
2831 * handled (as is usually the case with ListView children).
2832 *
2833 * @param layoutRequesters The list of views that requested layout during layout
2834 * @param secondLayoutRequests Whether the requests were issued during the second layout pass.
2835 * If so, the FORCE_LAYOUT flag was not set on requesters.
2836 * @return A list of the actual views that still need to be laid out.
2837 */
2838 private ArrayList<View> getValidLayoutRequesters(ArrayList<View> layoutRequesters,
2839 boolean secondLayoutRequests) {
2840
2841 int numViewsRequestingLayout = layoutRequesters.size();
2842 ArrayList<View> validLayoutRequesters = null;
2843 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2844 View view = layoutRequesters.get(i);
2845 if (view != null && view.mAttachInfo != null && view.mParent != null &&
2846 (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) ==
2847 View.PFLAG_FORCE_LAYOUT)) {
2848 boolean gone = false;
2849 View parent = view;
2850 // Only trigger new requests for views in a non-GONE hierarchy
2851 while (parent != null) {
2852 if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) {
2853 gone = true;
2854 break;
2855 }
2856 if (parent.mParent instanceof View) {
2857 parent = (View) parent.mParent;
2858 } else {
2859 parent = null;
2860 }
2861 }
2862 if (!gone) {
2863 if (validLayoutRequesters == null) {
2864 validLayoutRequesters = new ArrayList<View>();
2865 }
2866 validLayoutRequesters.add(view);
2867 }
2868 }
2869 }
2870 if (!secondLayoutRequests) {
2871 // If we're checking the layout flags, then we need to clean them up also
2872 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2873 View view = layoutRequesters.get(i);
2874 while (view != null &&
2875 (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
2876 view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
2877 if (view.mParent instanceof View) {
2878 view = (View) view.mParent;
2879 } else {
2880 view = null;
2881 }
2882 }
2883 }
2884 }
2885 layoutRequesters.clear();
2886 return validLayoutRequesters;
2887 }
2888
Igor Murashkina86ab6402013-08-30 12:58:36 -07002889 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002890 public void requestTransparentRegion(View child) {
2891 // the test below should not fail unless someone is messing with us
2892 checkThread();
2893 if (mView == child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002894 mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002895 // Need to make sure we re-evaluate the window attributes next
2896 // time around, to ensure the window has the correct format.
2897 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -07002898 mWindowAttributesChangesFlag = 0;
Mathias Agopian1bd80ad2010-11-04 17:13:39 -07002899 requestLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002900 }
2901 }
2902
2903 /**
2904 * Figures out the measure spec for the root view in a window based on it's
2905 * layout params.
2906 *
2907 * @param windowSize
2908 * The available width or height of the window
2909 *
2910 * @param rootDimension
2911 * The layout params for one dimension (width or height) of the
2912 * window.
2913 *
2914 * @return The measure spec to use to measure the root view.
2915 */
Romain Guya998dff2012-03-23 18:58:36 -07002916 private static int getRootMeasureSpec(int windowSize, int rootDimension) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002917 int measureSpec;
2918 switch (rootDimension) {
2919
Romain Guy980a9382010-01-08 15:06:28 -08002920 case ViewGroup.LayoutParams.MATCH_PARENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002921 // Window can't resize. Force root view to be windowSize.
2922 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
2923 break;
2924 case ViewGroup.LayoutParams.WRAP_CONTENT:
2925 // Window can resize. Set max size for root view.
2926 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
2927 break;
2928 default:
2929 // Window wants to be an exact size. Force root view to be that size.
2930 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
2931 break;
2932 }
2933 return measureSpec;
2934 }
2935
Alan Viveretteccb11e12014-07-08 16:04:02 -07002936 int mHardwareXOffset;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002937 int mHardwareYOffset;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002938
Igor Murashkina86ab6402013-08-30 12:58:36 -07002939 @Override
Stan Iliev45faba52016-06-28 13:33:15 -04002940 public void onPreDraw(DisplayListCanvas canvas) {
John Reck3e04f092017-06-02 15:50:09 -07002941 // If mCurScrollY is not 0 then this influences the hardwareYOffset. The end result is we
2942 // can apply offsets that are not handled by anything else, resulting in underdraw as
2943 // the View is shifted (thus shifting the window background) exposing unpainted
2944 // content. To handle this with minimal glitches we just clear to BLACK if the window
2945 // is opaque. If it's not opaque then HWUI already internally does a glClear to
2946 // transparent, so there's no risk of underdraw on non-opaque surfaces.
2947 if (mCurScrollY != 0 && mHardwareYOffset != 0 && mAttachInfo.mThreadedRenderer.isOpaque()) {
2948 canvas.drawColor(Color.BLACK);
2949 }
Alan Viveretteccb11e12014-07-08 16:04:02 -07002950 canvas.translate(-mHardwareXOffset, -mHardwareYOffset);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002951 }
2952
Igor Murashkina86ab6402013-08-30 12:58:36 -07002953 @Override
Stan Iliev45faba52016-06-28 13:33:15 -04002954 public void onPostDraw(DisplayListCanvas canvas) {
Alan Viverette632af842014-10-28 13:45:11 -07002955 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09002956 if (mUseMTRenderer) {
2957 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
2958 mWindowCallbacks.get(i).onPostDraw(canvas);
2959 }
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002960 }
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002961 }
2962
Chet Haaseed30fd82011-04-22 16:18:45 -07002963 /**
2964 * @hide
2965 */
2966 void outputDisplayList(View view) {
Chris Craik356b5fe2015-07-07 10:39:36 -07002967 view.mRenderNode.output();
Stan Iliev45faba52016-06-28 13:33:15 -04002968 if (mAttachInfo.mThreadedRenderer != null) {
John Reck3e04f092017-06-02 15:50:09 -07002969 mAttachInfo.mThreadedRenderer.serializeDisplayListTree();
John Recke248bd12015-08-05 13:53:53 -07002970 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002971 }
2972
2973 /**
2974 * @see #PROPERTY_PROFILE_RENDERING
2975 */
2976 private void profileRendering(boolean enabled) {
2977 if (mProfileRendering) {
2978 mRenderProfilingEnabled = enabled;
Chris Craikae4f32042013-02-07 12:57:10 -08002979
2980 if (mRenderProfiler != null) {
2981 mChoreographer.removeFrameCallback(mRenderProfiler);
2982 }
2983 if (mRenderProfilingEnabled) {
2984 if (mRenderProfiler == null) {
2985 mRenderProfiler = new Choreographer.FrameCallback() {
2986 @Override
2987 public void doFrame(long frameTimeNanos) {
2988 mDirty.set(0, 0, mWidth, mHeight);
2989 scheduleTraversals();
2990 if (mRenderProfilingEnabled) {
2991 mChoreographer.postFrameCallback(mRenderProfiler);
2992 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002993 }
Chris Craikae4f32042013-02-07 12:57:10 -08002994 };
2995 }
Romain Guy5bb3c732012-11-29 17:52:58 -08002996 mChoreographer.postFrameCallback(mRenderProfiler);
Romain Guy59a12ca2011-06-09 17:48:21 -07002997 } else {
Romain Guy59a12ca2011-06-09 17:48:21 -07002998 mRenderProfiler = null;
Chet Haaseed30fd82011-04-22 16:18:45 -07002999 }
3000 }
3001 }
3002
Chet Haase2f2022a2011-10-11 06:41:59 -07003003 /**
3004 * Called from draw() when DEBUG_FPS is enabled
3005 */
3006 private void trackFPS() {
3007 // Tracks frames per second drawn. First value in a series of draws may be bogus
3008 // because it down not account for the intervening idle time
3009 long nowTime = System.currentTimeMillis();
3010 if (mFpsStartTime < 0) {
3011 mFpsStartTime = mFpsPrevTime = nowTime;
3012 mFpsNumFrames = 0;
3013 } else {
3014 ++mFpsNumFrames;
3015 String thisHash = Integer.toHexString(System.identityHashCode(this));
3016 long frameTime = nowTime - mFpsPrevTime;
3017 long totalTime = nowTime - mFpsStartTime;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003018 Log.v(mTag, "0x" + thisHash + "\tFrame time:\t" + frameTime);
Chet Haase2f2022a2011-10-11 06:41:59 -07003019 mFpsPrevTime = nowTime;
3020 if (totalTime > 1000) {
3021 float fps = (float) mFpsNumFrames * 1000 / totalTime;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003022 Log.v(mTag, "0x" + thisHash + "\tFPS:\t" + fps);
Chet Haase2f2022a2011-10-11 06:41:59 -07003023 mFpsStartTime = nowTime;
3024 mFpsNumFrames = 0;
3025 }
3026 }
3027 }
3028
Robert Carr8508bb22017-03-27 15:46:27 -07003029 /**
3030 * A count of the number of calls to pendingDrawFinished we
3031 * require to notify the WM drawing is complete.
Robert Carr8508bb22017-03-27 15:46:27 -07003032 */
Robert Carr49cd9f82017-05-25 18:24:42 -07003033 int mDrawsNeededToReport = 0;
Robert Carr8508bb22017-03-27 15:46:27 -07003034
3035 /**
3036 * Delay notifying WM of draw finished until
3037 * a balanced call to pendingDrawFinished.
3038 */
3039 void drawPending() {
3040 mDrawsNeededToReport++;
3041 }
3042
3043 void pendingDrawFinished() {
3044 if (mDrawsNeededToReport == 0) {
3045 throw new RuntimeException("Unbalanced drawPending/pendingDrawFinished calls");
3046 }
3047 mDrawsNeededToReport--;
3048 if (mDrawsNeededToReport == 0) {
3049 reportDrawFinished();
3050 }
3051 }
3052
3053 private void postDrawFinished() {
3054 mHandler.sendEmptyMessage(MSG_DRAW_FINISHED);
3055 }
3056
3057 private void reportDrawFinished() {
Robert Carrd5c7dd62017-03-08 10:39:30 -08003058 try {
Robert Carr49cd9f82017-05-25 18:24:42 -07003059 mDrawsNeededToReport = 0;
Robert Carrd5c7dd62017-03-08 10:39:30 -08003060 mWindowSession.finishDrawing(mWindow);
3061 } catch (RemoteException e) {
3062 // Have fun!
3063 }
3064 }
3065
Jeff Brown96e942d2011-11-30 19:55:01 -08003066 private void performDraw() {
Jeff Brownd912e1f2014-04-11 18:46:22 -07003067 if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
Craig Mautner006f0e42012-03-21 11:00:32 -07003068 return;
Robert Carr32f37ab2017-06-15 12:39:34 -07003069 } else if (mView == null) {
3070 return;
Craig Mautner006f0e42012-03-21 11:00:32 -07003071 }
Romain Guy7e4e5612012-03-05 14:37:29 -08003072
Jeff Brown96e942d2011-11-30 19:55:01 -08003073 final boolean fullRedrawNeeded = mFullRedrawNeeded;
3074 mFullRedrawNeeded = false;
Jeff Brown481c1572012-03-09 14:41:15 -08003075
Romain Guy1f59e5c2012-05-06 14:11:16 -07003076 mIsDrawing = true;
Jeff Brown481c1572012-03-09 14:41:15 -08003077 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
3078 try {
3079 draw(fullRedrawNeeded);
3080 } finally {
Romain Guy1f59e5c2012-05-06 14:11:16 -07003081 mIsDrawing = false;
Jeff Brown481c1572012-03-09 14:41:15 -08003082 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
3083 }
Jeff Brown96e942d2011-11-30 19:55:01 -08003084
John Reck119907c2014-08-14 09:02:01 -07003085 // For whatever reason we didn't create a HardwareRenderer, end any
3086 // hardware animations that are now dangling
3087 if (mAttachInfo.mPendingAnimatingRenderNodes != null) {
3088 final int count = mAttachInfo.mPendingAnimatingRenderNodes.size();
3089 for (int i = 0; i < count; i++) {
3090 mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators();
3091 }
3092 mAttachInfo.mPendingAnimatingRenderNodes.clear();
3093 }
3094
Jeff Brown96e942d2011-11-30 19:55:01 -08003095 if (mReportNextDraw) {
3096 mReportNextDraw = false;
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07003097
3098 // if we're using multi-thread renderer, wait for the window frame draws
3099 if (mWindowDrawCountDown != null) {
3100 try {
3101 mWindowDrawCountDown.await();
3102 } catch (InterruptedException e) {
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07003103 Log.e(mTag, "Window redraw count down interrupted!");
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07003104 }
3105 mWindowDrawCountDown = null;
3106 }
3107
Stan Iliev45faba52016-06-28 13:33:15 -04003108 if (mAttachInfo.mThreadedRenderer != null) {
3109 mAttachInfo.mThreadedRenderer.fence();
3110 mAttachInfo.mThreadedRenderer.setStopped(mStopped);
John Reck28ad7b52014-04-07 16:59:25 -07003111 }
Jeff Brown96e942d2011-11-30 19:55:01 -08003112
3113 if (LOCAL_LOGV) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003114 Log.v(mTag, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
Jeff Brown96e942d2011-11-30 19:55:01 -08003115 }
Robert Carr25cfa132016-11-16 13:24:09 -08003116
Jeff Brown96e942d2011-11-30 19:55:01 -08003117 if (mSurfaceHolder != null && mSurface.isValid()) {
Robert Carr8508bb22017-03-27 15:46:27 -07003118 SurfaceCallbackHelper sch = new SurfaceCallbackHelper(this::postDrawFinished);
Jeff Brown96e942d2011-11-30 19:55:01 -08003119 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
Robert Carr25cfa132016-11-16 13:24:09 -08003120
3121 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
3122 } else {
Robert Carr8508bb22017-03-27 15:46:27 -07003123 pendingDrawFinished();
Jeff Brown96e942d2011-11-30 19:55:01 -08003124 }
Jeff Brown96e942d2011-11-30 19:55:01 -08003125 }
3126 }
3127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003128 private void draw(boolean fullRedrawNeeded) {
3129 Surface surface = mSurface;
Romain Guyfbb93fa2012-12-03 18:50:35 -08003130 if (!surface.isValid()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003131 return;
3132 }
3133
Chet Haase2f2022a2011-10-11 06:41:59 -07003134 if (DEBUG_FPS) {
3135 trackFPS();
3136 }
3137
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08003138 if (!sFirstDrawComplete) {
3139 synchronized (sFirstDrawHandlers) {
3140 sFirstDrawComplete = true;
Romain Guy812ccbe2010-06-01 14:07:24 -07003141 final int count = sFirstDrawHandlers.size();
3142 for (int i = 0; i< count; i++) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003143 mHandler.post(sFirstDrawHandlers.get(i));
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08003144 }
3145 }
3146 }
Romain Guy59a12ca2011-06-09 17:48:21 -07003147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003148 scrollToRectOrFocus(null, false);
3149
Chris Craikd36a81f2014-07-17 10:16:51 -07003150 if (mAttachInfo.mViewScrollChanged) {
3151 mAttachInfo.mViewScrollChanged = false;
3152 mAttachInfo.mTreeObserver.dispatchOnScrollChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003153 }
Romain Guy8506ab42009-06-11 17:35:47 -07003154
Dianne Hackborn0f761d62010-11-30 22:06:10 -08003155 boolean animating = mScroller != null && mScroller.computeScrollOffset();
Alan Viveretteccb11e12014-07-08 16:04:02 -07003156 final int curScrollY;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08003157 if (animating) {
Alan Viveretteccb11e12014-07-08 16:04:02 -07003158 curScrollY = mScroller.getCurrY();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003159 } else {
Alan Viveretteccb11e12014-07-08 16:04:02 -07003160 curScrollY = mScrollY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003161 }
Alan Viveretteccb11e12014-07-08 16:04:02 -07003162 if (mCurScrollY != curScrollY) {
3163 mCurScrollY = curScrollY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003164 fullRedrawNeeded = true;
Adrian Roos0e7ae4e2014-10-01 15:33:22 +02003165 if (mView instanceof RootViewSurfaceTaker) {
3166 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
3167 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003168 }
Jeff Brown96e942d2011-11-30 19:55:01 -08003169
Chris Craikd36a81f2014-07-17 10:16:51 -07003170 final float appScale = mAttachInfo.mApplicationScale;
3171 final boolean scalingRequired = mAttachInfo.mScalingRequired;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003172
Jeff Brown96e942d2011-11-30 19:55:01 -08003173 final Rect dirty = mDirty;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07003174 if (mSurfaceHolder != null) {
3175 // The app owns the surface, we won't draw.
3176 dirty.setEmpty();
Derek Sollenberger8d948352015-07-16 09:27:59 -04003177 if (animating && mScroller != null) {
3178 mScroller.abortAnimation();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08003179 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07003180 return;
3181 }
Romain Guy58ef7fb2010-09-13 12:52:37 -07003182
3183 if (fullRedrawNeeded) {
Chris Craikd36a81f2014-07-17 10:16:51 -07003184 mAttachInfo.mIgnoreDirtyState = true;
Romain Guyc3166e12011-08-08 15:00:03 -07003185 dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
Romain Guy58ef7fb2010-09-13 12:52:37 -07003186 }
Chet Haasead4f7032011-06-22 09:18:31 -07003187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003188 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003189 Log.v(mTag, "Draw " + mView + "/"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003190 + mWindowAttributes.getTitle()
3191 + ": dirty={" + dirty.left + "," + dirty.top
3192 + "," + dirty.right + "," + dirty.bottom + "} surface="
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07003193 + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
3194 appScale + ", width=" + mWidth + ", height=" + mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003195 }
3196
Chris Craikd36a81f2014-07-17 10:16:51 -07003197 mAttachInfo.mTreeObserver.dispatchOnDraw();
Romain Guy25eba5c2012-04-04 17:29:03 -07003198
Chong Zhang0275e392015-09-17 10:41:44 -07003199 int xOffset = -mCanvasOffsetX;
3200 int yOffset = -mCanvasOffsetY + curScrollY;
Alan Viverettea51cab92014-07-16 15:15:49 -07003201 final WindowManager.LayoutParams params = mWindowAttributes;
3202 final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
3203 if (surfaceInsets != null) {
3204 xOffset -= surfaceInsets.left;
3205 yOffset -= surfaceInsets.top;
3206
3207 // Offset dirty rect for surface insets.
3208 dirty.offset(surfaceInsets.left, surfaceInsets.right);
3209 }
3210
Alan Viverette632af842014-10-28 13:45:11 -07003211 boolean accessibilityFocusDirty = false;
3212 final Drawable drawable = mAttachInfo.mAccessibilityFocusDrawable;
3213 if (drawable != null) {
3214 final Rect bounds = mAttachInfo.mTmpInvalRect;
3215 final boolean hasFocus = getAccessibilityFocusedRect(bounds);
3216 if (!hasFocus) {
3217 bounds.setEmpty();
3218 }
3219 if (!bounds.equals(drawable.getBounds())) {
3220 accessibilityFocusDirty = true;
3221 }
3222 }
3223
John Reckba6adf62015-02-19 14:36:50 -08003224 mAttachInfo.mDrawingTime =
3225 mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
3226
Alan Viverette632af842014-10-28 13:45:11 -07003227 if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
Stan Iliev45faba52016-06-28 13:33:15 -04003228 if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {
Alan Viverette632af842014-10-28 13:45:11 -07003229 // If accessibility focus moved, always invalidate the root.
Jorim Jaggic39c7b02016-03-24 10:47:07 -07003230 boolean invalidateRoot = accessibilityFocusDirty || mInvalidateRootRequested;
3231 mInvalidateRootRequested = false;
Alan Viverette632af842014-10-28 13:45:11 -07003232
Jeff Brown96e942d2011-11-30 19:55:01 -08003233 // Draw with hardware renderer.
3234 mIsAnimating = false;
Alan Viverette632af842014-10-28 13:45:11 -07003235
John Reck0a973302014-07-16 13:29:45 -07003236 if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
3237 mHardwareYOffset = yOffset;
3238 mHardwareXOffset = xOffset;
Alan Viverette632af842014-10-28 13:45:11 -07003239 invalidateRoot = true;
Alan Viverettef6cf1a02014-08-11 14:13:02 -07003240 }
3241
Alan Viverette632af842014-10-28 13:45:11 -07003242 if (invalidateRoot) {
Stan Iliev45faba52016-06-28 13:33:15 -04003243 mAttachInfo.mThreadedRenderer.invalidateRoot();
Alan Viverette632af842014-10-28 13:45:11 -07003244 }
3245
Jeff Brown96e942d2011-11-30 19:55:01 -08003246 dirty.setEmpty();
3247
Skuhne980ee472015-10-06 11:31:31 -07003248 // Stage the content drawn size now. It will be transferred to the renderer
3249 // shortly before the draw commands get send to the renderer.
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07003250 final boolean updated = updateContentDrawBounds();
3251
John Reck8afcc762016-04-13 10:24:06 -07003252 if (mReportNextDraw) {
3253 // report next draw overrides setStopped()
3254 // This value is re-sync'd to the value of mStopped
3255 // in the handling of mReportNextDraw post-draw.
Stan Iliev45faba52016-06-28 13:33:15 -04003256 mAttachInfo.mThreadedRenderer.setStopped(false);
John Reck8afcc762016-04-13 10:24:06 -07003257 }
3258
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07003259 if (updated) {
3260 requestDrawWindow();
3261 }
Jorim Jaggi0d6222d2016-04-18 20:42:10 -07003262
Stan Iliev45faba52016-06-28 13:33:15 -04003263 mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
Romain Guy3696779b2013-01-28 14:04:07 -08003264 } else {
3265 // If we get here with a disabled & requested hardware renderer, something went
3266 // wrong (an invalidate posted right before we destroyed the hardware surface
3267 // for instance) so we should just bail out. Locking the surface with software
3268 // rendering at this point would lock it forever and prevent hardware renderer
3269 // from doing its job when it comes back.
3270 // Before we request a new frame we must however attempt to reinitiliaze the
3271 // hardware renderer if it's in requested state. This would happen after an
3272 // eglTerminate() for instance.
Stan Iliev45faba52016-06-28 13:33:15 -04003273 if (mAttachInfo.mThreadedRenderer != null &&
3274 !mAttachInfo.mThreadedRenderer.isEnabled() &&
Robert Carr80923d52018-04-19 13:05:08 -07003275 mAttachInfo.mThreadedRenderer.isRequested() &&
3276 mSurface.isValid()) {
Romain Guy3696779b2013-01-28 14:04:07 -08003277
3278 try {
Stan Iliev45faba52016-06-28 13:33:15 -04003279 mAttachInfo.mThreadedRenderer.initializeIfNeeded(
Alan Viverette50210d92015-05-14 18:05:36 -07003280 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
Igor Murashkina86ab6402013-08-30 12:58:36 -07003281 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08003282 handleOutOfResourcesException(e);
3283 return;
3284 }
3285
3286 mFullRedrawNeeded = true;
3287 scheduleTraversals();
3288 return;
3289 }
3290
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09003291 if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
3292 scalingRequired, dirty, surfaceInsets)) {
Romain Guy3696779b2013-01-28 14:04:07 -08003293 return;
3294 }
Jeff Brown95db2b22011-11-30 19:54:41 -08003295 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003296 }
Romain Guy8506ab42009-06-11 17:35:47 -07003297
Dianne Hackborn0f761d62010-11-30 22:06:10 -08003298 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003299 mFullRedrawNeeded = true;
3300 scheduleTraversals();
3301 }
3302 }
3303
Romain Guy25eba5c2012-04-04 17:29:03 -07003304 /**
Alan Viveretteccb11e12014-07-08 16:04:02 -07003305 * @return true if drawing was successful, false if an error occurred
Romain Guy25eba5c2012-04-04 17:29:03 -07003306 */
Alan Viveretteccb11e12014-07-08 16:04:02 -07003307 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09003308 boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
Romain Guy25eba5c2012-04-04 17:29:03 -07003309
3310 // Draw with software renderer.
Alan Viverettea51cab92014-07-16 15:15:49 -07003311 final Canvas canvas;
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09003312
3313 // We already have the offset of surfaceInsets in xoff, yoff and dirty region,
3314 // therefore we need to add it back when moving the dirty region.
3315 int dirtyXOffset = xoff;
3316 int dirtyYOffset = yoff;
3317 if (surfaceInsets != null) {
3318 dirtyXOffset += surfaceInsets.left;
3319 dirtyYOffset += surfaceInsets.top;
3320 }
3321
Romain Guy25eba5c2012-04-04 17:29:03 -07003322 try {
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09003323 dirty.offset(-dirtyXOffset, -dirtyYOffset);
Alan Viverettea51cab92014-07-16 15:15:49 -07003324 final int left = dirty.left;
3325 final int top = dirty.top;
3326 final int right = dirty.right;
3327 final int bottom = dirty.bottom;
Romain Guy25eba5c2012-04-04 17:29:03 -07003328
Romain Guy25eba5c2012-04-04 17:29:03 -07003329 canvas = mSurface.lockCanvas(dirty);
3330
Romain Guye55945e2013-04-04 15:26:04 -07003331 // The dirty rectangle can be modified by Surface.lockCanvas()
3332 //noinspection ConstantConditions
Alan Viverettea51cab92014-07-16 15:15:49 -07003333 if (left != dirty.left || top != dirty.top || right != dirty.right
3334 || bottom != dirty.bottom) {
Romain Guy25eba5c2012-04-04 17:29:03 -07003335 attachInfo.mIgnoreDirtyState = true;
3336 }
3337
3338 // TODO: Do this in native
3339 canvas.setDensity(mDensity);
3340 } catch (Surface.OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08003341 handleOutOfResourcesException(e);
Romain Guy25eba5c2012-04-04 17:29:03 -07003342 return false;
3343 } catch (IllegalArgumentException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003344 Log.e(mTag, "Could not lock surface", e);
Romain Guy25eba5c2012-04-04 17:29:03 -07003345 // Don't assume this is due to out of memory, it could be
3346 // something else, and if it is something else then we could
3347 // kill stuff (or ourself) for no reason.
3348 mLayoutRequested = true; // ask wm for a new surface next time.
3349 return false;
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09003350 } finally {
3351 dirty.offset(dirtyXOffset, dirtyYOffset); // Reset to the original value.
Romain Guy25eba5c2012-04-04 17:29:03 -07003352 }
3353
3354 try {
3355 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003356 Log.v(mTag, "Surface " + surface + " drawing to bitmap w="
Romain Guy25eba5c2012-04-04 17:29:03 -07003357 + canvas.getWidth() + ", h=" + canvas.getHeight());
3358 //canvas.drawARGB(255, 255, 0, 0);
3359 }
3360
Romain Guy25eba5c2012-04-04 17:29:03 -07003361 // If this bitmap's format includes an alpha channel, we
3362 // need to clear it before drawing so that the child will
3363 // properly re-composite its drawing on a transparent
3364 // background. This automatically respects the clip/dirty region
3365 // or
3366 // If we are applying an offset, we need to clear the area
3367 // where the offset doesn't appear to avoid having garbage
3368 // left in the blank areas.
Alan Viveretteccb11e12014-07-08 16:04:02 -07003369 if (!canvas.isOpaque() || yoff != 0 || xoff != 0) {
Romain Guy25eba5c2012-04-04 17:29:03 -07003370 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
3371 }
3372
3373 dirty.setEmpty();
3374 mIsAnimating = false;
Dianne Hackborn4702a852012-08-17 15:18:29 -07003375 mView.mPrivateFlags |= View.PFLAG_DRAWN;
Romain Guy25eba5c2012-04-04 17:29:03 -07003376
3377 if (DEBUG_DRAW) {
3378 Context cxt = mView.getContext();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003379 Log.i(mTag, "Drawing: package:" + cxt.getPackageName() +
Romain Guy25eba5c2012-04-04 17:29:03 -07003380 ", metrics=" + cxt.getResources().getDisplayMetrics() +
3381 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
3382 }
3383 try {
Alan Viveretteccb11e12014-07-08 16:04:02 -07003384 canvas.translate(-xoff, -yoff);
Romain Guy25eba5c2012-04-04 17:29:03 -07003385 if (mTranslator != null) {
3386 mTranslator.translateCanvas(canvas);
3387 }
Dianne Hackborn908aecc2012-07-31 16:37:34 -07003388 canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
Romain Guy25eba5c2012-04-04 17:29:03 -07003389 attachInfo.mSetIgnoreDirtyState = false;
3390
Romain Guy25eba5c2012-04-04 17:29:03 -07003391 mView.draw(canvas);
Alan Viverette632af842014-10-28 13:45:11 -07003392
3393 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Romain Guy25eba5c2012-04-04 17:29:03 -07003394 } finally {
3395 if (!attachInfo.mSetIgnoreDirtyState) {
3396 // Only clear the flag if it was not set during the mView.draw() call
3397 attachInfo.mIgnoreDirtyState = false;
3398 }
3399 }
Romain Guy25eba5c2012-04-04 17:29:03 -07003400 } finally {
Romain Guydddcd222012-05-18 15:33:57 -07003401 try {
3402 surface.unlockCanvasAndPost(canvas);
3403 } catch (IllegalArgumentException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003404 Log.e(mTag, "Could not unlock surface", e);
Romain Guydddcd222012-05-18 15:33:57 -07003405 mLayoutRequested = true; // ask wm for a new surface next time.
3406 //noinspection ReturnInsideFinallyBlock
3407 return false;
3408 }
Romain Guy25eba5c2012-04-04 17:29:03 -07003409
Romain Guy25eba5c2012-04-04 17:29:03 -07003410 if (LOCAL_LOGV) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003411 Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost");
Romain Guy25eba5c2012-04-04 17:29:03 -07003412 }
3413 }
3414 return true;
3415 }
3416
Alan Viverette632af842014-10-28 13:45:11 -07003417 /**
3418 * We want to draw a highlight around the current accessibility focused.
3419 * Since adding a style for all possible view is not a viable option we
3420 * have this specialized drawing method.
3421 *
3422 * Note: We are doing this here to be able to draw the highlight for
3423 * virtual views in addition to real ones.
3424 *
3425 * @param canvas The canvas on which to draw.
3426 */
3427 private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
3428 final Rect bounds = mAttachInfo.mTmpInvalRect;
3429 if (getAccessibilityFocusedRect(bounds)) {
3430 final Drawable drawable = getAccessibilityFocusedDrawable();
3431 if (drawable != null) {
3432 drawable.setBounds(bounds);
3433 drawable.draw(canvas);
3434 }
3435 } else if (mAttachInfo.mAccessibilityFocusDrawable != null) {
3436 mAttachInfo.mAccessibilityFocusDrawable.setBounds(0, 0, 0, 0);
3437 }
3438 }
3439
3440 private boolean getAccessibilityFocusedRect(Rect bounds) {
3441 final AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
3442 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
3443 return false;
3444 }
3445
3446 final View host = mAccessibilityFocusedHost;
3447 if (host == null || host.mAttachInfo == null) {
3448 return false;
3449 }
3450
3451 final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
3452 if (provider == null) {
Svetoslavded133c2015-01-30 20:28:41 -08003453 host.getBoundsOnScreen(bounds, true);
Alan Viverette632af842014-10-28 13:45:11 -07003454 } else if (mAccessibilityFocusedVirtualView != null) {
3455 mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
3456 } else {
3457 return false;
3458 }
3459
Alan Viverette2232add2015-05-26 15:24:18 -07003460 // Transform the rect into window-relative coordinates.
Alan Viverette632af842014-10-28 13:45:11 -07003461 final AttachInfo attachInfo = mAttachInfo;
Alan Viverette2232add2015-05-26 15:24:18 -07003462 bounds.offset(0, attachInfo.mViewRootImpl.mScrollY);
Alan Viverette632af842014-10-28 13:45:11 -07003463 bounds.offset(-attachInfo.mWindowLeft, -attachInfo.mWindowTop);
Doris Liu9607fbe2015-05-28 17:17:28 -07003464 if (!bounds.intersect(0, 0, attachInfo.mViewRootImpl.mWidth,
3465 attachInfo.mViewRootImpl.mHeight)) {
3466 // If no intersection, set bounds to empty.
3467 bounds.setEmpty();
3468 }
Alan Viverette632af842014-10-28 13:45:11 -07003469 return !bounds.isEmpty();
3470 }
3471
3472 private Drawable getAccessibilityFocusedDrawable() {
Chris Craikd36a81f2014-07-17 10:16:51 -07003473 // Lazily load the accessibility focus drawable.
3474 if (mAttachInfo.mAccessibilityFocusDrawable == null) {
Alan Viverettef6cf1a02014-08-11 14:13:02 -07003475 final TypedValue value = new TypedValue();
Chris Craikd36a81f2014-07-17 10:16:51 -07003476 final boolean resolved = mView.mContext.getTheme().resolveAttribute(
3477 R.attr.accessibilityFocusedDrawable, value, true);
3478 if (resolved) {
3479 mAttachInfo.mAccessibilityFocusDrawable =
Alan Viverette8eea3ea2014-02-03 18:40:20 -08003480 mView.mContext.getDrawable(value.resourceId);
Svetoslav Ganov42138042012-03-20 11:51:39 -07003481 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07003482 }
Chris Craikd36a81f2014-07-17 10:16:51 -07003483 return mAttachInfo.mAccessibilityFocusDrawable;
Svetoslav Ganov42138042012-03-20 11:51:39 -07003484 }
3485
Jorim Jaggic39c7b02016-03-24 10:47:07 -07003486 /**
3487 * Requests that the root render node is invalidated next time we perform a draw, such that
3488 * {@link WindowCallbacks#onPostDraw} gets called.
3489 */
3490 public void requestInvalidateRootRenderNode() {
3491 mInvalidateRootRequested = true;
3492 }
3493
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003494 boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
Chris Craikd36a81f2014-07-17 10:16:51 -07003495 final Rect ci = mAttachInfo.mContentInsets;
3496 final Rect vi = mAttachInfo.mVisibleInsets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003497 int scrollY = 0;
3498 boolean handled = false;
Romain Guy8506ab42009-06-11 17:35:47 -07003499
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003500 if (vi.left > ci.left || vi.top > ci.top
3501 || vi.right > ci.right || vi.bottom > ci.bottom) {
3502 // We'll assume that we aren't going to change the scroll
3503 // offset, since we want to avoid that unless it is actually
3504 // going to make the focus visible... otherwise we scroll
3505 // all over the place.
3506 scrollY = mScrollY;
3507 // We can be called for two different situations: during a draw,
3508 // to update the scroll position if the focus has changed (in which
3509 // case 'rectangle' is null), or in response to a
3510 // requestChildRectangleOnScreen() call (in which case 'rectangle'
3511 // is non-null and we just want to scroll to whatever that
3512 // rectangle is).
Craig Mautner26a84df2013-04-11 19:09:05 -07003513 final View focus = mView.findFocus();
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003514 if (focus == null) {
Romain Guye8b16522009-07-14 13:06:42 -07003515 return false;
3516 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003517 View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null;
Craig Mautner26a84df2013-04-11 19:09:05 -07003518 if (focus != lastScrolledFocus) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003519 // If the focus has changed, then ignore any requests to scroll
3520 // to a rectangle; first we want to make sure the entire focus
3521 // view is visible.
3522 rectangle = null;
3523 }
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003524 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Eval scroll: focus=" + focus
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003525 + " rectangle=" + rectangle + " ci=" + ci
3526 + " vi=" + vi);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003527 if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003528 // Optimization: if the focus hasn't changed since last
3529 // time, and no layout has happened, then just leave things
3530 // as they are.
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003531 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Keeping scroll y="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003532 + mScrollY + " vi=" + vi.toShortString());
Craig Mautner26a84df2013-04-11 19:09:05 -07003533 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003534 // We need to determine if the currently focused view is
3535 // within the visible part of the window and, if not, apply
3536 // a pan so it can be seen.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003537 mLastScrolledFocus = new WeakReference<View>(focus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003538 mScrollMayChange = false;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003539 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Need to scroll?");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003540 // Try to find the rectangle from the focus view.
3541 if (focus.getGlobalVisibleRect(mVisRect, null)) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003542 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Root w="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003543 + mView.getWidth() + " h=" + mView.getHeight()
3544 + " ci=" + ci.toShortString()
3545 + " vi=" + vi.toShortString());
3546 if (rectangle == null) {
3547 focus.getFocusedRect(mTempRect);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003548 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Focus " + focus
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003549 + ": focusRect=" + mTempRect.toShortString());
Dianne Hackborn1c6a8942010-03-23 16:34:20 -07003550 if (mView instanceof ViewGroup) {
3551 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
3552 focus, mTempRect);
3553 }
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003554 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003555 "Focus in window: focusRect="
3556 + mTempRect.toShortString()
3557 + " visRect=" + mVisRect.toShortString());
3558 } else {
3559 mTempRect.set(rectangle);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003560 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003561 "Request scroll to rect: "
3562 + mTempRect.toShortString()
3563 + " visRect=" + mVisRect.toShortString());
3564 }
3565 if (mTempRect.intersect(mVisRect)) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003566 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003567 "Focus window visible rect: "
3568 + mTempRect.toShortString());
3569 if (mTempRect.height() >
3570 (mView.getHeight()-vi.top-vi.bottom)) {
3571 // If the focus simply is not going to fit, then
3572 // best is probably just to leave things as-is.
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003573 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003574 "Too tall; leaving scrollY=" + scrollY);
Chong Zhang67254722016-06-02 12:56:54 -07003575 }
3576 // Next, check whether top or bottom is covered based on the non-scrolled
3577 // position, and calculate new scrollY (or set it to 0).
3578 // We can't keep using mScrollY here. For example mScrollY is non-zero
3579 // due to IME, then IME goes away. The current value of mScrollY leaves top
3580 // and bottom both visible, but we still need to scroll it back to 0.
3581 else if (mTempRect.top < vi.top) {
3582 scrollY = mTempRect.top - vi.top;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003583 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003584 "Top covered; scrollY=" + scrollY);
Chong Zhang67254722016-06-02 12:56:54 -07003585 } else if (mTempRect.bottom > (mView.getHeight()-vi.bottom)) {
3586 scrollY = mTempRect.bottom - (mView.getHeight()-vi.bottom);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003587 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003588 "Bottom covered; scrollY=" + scrollY);
Chong Zhang67254722016-06-02 12:56:54 -07003589 } else {
3590 scrollY = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003591 }
3592 handled = true;
3593 }
3594 }
3595 }
3596 }
Romain Guy8506ab42009-06-11 17:35:47 -07003597
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003598 if (scrollY != mScrollY) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003599 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Pan scroll changed: old="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003600 + mScrollY + " , new=" + scrollY);
Derek Sollenberger8d948352015-07-16 09:27:59 -04003601 if (!immediate) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003602 if (mScroller == null) {
3603 mScroller = new Scroller(mView.getContext());
3604 }
3605 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
3606 } else if (mScroller != null) {
3607 mScroller.abortAnimation();
3608 }
3609 mScrollY = scrollY;
3610 }
Romain Guy8506ab42009-06-11 17:35:47 -07003611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003612 return handled;
3613 }
Romain Guy8506ab42009-06-11 17:35:47 -07003614
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07003615 /**
3616 * @hide
3617 */
3618 public View getAccessibilityFocusedHost() {
3619 return mAccessibilityFocusedHost;
3620 }
3621
3622 /**
3623 * @hide
3624 */
3625 public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
3626 return mAccessibilityFocusedVirtualView;
3627 }
3628
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003629 void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003630 // If we have a virtual view with accessibility focus we need
3631 // to clear the focus and invalidate the virtual view bounds.
3632 if (mAccessibilityFocusedVirtualView != null) {
3633
3634 AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
3635 View focusHost = mAccessibilityFocusedHost;
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003636
3637 // Wipe the state of the current accessibility focus since
3638 // the call into the provider to clear accessibility focus
3639 // will fire an accessibility event which will end up calling
3640 // this method and we want to have clean state when this
3641 // invocation happens.
3642 mAccessibilityFocusedHost = null;
3643 mAccessibilityFocusedVirtualView = null;
3644
Alan Viverette239a0c02013-05-07 17:17:35 -07003645 // Clear accessibility focus on the host after clearing state since
3646 // this method may be reentrant.
Phil Weavere37cfab2016-04-07 21:01:57 -07003647 focusHost.clearAccessibilityFocusNoCallbacks(
3648 AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
Alan Viverette239a0c02013-05-07 17:17:35 -07003649
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003650 AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
3651 if (provider != null) {
3652 // Invalidate the area of the cleared accessibility focus.
3653 focusNode.getBoundsInParent(mTempRect);
3654 focusHost.invalidate(mTempRect);
3655 // Clear accessibility focus in the virtual node.
3656 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
3657 focusNode.getSourceNodeId());
3658 provider.performAction(virtualNodeId,
3659 AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
3660 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003661 focusNode.recycle();
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003662 }
Phil Weaverda469272016-06-24 18:17:21 -07003663 if ((mAccessibilityFocusedHost != null) && (mAccessibilityFocusedHost != view)) {
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003664 // Clear accessibility focus in the view.
Phil Weavere37cfab2016-04-07 21:01:57 -07003665 mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks(
3666 AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
Svetoslav Ganov42138042012-03-20 11:51:39 -07003667 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003668
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003669 // Set the new focus host and node.
3670 mAccessibilityFocusedHost = view;
3671 mAccessibilityFocusedVirtualView = node;
John Reck0a973302014-07-16 13:29:45 -07003672
Stan Iliev45faba52016-06-28 13:33:15 -04003673 if (mAttachInfo.mThreadedRenderer != null) {
3674 mAttachInfo.mThreadedRenderer.invalidateRoot();
John Reck0a973302014-07-16 13:29:45 -07003675 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07003676 }
3677
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08003678 boolean hasPointerCapture() {
3679 return mPointerCapture;
3680 }
3681
3682 void requestPointerCapture(boolean enabled) {
3683 if (mPointerCapture == enabled) {
3684 return;
3685 }
3686 InputManager.getInstance().requestPointerCapture(mAttachInfo.mWindowToken, enabled);
3687 }
3688
3689 private void handlePointerCaptureChanged(boolean hasCapture) {
3690 if (mPointerCapture == hasCapture) {
3691 return;
3692 }
3693 mPointerCapture = hasCapture;
3694 if (mView != null) {
3695 mView.dispatchPointerCaptureChanged(hasCapture);
3696 }
3697 }
3698
Igor Murashkina86ab6402013-08-30 12:58:36 -07003699 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003700 public void requestChildFocus(View child, View focused) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003701 if (DEBUG_INPUT_RESIZE) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003702 Log.v(mTag, "Request child focus: focus now " + focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003703 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003704 checkThread();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003705 scheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003706 }
3707
Igor Murashkina86ab6402013-08-30 12:58:36 -07003708 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003709 public void clearChildFocus(View child) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003710 if (DEBUG_INPUT_RESIZE) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003711 Log.v(mTag, "Clearing child focus");
Amith Yamasani73eb97f2012-02-14 15:45:15 -08003712 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003713 checkThread();
3714 scheduleTraversals();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003715 }
Amith Yamasani73eb97f2012-02-14 15:45:15 -08003716
Svetoslav Ganov42138042012-03-20 11:51:39 -07003717 @Override
3718 public ViewParent getParentForAccessibility() {
3719 return null;
3720 }
3721
Igor Murashkina86ab6402013-08-30 12:58:36 -07003722 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003723 public void focusableViewAvailable(View v) {
3724 checkThread();
Romain Guy1c90f032011-05-24 14:59:50 -07003725 if (mView != null) {
3726 if (!mView.hasFocus()) {
Evan Rosky28884042018-04-03 13:21:55 -07003727 if (sAlwaysAssignFocus || !mAttachInfo.mInTouchMode) {
Evan Rosky37df2db2017-01-24 16:35:52 -08003728 v.requestFocus();
3729 }
Romain Guy1c90f032011-05-24 14:59:50 -07003730 } else {
3731 // the one case where will transfer focus away from the current one
3732 // is if the current view is a view group that prefers to give focus
3733 // to its children first AND the view is a descendant of it.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003734 View focused = mView.findFocus();
3735 if (focused instanceof ViewGroup) {
3736 ViewGroup group = (ViewGroup) focused;
3737 if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
3738 && isViewDescendantOf(v, focused)) {
3739 v.requestFocus();
3740 }
Romain Guy1c90f032011-05-24 14:59:50 -07003741 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003742 }
3743 }
3744 }
3745
Igor Murashkina86ab6402013-08-30 12:58:36 -07003746 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003747 public void recomputeViewAttributes(View child) {
3748 checkThread();
3749 if (mView == child) {
3750 mAttachInfo.mRecomputeGlobalAttributes = true;
3751 if (!mWillDrawSoon) {
3752 scheduleTraversals();
3753 }
3754 }
3755 }
3756
3757 void dispatchDetachedFromWindow() {
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07003758 mFirstInputStage.onDetachedFromWindow();
Romain Guy90fc03b2011-01-16 13:07:15 -08003759 if (mView != null && mView.mAttachInfo != null) {
Dianne Hackborn961cae92013-03-20 14:59:43 -07003760 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003761 mView.dispatchDetachedFromWindow();
3762 }
3763
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003764 mAccessibilityInteractionConnectionManager.ensureNoConnection();
3765 mAccessibilityManager.removeAccessibilityStateChangeListener(
3766 mAccessibilityInteractionConnectionManager);
Chris Craikcce47eb2014-07-16 15:12:15 -07003767 mAccessibilityManager.removeHighTextContrastStateChangeListener(
3768 mHighContrastTextManager);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07003769 removeSendWindowContentChangedCallback();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003770
Romain Guya998dff2012-03-23 18:58:36 -07003771 destroyHardwareRenderer();
3772
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003773 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003774
Craig Mautner8f303ad2013-06-14 11:32:22 -07003775 mView.assignParent(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003776 mView = null;
3777 mAttachInfo.mRootView = null;
3778
Dianne Hackborn0586a1b2009-09-06 21:08:27 -07003779 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003780
Jeff Browncc4f7db2011-08-30 20:34:48 -07003781 if (mInputQueueCallback != null && mInputQueue != null) {
3782 mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
Michael Wrighta44dd262013-04-10 21:12:00 -07003783 mInputQueue.dispose();
Jeff Browncc4f7db2011-08-30 20:34:48 -07003784 mInputQueueCallback = null;
3785 mInputQueue = null;
Michael Wrighta44dd262013-04-10 21:12:00 -07003786 }
3787 if (mInputEventReceiver != null) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08003788 mInputEventReceiver.dispose();
3789 mInputEventReceiver = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -07003790 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003791 try {
Jeff Brown98365d72012-08-19 20:30:52 -07003792 mWindowSession.remove(mWindow);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003793 } catch (RemoteException e) {
3794 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003795
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003796 // Dispose the input channel after removing the window so the Window Manager
3797 // doesn't interpret the input channel being closed as an abnormal termination.
3798 if (mInputChannel != null) {
3799 mInputChannel.dispose();
3800 mInputChannel = null;
Jeff Brown349703e2010-06-22 01:27:15 -07003801 }
Jeff Brown96e942d2011-11-30 19:55:01 -08003802
Jeff Brownd912e1f2014-04-11 18:46:22 -07003803 mDisplayManager.unregisterDisplayListener(mDisplayListener);
3804
Jeff Brownebb2d8d2012-03-23 17:14:34 -07003805 unscheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003806 }
Romain Guy8506ab42009-06-11 17:35:47 -07003807
Andrii Kulian44607962017-03-16 11:06:24 -07003808 /**
3809 * Notifies all callbacks that configuration and/or display has changed and updates internal
3810 * state.
3811 * @param mergedConfiguration New global and override config in {@link MergedConfiguration}
3812 * container.
3813 * @param force Flag indicating if we should force apply the config.
3814 * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} if not
3815 * changed.
3816 */
3817 private void performConfigurationChange(MergedConfiguration mergedConfiguration, boolean force,
3818 int newDisplayId) {
3819 if (mergedConfiguration == null) {
3820 throw new IllegalArgumentException("No merged config provided.");
3821 }
Dianne Hackborn5fd21692011-06-07 14:09:47 -07003822
Andrii Kulian44607962017-03-16 11:06:24 -07003823 Configuration globalConfig = mergedConfiguration.getGlobalConfiguration();
3824 final Configuration overrideConfig = mergedConfiguration.getOverrideConfiguration();
3825 if (DEBUG_CONFIGURATION) Log.v(mTag,
3826 "Applying new config to window " + mWindowAttributes.getTitle()
3827 + ", globalConfig: " + globalConfig
3828 + ", overrideConfig: " + overrideConfig);
3829
3830 final CompatibilityInfo ci = mDisplay.getDisplayAdjustments().getCompatibilityInfo();
Craig Mautner48d0d182013-06-11 07:53:06 -07003831 if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
Andrii Kulian44607962017-03-16 11:06:24 -07003832 globalConfig = new Configuration(globalConfig);
3833 ci.applyToConfiguration(mNoncompatDensity, globalConfig);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07003834 }
3835
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003836 synchronized (sConfigCallbacks) {
3837 for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
Andrii Kulian44607962017-03-16 11:06:24 -07003838 sConfigCallbacks.get(i).onConfigurationChanged(globalConfig);
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003839 }
3840 }
Adam Lesinski4ece3d62016-06-16 18:05:41 -07003841
Andrii Kulian44607962017-03-16 11:06:24 -07003842 mLastReportedMergedConfiguration.setConfiguration(globalConfig, overrideConfig);
3843
3844 mForceNextConfigUpdate = force;
3845 if (mActivityConfigCallback != null) {
3846 // An activity callback is set - notify it about override configuration update.
3847 // This basically initiates a round trip to ActivityThread and back, which will ensure
3848 // that corresponding activity and resources are updated before updating inner state of
3849 // ViewRootImpl. Eventually it will call #updateConfiguration().
3850 mActivityConfigCallback.onConfigurationChanged(overrideConfig, newDisplayId);
3851 } else {
3852 // There is no activity callback - update the configuration right away.
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07003853 updateConfiguration(newDisplayId);
Andrii Kulian44607962017-03-16 11:06:24 -07003854 }
3855 mForceNextConfigUpdate = false;
3856 }
3857
3858 /**
3859 * Update display and views if last applied merged configuration changed.
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07003860 * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} otherwise.
Andrii Kulian44607962017-03-16 11:06:24 -07003861 */
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07003862 public void updateConfiguration(int newDisplayId) {
Andrii Kulian44607962017-03-16 11:06:24 -07003863 if (mView == null) {
3864 return;
3865 }
3866
3867 // At this point the resources have been updated to
3868 // have the most recent config, whatever that is. Use
3869 // the one in them which may be newer.
3870 final Resources localResources = mView.getResources();
3871 final Configuration config = localResources.getConfiguration();
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07003872
3873 // Handle move to display.
3874 if (newDisplayId != INVALID_DISPLAY) {
3875 onMovedToDisplay(newDisplayId, config);
3876 }
3877
3878 // Handle configuration change.
Andrii Kulian44607962017-03-16 11:06:24 -07003879 if (mForceNextConfigUpdate || mLastConfigurationFromResources.diff(config) != 0) {
3880 // Update the display with new DisplayAdjustments.
3881 mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(
3882 mDisplay.getDisplayId(), localResources);
3883
3884 final int lastLayoutDirection = mLastConfigurationFromResources.getLayoutDirection();
3885 final int currentLayoutDirection = config.getLayoutDirection();
3886 mLastConfigurationFromResources.setTo(config);
3887 if (lastLayoutDirection != currentLayoutDirection
3888 && mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
3889 mView.setLayoutDirection(currentLayoutDirection);
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003890 }
Andrii Kulian44607962017-03-16 11:06:24 -07003891 mView.dispatchConfigurationChanged(config);
Bryce Leef858b572017-06-29 14:03:33 -07003892
3893 // We could have gotten this {@link Configuration} update after we called
3894 // {@link #performTraversals} with an older {@link Configuration}. As a result, our
3895 // window frame may be stale. We must ensure the next pass of {@link #performTraversals}
3896 // catches this.
3897 mForceNextWindowRelayout = true;
3898 requestLayout();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003899 }
3900 }
John Reck05e85842014-04-23 14:48:28 -07003901
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003902 /**
3903 * Return true if child is an ancestor of parent, (or equal to the parent).
3904 */
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07003905 public static boolean isViewDescendantOf(View child, View parent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003906 if (child == parent) {
3907 return true;
3908 }
3909
3910 final ViewParent theParent = child.getParent();
3911 return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
3912 }
3913
Yohei Yukawad2e56472015-07-28 17:00:33 -07003914 private static void forceLayout(View view) {
3915 view.forceLayout();
3916 if (view instanceof ViewGroup) {
3917 ViewGroup group = (ViewGroup) view;
3918 final int count = group.getChildCount();
3919 for (int i = 0; i < count; i++) {
3920 forceLayout(group.getChildAt(i));
3921 }
3922 }
3923 }
3924
Jeff Browna175a5b2012-02-15 19:18:31 -08003925 private final static int MSG_INVALIDATE = 1;
3926 private final static int MSG_INVALIDATE_RECT = 2;
3927 private final static int MSG_DIE = 3;
3928 private final static int MSG_RESIZED = 4;
3929 private final static int MSG_RESIZED_REPORT = 5;
3930 private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
keunyoung30f420f2013-08-02 14:23:10 -07003931 private final static int MSG_DISPATCH_INPUT_EVENT = 7;
Jeff Browna175a5b2012-02-15 19:18:31 -08003932 private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
3933 private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
Jeff Browna175a5b2012-02-15 19:18:31 -08003934 private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
Dake Gu6a20a192018-02-08 12:09:30 -08003935 private final static int MSG_DISPATCH_KEY_FROM_AUTOFILL = 12;
Jeff Browna175a5b2012-02-15 19:18:31 -08003936 private final static int MSG_CHECK_FOCUS = 13;
3937 private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
3938 private final static int MSG_DISPATCH_DRAG_EVENT = 15;
3939 private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
3940 private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
3941 private final static int MSG_UPDATE_CONFIGURATION = 18;
Svetoslav Ganov42138042012-03-20 11:51:39 -07003942 private final static int MSG_PROCESS_INPUT_EVENTS = 19;
Romain Guyfbb93fa2012-12-03 18:50:35 -08003943 private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
Jorim Jaggi827e0fa2015-05-07 11:41:41 -07003944 private final static int MSG_INVALIDATE_WORLD = 22;
3945 private final static int MSG_WINDOW_MOVED = 23;
3946 private final static int MSG_SYNTHESIZE_INPUT_EVENT = 24;
3947 private final static int MSG_DISPATCH_WINDOW_SHOWN = 25;
Clara Bayarri75e09792015-07-29 16:20:40 +01003948 private final static int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26;
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08003949 private final static int MSG_UPDATE_POINTER_ICON = 27;
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08003950 private final static int MSG_POINTER_CAPTURE_CHANGED = 28;
Robert Carr8508bb22017-03-27 15:46:27 -07003951 private final static int MSG_DRAW_FINISHED = 29;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003952
Jeff Browna175a5b2012-02-15 19:18:31 -08003953 final class ViewRootHandler extends Handler {
3954 @Override
3955 public String getMessageName(Message message) {
3956 switch (message.what) {
3957 case MSG_INVALIDATE:
3958 return "MSG_INVALIDATE";
3959 case MSG_INVALIDATE_RECT:
3960 return "MSG_INVALIDATE_RECT";
3961 case MSG_DIE:
3962 return "MSG_DIE";
3963 case MSG_RESIZED:
3964 return "MSG_RESIZED";
3965 case MSG_RESIZED_REPORT:
3966 return "MSG_RESIZED_REPORT";
3967 case MSG_WINDOW_FOCUS_CHANGED:
3968 return "MSG_WINDOW_FOCUS_CHANGED";
keunyoung30f420f2013-08-02 14:23:10 -07003969 case MSG_DISPATCH_INPUT_EVENT:
3970 return "MSG_DISPATCH_INPUT_EVENT";
Jeff Browna175a5b2012-02-15 19:18:31 -08003971 case MSG_DISPATCH_APP_VISIBILITY:
3972 return "MSG_DISPATCH_APP_VISIBILITY";
3973 case MSG_DISPATCH_GET_NEW_SURFACE:
3974 return "MSG_DISPATCH_GET_NEW_SURFACE";
Jeff Browna175a5b2012-02-15 19:18:31 -08003975 case MSG_DISPATCH_KEY_FROM_IME:
3976 return "MSG_DISPATCH_KEY_FROM_IME";
Dake Gu6a20a192018-02-08 12:09:30 -08003977 case MSG_DISPATCH_KEY_FROM_AUTOFILL:
3978 return "MSG_DISPATCH_KEY_FROM_AUTOFILL";
Jeff Browna175a5b2012-02-15 19:18:31 -08003979 case MSG_CHECK_FOCUS:
3980 return "MSG_CHECK_FOCUS";
3981 case MSG_CLOSE_SYSTEM_DIALOGS:
3982 return "MSG_CLOSE_SYSTEM_DIALOGS";
3983 case MSG_DISPATCH_DRAG_EVENT:
3984 return "MSG_DISPATCH_DRAG_EVENT";
3985 case MSG_DISPATCH_DRAG_LOCATION_EVENT:
3986 return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
3987 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
3988 return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
3989 case MSG_UPDATE_CONFIGURATION:
3990 return "MSG_UPDATE_CONFIGURATION";
Jeff Browna175a5b2012-02-15 19:18:31 -08003991 case MSG_PROCESS_INPUT_EVENTS:
3992 return "MSG_PROCESS_INPUT_EVENTS";
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003993 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
3994 return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
Craig Mautner5702d4d2012-06-30 14:10:16 -07003995 case MSG_WINDOW_MOVED:
3996 return "MSG_WINDOW_MOVED";
Michael Wright899d7052014-04-23 17:23:39 -07003997 case MSG_SYNTHESIZE_INPUT_EVENT:
3998 return "MSG_SYNTHESIZE_INPUT_EVENT";
Craig Mautner9c795042014-10-28 19:59:59 -07003999 case MSG_DISPATCH_WINDOW_SHOWN:
4000 return "MSG_DISPATCH_WINDOW_SHOWN";
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08004001 case MSG_UPDATE_POINTER_ICON:
4002 return "MSG_UPDATE_POINTER_ICON";
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08004003 case MSG_POINTER_CAPTURE_CHANGED:
4004 return "MSG_POINTER_CAPTURE_CHANGED";
Robert Carr8508bb22017-03-27 15:46:27 -07004005 case MSG_DRAW_FINISHED:
4006 return "MSG_DRAW_FINISHED";
Jeff Browna175a5b2012-02-15 19:18:31 -08004007 }
4008 return super.getMessageName(message);
Romain Guyf9284692011-07-13 18:46:21 -07004009 }
Romain Guyf9284692011-07-13 18:46:21 -07004010
Jeff Browna175a5b2012-02-15 19:18:31 -08004011 @Override
Michael Wright53b854a2016-04-12 19:22:41 -04004012 public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
4013 if (msg.what == MSG_REQUEST_KEYBOARD_SHORTCUTS && msg.obj == null) {
4014 // Debugging for b/27963013
4015 throw new NullPointerException(
4016 "Attempted to call MSG_REQUEST_KEYBOARD_SHORTCUTS with null receiver:");
4017 }
4018 return super.sendMessageAtTime(msg, uptimeMillis);
4019 }
4020
4021 @Override
Jeff Browna175a5b2012-02-15 19:18:31 -08004022 public void handleMessage(Message msg) {
4023 switch (msg.what) {
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004024 case MSG_INVALIDATE:
4025 ((View) msg.obj).invalidate();
Jeff Browna175a5b2012-02-15 19:18:31 -08004026 break;
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004027 case MSG_INVALIDATE_RECT:
4028 final View.AttachInfo.InvalidateInfo info =
4029 (View.AttachInfo.InvalidateInfo) msg.obj;
4030 info.target.invalidate(info.left, info.top, info.right, info.bottom);
4031 info.recycle();
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07004032 break;
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004033 case MSG_PROCESS_INPUT_EVENTS:
4034 mProcessInputEventsScheduled = false;
4035 doProcessInputEvents();
4036 break;
4037 case MSG_DISPATCH_APP_VISIBILITY:
4038 handleAppVisibility(msg.arg1 != 0);
4039 break;
4040 case MSG_DISPATCH_GET_NEW_SURFACE:
4041 handleGetNewSurface();
4042 break;
4043 case MSG_RESIZED: {
4044 // Recycled in the fall through...
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004045 SomeArgs args = (SomeArgs) msg.obj;
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004046 if (mWinFrame.equals(args.arg1)
4047 && mPendingOverscanInsets.equals(args.arg5)
4048 && mPendingContentInsets.equals(args.arg2)
4049 && mPendingStableInsets.equals(args.arg6)
Adrian Roos5c6b6222017-11-07 17:36:10 +01004050 && mPendingDisplayCutout.get().equals(args.arg9)
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004051 && mPendingVisibleInsets.equals(args.arg3)
4052 && mPendingOutsets.equals(args.arg7)
4053 && mPendingBackDropFrame.equals(args.arg8)
4054 && args.arg4 == null
4055 && args.argi1 == 0
4056 && mDisplay.getDisplayId() == args.argi3) {
4057 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08004058 }
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004059 } // fall through...
4060 case MSG_RESIZED_REPORT:
4061 if (mAdded) {
4062 SomeArgs args = (SomeArgs) msg.obj;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004063
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004064 final int displayId = args.argi3;
4065 MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg4;
4066 final boolean displayChanged = mDisplay.getDisplayId() != displayId;
Jorim Jaggi26952d72016-04-01 17:43:14 -07004067
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004068 if (!mLastReportedMergedConfiguration.equals(mergedConfiguration)) {
4069 // If configuration changed - notify about that and, maybe,
4070 // about move to display.
4071 performConfigurationChange(mergedConfiguration, false /* force */,
4072 displayChanged
4073 ? displayId : INVALID_DISPLAY /* same display */);
4074 } else if (displayChanged) {
4075 // Moved to display without config change - report last applied one.
4076 onMovedToDisplay(displayId, mLastConfigurationFromResources);
4077 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004078
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004079 final boolean framesChanged = !mWinFrame.equals(args.arg1)
4080 || !mPendingOverscanInsets.equals(args.arg5)
4081 || !mPendingContentInsets.equals(args.arg2)
4082 || !mPendingStableInsets.equals(args.arg6)
Adrian Roos5c6b6222017-11-07 17:36:10 +01004083 || !mPendingDisplayCutout.get().equals(args.arg9)
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004084 || !mPendingVisibleInsets.equals(args.arg3)
4085 || !mPendingOutsets.equals(args.arg7);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004086
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004087 mWinFrame.set((Rect) args.arg1);
4088 mPendingOverscanInsets.set((Rect) args.arg5);
4089 mPendingContentInsets.set((Rect) args.arg2);
4090 mPendingStableInsets.set((Rect) args.arg6);
Adrian Roos5c6b6222017-11-07 17:36:10 +01004091 mPendingDisplayCutout.set((DisplayCutout) args.arg9);
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004092 mPendingVisibleInsets.set((Rect) args.arg3);
4093 mPendingOutsets.set((Rect) args.arg7);
4094 mPendingBackDropFrame.set((Rect) args.arg8);
4095 mForceNextWindowRelayout = args.argi1 != 0;
4096 mPendingAlwaysConsumeNavBar = args.argi2 != 0;
4097
4098 args.recycle();
4099
4100 if (msg.what == MSG_RESIZED_REPORT) {
4101 reportNextDraw();
4102 }
4103
4104 if (mView != null && framesChanged) {
4105 forceLayout(mView);
4106 }
4107 requestLayout();
Jeff Browna175a5b2012-02-15 19:18:31 -08004108 }
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004109 break;
4110 case MSG_WINDOW_MOVED:
4111 if (mAdded) {
4112 final int w = mWinFrame.width();
4113 final int h = mWinFrame.height();
4114 final int l = msg.arg1;
4115 final int t = msg.arg2;
4116 mWinFrame.left = l;
4117 mWinFrame.right = l + w;
4118 mWinFrame.top = t;
4119 mWinFrame.bottom = t + h;
Romain Guy59a12ca2011-06-09 17:48:21 -07004120
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004121 mPendingBackDropFrame.set(mWinFrame);
4122 maybeHandleWindowMove(mWinFrame);
Yohei Yukawad2e56472015-07-28 17:00:33 -07004123 }
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004124 break;
4125 case MSG_WINDOW_FOCUS_CHANGED: {
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08004126 handleWindowFocusChanged();
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004127 } break;
4128 case MSG_DIE:
4129 doDie();
4130 break;
4131 case MSG_DISPATCH_INPUT_EVENT: {
4132 SomeArgs args = (SomeArgs) msg.obj;
4133 InputEvent event = (InputEvent) args.arg1;
4134 InputEventReceiver receiver = (InputEventReceiver) args.arg2;
4135 enqueueInputEvent(event, receiver, 0, true);
4136 args.recycle();
4137 } break;
4138 case MSG_SYNTHESIZE_INPUT_EVENT: {
4139 InputEvent event = (InputEvent) msg.obj;
4140 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_UNHANDLED, true);
4141 } break;
4142 case MSG_DISPATCH_KEY_FROM_IME: {
4143 if (LOCAL_LOGV) {
4144 Log.v(TAG, "Dispatching key " + msg.obj + " from IME to " + mView);
4145 }
4146 KeyEvent event = (KeyEvent) msg.obj;
4147 if ((event.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) != 0) {
4148 // The IME is trying to say this event is from the
4149 // system! Bad bad bad!
4150 //noinspection UnusedAssignment
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07004151 event = KeyEvent.changeFlags(event,
4152 event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004153 }
4154 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
4155 } break;
Dake Gu6a20a192018-02-08 12:09:30 -08004156 case MSG_DISPATCH_KEY_FROM_AUTOFILL: {
4157 if (LOCAL_LOGV) {
4158 Log.v(TAG, "Dispatching key " + msg.obj + " from Autofill to " + mView);
4159 }
4160 KeyEvent event = (KeyEvent) msg.obj;
Dake Gud9dbd272018-03-13 11:38:42 -07004161 enqueueInputEvent(event, null, 0, true);
Dake Gu6a20a192018-02-08 12:09:30 -08004162 } break;
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004163 case MSG_CHECK_FOCUS: {
Jeff Browna175a5b2012-02-15 19:18:31 -08004164 InputMethodManager imm = InputMethodManager.peekInstance();
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004165 if (imm != null) {
4166 imm.checkFocus();
Yohei Yukawa5f059652015-05-14 22:16:41 -07004167 }
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004168 } break;
4169 case MSG_CLOSE_SYSTEM_DIALOGS: {
Jeff Browna175a5b2012-02-15 19:18:31 -08004170 if (mView != null) {
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004171 mView.onCloseSystemDialogs((String) msg.obj);
4172 }
4173 } break;
4174 case MSG_DISPATCH_DRAG_EVENT: {
4175 } // fall through
4176 case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
4177 DragEvent event = (DragEvent) msg.obj;
4178 // only present when this app called startDrag()
4179 event.mLocalState = mLocalDragState;
4180 handleDragEvent(event);
4181 } break;
4182 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
4183 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj);
4184 } break;
4185 case MSG_UPDATE_CONFIGURATION: {
4186 Configuration config = (Configuration) msg.obj;
4187 if (config.isOtherSeqNewer(
4188 mLastReportedMergedConfiguration.getMergedConfiguration())) {
4189 // If we already have a newer merged config applied - use its global part.
4190 config = mLastReportedMergedConfiguration.getGlobalConfiguration();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004191 }
svetoslavganov75986cf2009-05-14 22:28:01 -07004192
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004193 // Use the newer global config and last reported override config.
4194 mPendingMergedConfiguration.setConfiguration(config,
4195 mLastReportedMergedConfiguration.getOverrideConfiguration());
4196
4197 performConfigurationChange(mPendingMergedConfiguration, false /* force */,
4198 INVALID_DISPLAY /* same display */);
4199 } break;
4200 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
4201 setAccessibilityFocus(null, null);
4202 } break;
4203 case MSG_INVALIDATE_WORLD: {
4204 if (mView != null) {
4205 invalidateWorld(mView);
Jeff Browna175a5b2012-02-15 19:18:31 -08004206 }
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004207 } break;
4208 case MSG_DISPATCH_WINDOW_SHOWN: {
4209 handleDispatchWindowShown();
4210 } break;
4211 case MSG_REQUEST_KEYBOARD_SHORTCUTS: {
4212 final IResultReceiver receiver = (IResultReceiver) msg.obj;
4213 final int deviceId = msg.arg1;
4214 handleRequestKeyboardShortcuts(receiver, deviceId);
4215 } break;
4216 case MSG_UPDATE_POINTER_ICON: {
4217 MotionEvent event = (MotionEvent) msg.obj;
4218 resetPointerIcon(event);
4219 } break;
4220 case MSG_POINTER_CAPTURE_CHANGED: {
4221 final boolean hasCapture = msg.arg1 != 0;
4222 handlePointerCaptureChanged(hasCapture);
4223 } break;
4224 case MSG_DRAW_FINISHED: {
4225 pendingDrawFinished();
4226 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004227 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004228 }
4229 }
Romain Guy51e4d4d2012-03-15 18:30:47 -07004230
Jeff Browna175a5b2012-02-15 19:18:31 -08004231 final ViewRootHandler mHandler = new ViewRootHandler();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004232
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004233 /**
4234 * Something in the current window tells us we need to change the touch mode. For
4235 * example, we are not in touch mode, and the user touches the screen.
4236 *
4237 * If the touch mode has changed, tell the window manager, and handle it locally.
4238 *
4239 * @param inTouchMode Whether we want to be in touch mode.
4240 * @return True if the touch mode changed and focus changed was changed as a result
4241 */
4242 boolean ensureTouchMode(boolean inTouchMode) {
4243 if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
4244 + "touch mode is " + mAttachInfo.mInTouchMode);
4245 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
4246
4247 // tell the window manager
4248 try {
Matt Wud6bc96d2016-01-14 12:59:24 -08004249 mWindowSession.setInTouchMode(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004250 } catch (RemoteException e) {
4251 throw new RuntimeException(e);
4252 }
4253
4254 // handle the change
Romain Guy2d4cff62010-04-09 15:39:00 -07004255 return ensureTouchModeLocally(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004256 }
4257
4258 /**
4259 * Ensure that the touch mode for this window is set, and if it is changing,
4260 * take the appropriate action.
4261 * @param inTouchMode Whether we want to be in touch mode.
4262 * @return True if the touch mode changed and focus changed was changed as a result
4263 */
Romain Guy2d4cff62010-04-09 15:39:00 -07004264 private boolean ensureTouchModeLocally(boolean inTouchMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004265 if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
4266 + "touch mode is " + mAttachInfo.mInTouchMode);
4267
4268 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
4269
4270 mAttachInfo.mInTouchMode = inTouchMode;
4271 mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
4272
Romain Guy2d4cff62010-04-09 15:39:00 -07004273 return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004274 }
4275
4276 private boolean enterTouchMode() {
Alan Viveretteed7821a2013-07-24 15:49:23 -07004277 if (mView != null && mView.hasFocus()) {
4278 // note: not relying on mFocusedView here because this could
4279 // be when the window is first being added, and mFocused isn't
4280 // set yet.
4281 final View focused = mView.findFocus();
4282 if (focused != null && !focused.isFocusableInTouchMode()) {
4283 final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
4284 if (ancestorToTakeFocus != null) {
4285 // there is an ancestor that wants focus after its
4286 // descendants that is focusable in touch mode.. give it
4287 // focus
4288 return ancestorToTakeFocus.requestFocus();
4289 } else {
Alan Viverette973f3b42013-08-13 16:57:28 -07004290 // There's nothing to focus. Clear and propagate through the
4291 // hierarchy, but don't attempt to place new focus.
Alan Viverette223622a2013-12-17 13:29:02 -08004292 focused.clearFocusInternal(null, true, false);
Alan Viveretteed7821a2013-07-24 15:49:23 -07004293 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004294 }
4295 }
4296 }
4297 return false;
4298 }
4299
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004300 /**
4301 * Find an ancestor of focused that wants focus after its descendants and is
4302 * focusable in touch mode.
4303 * @param focused The currently focused view.
4304 * @return An appropriate view, or null if no such view exists.
4305 */
Romain Guya998dff2012-03-23 18:58:36 -07004306 private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004307 ViewParent parent = focused.getParent();
4308 while (parent instanceof ViewGroup) {
4309 final ViewGroup vgParent = (ViewGroup) parent;
4310 if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
4311 && vgParent.isFocusableInTouchMode()) {
4312 return vgParent;
4313 }
4314 if (vgParent.isRootNamespace()) {
4315 return null;
4316 } else {
4317 parent = vgParent.getParent();
4318 }
4319 }
4320 return null;
4321 }
4322
4323 private boolean leaveTouchMode() {
4324 if (mView != null) {
4325 if (mView.hasFocus()) {
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004326 View focusedView = mView.findFocus();
4327 if (!(focusedView instanceof ViewGroup)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004328 // some view has focus, let it keep it
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07004329 return false;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004330 } else if (((ViewGroup) focusedView).getDescendantFocusability() !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004331 ViewGroup.FOCUS_AFTER_DESCENDANTS) {
4332 // some view group has focus, and doesn't prefer its children
4333 // over itself for focus, so let them keep it.
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07004334 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004335 }
4336 }
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07004337
4338 // find the best view to give focus to in this brave new non-touch-mode
4339 // world
Evan Roskybdc66cb2017-09-08 14:27:24 -07004340 return mView.restoreDefaultFocus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004341 }
4342 return false;
4343 }
4344
Jeff Brownf9e989d2013-04-04 23:04:03 -07004345 /**
4346 * Base class for implementing a stage in the chain of responsibility
4347 * for processing input events.
4348 * <p>
4349 * Events are delivered to the stage by the {@link #deliver} method. The stage
4350 * then has the choice of finishing the event or forwarding it to the next stage.
4351 * </p>
4352 */
4353 abstract class InputStage {
4354 private final InputStage mNext;
4355
4356 protected static final int FORWARD = 0;
4357 protected static final int FINISH_HANDLED = 1;
4358 protected static final int FINISH_NOT_HANDLED = 2;
4359
4360 /**
4361 * Creates an input stage.
4362 * @param next The next stage to which events should be forwarded.
4363 */
4364 public InputStage(InputStage next) {
4365 mNext = next;
4366 }
4367
4368 /**
4369 * Delivers an event to be processed.
4370 */
4371 public final void deliver(QueuedInputEvent q) {
4372 if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
4373 forward(q);
Michael Wright17d28ca2013-10-31 17:47:45 -07004374 } else if (shouldDropInputEvent(q)) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004375 finish(q, false);
4376 } else {
4377 apply(q, onProcess(q));
4378 }
4379 }
4380
4381 /**
4382 * Marks the the input event as finished then forwards it to the next stage.
4383 */
4384 protected void finish(QueuedInputEvent q, boolean handled) {
4385 q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
4386 if (handled) {
4387 q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
4388 }
4389 forward(q);
4390 }
4391
4392 /**
4393 * Forwards the event to the next stage.
4394 */
4395 protected void forward(QueuedInputEvent q) {
4396 onDeliverToNext(q);
4397 }
4398
4399 /**
4400 * Applies a result code from {@link #onProcess} to the specified event.
4401 */
4402 protected void apply(QueuedInputEvent q, int result) {
4403 if (result == FORWARD) {
4404 forward(q);
4405 } else if (result == FINISH_HANDLED) {
4406 finish(q, true);
4407 } else if (result == FINISH_NOT_HANDLED) {
4408 finish(q, false);
4409 } else {
4410 throw new IllegalArgumentException("Invalid result: " + result);
4411 }
4412 }
4413
4414 /**
4415 * Called when an event is ready to be processed.
4416 * @return A result code indicating how the event was handled.
4417 */
4418 protected int onProcess(QueuedInputEvent q) {
4419 return FORWARD;
4420 }
4421
4422 /**
4423 * Called when an event is being delivered to the next stage.
4424 */
4425 protected void onDeliverToNext(QueuedInputEvent q) {
Michael Wright06a79252014-05-05 17:45:29 -07004426 if (DEBUG_INPUT_STAGES) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004427 Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);
Michael Wright06a79252014-05-05 17:45:29 -07004428 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004429 if (mNext != null) {
4430 mNext.deliver(q);
4431 } else {
4432 finishInputEvent(q);
4433 }
4434 }
Jeff Brown5182c782013-10-15 20:31:52 -07004435
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07004436 protected void onWindowFocusChanged(boolean hasWindowFocus) {
4437 if (mNext != null) {
4438 mNext.onWindowFocusChanged(hasWindowFocus);
4439 }
4440 }
4441
4442 protected void onDetachedFromWindow() {
4443 if (mNext != null) {
4444 mNext.onDetachedFromWindow();
4445 }
4446 }
4447
Michael Wright17d28ca2013-10-31 17:47:45 -07004448 protected boolean shouldDropInputEvent(QueuedInputEvent q) {
4449 if (mView == null || !mAdded) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004450 Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent);
Michael Wright17d28ca2013-10-31 17:47:45 -07004451 return true;
George Mount41725de2015-04-09 08:23:05 -07004452 } else if ((!mAttachInfo.mHasWindowFocus
Dake Gu6a20a192018-02-08 12:09:30 -08004453 && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
Dake Gud9dbd272018-03-13 11:38:42 -07004454 && !isAutofillUiShowing()) || mStopped
Joe LaPenna90776de2016-01-22 07:11:49 -08004455 || (mIsAmbientMode && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON))
4456 || (mPausedForTransition && !isBack(q.mEvent))) {
Wale Ogunwalec3672cd2014-11-05 15:17:35 -08004457 // This is a focus event and the window doesn't currently have input focus or
4458 // has stopped. This could be an event that came back from the previous stage
4459 // but the window has lost focus or stopped in the meantime.
4460 if (isTerminalInputEvent(q.mEvent)) {
4461 // Don't drop terminal input events, however mark them as canceled.
4462 q.mEvent.cancel();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004463 Slog.w(mTag, "Cancelling event due to no window focus: " + q.mEvent);
Wale Ogunwalec3672cd2014-11-05 15:17:35 -08004464 return false;
4465 }
4466
4467 // Drop non-terminal input events.
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004468 Slog.w(mTag, "Dropping event due to no window focus: " + q.mEvent);
Michael Wright17d28ca2013-10-31 17:47:45 -07004469 return true;
4470 }
4471 return false;
4472 }
4473
Jeff Brown5182c782013-10-15 20:31:52 -07004474 void dump(String prefix, PrintWriter writer) {
4475 if (mNext != null) {
4476 mNext.dump(prefix, writer);
4477 }
4478 }
George Mount41725de2015-04-09 08:23:05 -07004479
4480 private boolean isBack(InputEvent event) {
4481 if (event instanceof KeyEvent) {
4482 return ((KeyEvent) event).getKeyCode() == KeyEvent.KEYCODE_BACK;
4483 } else {
4484 return false;
4485 }
4486 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004487 }
4488
4489 /**
4490 * Base class for implementing an input pipeline stage that supports
4491 * asynchronous and out-of-order processing of input events.
4492 * <p>
4493 * In addition to what a normal input stage can do, an asynchronous
4494 * input stage may also defer an input event that has been delivered to it
4495 * and finish or forward it later.
4496 * </p>
4497 */
4498 abstract class AsyncInputStage extends InputStage {
4499 private final String mTraceCounter;
4500
4501 private QueuedInputEvent mQueueHead;
4502 private QueuedInputEvent mQueueTail;
4503 private int mQueueLength;
4504
4505 protected static final int DEFER = 3;
4506
4507 /**
4508 * Creates an asynchronous input stage.
4509 * @param next The next stage to which events should be forwarded.
4510 * @param traceCounter The name of a counter to record the size of
4511 * the queue of pending events.
4512 */
4513 public AsyncInputStage(InputStage next, String traceCounter) {
4514 super(next);
4515 mTraceCounter = traceCounter;
4516 }
4517
4518 /**
4519 * Marks the event as deferred, which is to say that it will be handled
4520 * asynchronously. The caller is responsible for calling {@link #forward}
4521 * or {@link #finish} later when it is done handling the event.
4522 */
4523 protected void defer(QueuedInputEvent q) {
4524 q.mFlags |= QueuedInputEvent.FLAG_DEFERRED;
4525 enqueue(q);
4526 }
4527
4528 @Override
4529 protected void forward(QueuedInputEvent q) {
4530 // Clear the deferred flag.
4531 q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED;
4532
4533 // Fast path if the queue is empty.
4534 QueuedInputEvent curr = mQueueHead;
4535 if (curr == null) {
4536 super.forward(q);
4537 return;
4538 }
4539
4540 // Determine whether the event must be serialized behind any others
4541 // before it can be delivered to the next stage. This is done because
4542 // deferred events might be handled out of order by the stage.
4543 final int deviceId = q.mEvent.getDeviceId();
4544 QueuedInputEvent prev = null;
4545 boolean blocked = false;
4546 while (curr != null && curr != q) {
4547 if (!blocked && deviceId == curr.mEvent.getDeviceId()) {
4548 blocked = true;
4549 }
4550 prev = curr;
4551 curr = curr.mNext;
4552 }
4553
4554 // If the event is blocked, then leave it in the queue to be delivered later.
4555 // Note that the event might not yet be in the queue if it was not previously
4556 // deferred so we will enqueue it if needed.
4557 if (blocked) {
4558 if (curr == null) {
4559 enqueue(q);
4560 }
4561 return;
4562 }
4563
4564 // The event is not blocked. Deliver it immediately.
4565 if (curr != null) {
4566 curr = curr.mNext;
4567 dequeue(q, prev);
4568 }
4569 super.forward(q);
4570
4571 // Dequeuing this event may have unblocked successors. Deliver them.
4572 while (curr != null) {
4573 if (deviceId == curr.mEvent.getDeviceId()) {
4574 if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) {
4575 break;
4576 }
4577 QueuedInputEvent next = curr.mNext;
4578 dequeue(curr, prev);
4579 super.forward(curr);
4580 curr = next;
4581 } else {
4582 prev = curr;
4583 curr = curr.mNext;
4584 }
4585 }
4586 }
4587
4588 @Override
4589 protected void apply(QueuedInputEvent q, int result) {
4590 if (result == DEFER) {
4591 defer(q);
4592 } else {
4593 super.apply(q, result);
4594 }
4595 }
4596
4597 private void enqueue(QueuedInputEvent q) {
4598 if (mQueueTail == null) {
4599 mQueueHead = q;
4600 mQueueTail = q;
4601 } else {
4602 mQueueTail.mNext = q;
4603 mQueueTail = q;
4604 }
4605
4606 mQueueLength += 1;
4607 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
4608 }
4609
4610 private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) {
4611 if (prev == null) {
4612 mQueueHead = q.mNext;
4613 } else {
4614 prev.mNext = q.mNext;
4615 }
4616 if (mQueueTail == q) {
4617 mQueueTail = prev;
4618 }
4619 q.mNext = null;
4620
4621 mQueueLength -= 1;
4622 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
4623 }
Jeff Brown5182c782013-10-15 20:31:52 -07004624
4625 @Override
4626 void dump(String prefix, PrintWriter writer) {
4627 writer.print(prefix);
4628 writer.print(getClass().getName());
4629 writer.print(": mQueueLength=");
4630 writer.println(mQueueLength);
4631
4632 super.dump(prefix, writer);
4633 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004634 }
4635
4636 /**
4637 * Delivers pre-ime input events to a native activity.
4638 * Does not support pointer events.
4639 */
Michael Wrighta44dd262013-04-10 21:12:00 -07004640 final class NativePreImeInputStage extends AsyncInputStage
4641 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004642 public NativePreImeInputStage(InputStage next, String traceCounter) {
4643 super(next, traceCounter);
4644 }
4645
4646 @Override
4647 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07004648 if (mInputQueue != null && q.mEvent instanceof KeyEvent) {
4649 mInputQueue.sendInputEvent(q.mEvent, q, true, this);
4650 return DEFER;
4651 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004652 return FORWARD;
4653 }
Michael Wrighta44dd262013-04-10 21:12:00 -07004654
4655 @Override
4656 public void onFinishedInputEvent(Object token, boolean handled) {
4657 QueuedInputEvent q = (QueuedInputEvent)token;
4658 if (handled) {
4659 finish(q, true);
4660 return;
4661 }
4662 forward(q);
4663 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004664 }
4665
4666 /**
4667 * Delivers pre-ime input events to the view hierarchy.
4668 * Does not support pointer events.
4669 */
4670 final class ViewPreImeInputStage extends InputStage {
4671 public ViewPreImeInputStage(InputStage next) {
4672 super(next);
4673 }
4674
4675 @Override
4676 protected int onProcess(QueuedInputEvent q) {
Jeff Brown481c1572012-03-09 14:41:15 -08004677 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004678 return processKeyEvent(q);
4679 }
4680 return FORWARD;
4681 }
4682
4683 private int processKeyEvent(QueuedInputEvent q) {
4684 final KeyEvent event = (KeyEvent)q.mEvent;
4685 if (mView.dispatchKeyEventPreIme(event)) {
4686 return FINISH_HANDLED;
4687 }
4688 return FORWARD;
4689 }
4690 }
4691
4692 /**
4693 * Delivers input events to the ime.
4694 * Does not support pointer events.
4695 */
4696 final class ImeInputStage extends AsyncInputStage
4697 implements InputMethodManager.FinishedInputEventCallback {
4698 public ImeInputStage(InputStage next, String traceCounter) {
4699 super(next, traceCounter);
4700 }
4701
4702 @Override
4703 protected int onProcess(QueuedInputEvent q) {
keunyoung30f420f2013-08-02 14:23:10 -07004704 if (mLastWasImTarget && !isInLocalFocusMode()) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004705 InputMethodManager imm = InputMethodManager.peekInstance();
4706 if (imm != null) {
4707 final InputEvent event = q.mEvent;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004708 if (DEBUG_IMF) Log.v(mTag, "Sending input event to IME: " + event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004709 int result = imm.dispatchInputEvent(event, q, this, mHandler);
4710 if (result == InputMethodManager.DISPATCH_HANDLED) {
4711 return FINISH_HANDLED;
4712 } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
Adam Lesinskic0f6eed2013-10-28 16:03:19 -07004713 // The IME could not handle it, so skip along to the next InputStage
4714 return FORWARD;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004715 } else {
4716 return DEFER; // callback will be invoked later
4717 }
4718 }
4719 }
4720 return FORWARD;
4721 }
4722
4723 @Override
4724 public void onFinishedInputEvent(Object token, boolean handled) {
4725 QueuedInputEvent q = (QueuedInputEvent)token;
4726 if (handled) {
4727 finish(q, true);
4728 return;
4729 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004730 forward(q);
4731 }
4732 }
4733
4734 /**
4735 * Performs early processing of post-ime input events.
4736 */
4737 final class EarlyPostImeInputStage extends InputStage {
4738 public EarlyPostImeInputStage(InputStage next) {
4739 super(next);
4740 }
4741
4742 @Override
4743 protected int onProcess(QueuedInputEvent q) {
4744 if (q.mEvent instanceof KeyEvent) {
4745 return processKeyEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08004746 } else {
Jeff Brown481c1572012-03-09 14:41:15 -08004747 final int source = q.mEvent.getSource();
4748 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004749 return processPointerEvent(q);
Jeff Brown481c1572012-03-09 14:41:15 -08004750 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08004751 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004752 return FORWARD;
4753 }
4754
4755 private int processKeyEvent(QueuedInputEvent q) {
4756 final KeyEvent event = (KeyEvent)q.mEvent;
4757
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08004758 if (mAttachInfo.mTooltipHost != null) {
4759 mAttachInfo.mTooltipHost.handleTooltipKey(event);
4760 }
4761
Jeff Brownf9e989d2013-04-04 23:04:03 -07004762 // If the key's purpose is to exit touch mode then we consume it
4763 // and consider it handled.
4764 if (checkForLeavingTouchModeAndConsume(event)) {
4765 return FINISH_HANDLED;
4766 }
4767
4768 // Make sure the fallback event policy sees all keys that will be
4769 // delivered to the view hierarchy.
4770 mFallbackEventHandler.preDispatchKeyEvent(event);
4771 return FORWARD;
4772 }
4773
4774 private int processPointerEvent(QueuedInputEvent q) {
4775 final MotionEvent event = (MotionEvent)q.mEvent;
4776
4777 // Translate the pointer event for compatibility, if needed.
4778 if (mTranslator != null) {
4779 mTranslator.translateEventInScreenToAppWindow(event);
4780 }
4781
Vladislav Kaznacheev7614cdf2017-02-21 11:57:59 -08004782 // Enter touch mode on down or scroll, if it is coming from a touch screen device,
4783 // exit otherwise.
Jeff Brownf9e989d2013-04-04 23:04:03 -07004784 final int action = event.getAction();
Vladislav Kaznacheev7614cdf2017-02-21 11:57:59 -08004785 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
4786 ensureTouchMode(event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN));
Jeff Brownf9e989d2013-04-04 23:04:03 -07004787 }
4788
Dake Gud9dbd272018-03-13 11:38:42 -07004789 if (action == MotionEvent.ACTION_DOWN) {
Dake Gub0fa3782018-02-26 12:25:14 -08004790 // Upon motion event within app window, close autofill ui.
Dake Gud9dbd272018-03-13 11:38:42 -07004791 AutofillManager afm = getAutofillManager();
4792 if (afm != null) {
4793 afm.requestHideFillUi();
Dake Gub0fa3782018-02-26 12:25:14 -08004794 }
4795 }
4796
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08004797 if (action == MotionEvent.ACTION_DOWN && mAttachInfo.mTooltipHost != null) {
4798 mAttachInfo.mTooltipHost.hideTooltip();
4799 }
4800
Jeff Brownf9e989d2013-04-04 23:04:03 -07004801 // Offset the scroll position.
4802 if (mCurScrollY != 0) {
4803 event.offsetLocation(0, mCurScrollY);
4804 }
4805
4806 // Remember the touch position for possible drag-initiation.
4807 if (event.isTouchEvent()) {
4808 mLastTouchPoint.x = event.getRawX();
4809 mLastTouchPoint.y = event.getRawY();
Vladislav Kaznacheevba761122016-01-22 12:09:45 -08004810 mLastTouchSource = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004811 }
4812 return FORWARD;
Jeff Brown4952dfd2011-11-30 19:23:22 -08004813 }
4814 }
4815
Jeff Brownf9e989d2013-04-04 23:04:03 -07004816 /**
4817 * Delivers post-ime input events to a native activity.
4818 */
Michael Wrighta44dd262013-04-10 21:12:00 -07004819 final class NativePostImeInputStage extends AsyncInputStage
4820 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004821 public NativePostImeInputStage(InputStage next, String traceCounter) {
4822 super(next, traceCounter);
4823 }
4824
4825 @Override
4826 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07004827 if (mInputQueue != null) {
4828 mInputQueue.sendInputEvent(q.mEvent, q, false, this);
4829 return DEFER;
4830 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004831 return FORWARD;
4832 }
Michael Wrighta44dd262013-04-10 21:12:00 -07004833
4834 @Override
4835 public void onFinishedInputEvent(Object token, boolean handled) {
4836 QueuedInputEvent q = (QueuedInputEvent)token;
4837 if (handled) {
4838 finish(q, true);
4839 return;
4840 }
4841 forward(q);
4842 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004843 }
4844
4845 /**
4846 * Delivers post-ime input events to the view hierarchy.
4847 */
4848 final class ViewPostImeInputStage extends InputStage {
4849 public ViewPostImeInputStage(InputStage next) {
4850 super(next);
4851 }
4852
4853 @Override
4854 protected int onProcess(QueuedInputEvent q) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08004855 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004856 return processKeyEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08004857 } else {
4858 final int source = q.mEvent.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004859 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
4860 return processPointerEvent(q);
4861 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
4862 return processTrackballEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08004863 } else {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004864 return processGenericMotionEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08004865 }
4866 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08004867 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08004868
Michael Wright9d744c72014-02-18 21:27:42 -08004869 @Override
4870 protected void onDeliverToNext(QueuedInputEvent q) {
4871 if (mUnbufferedInputDispatch
4872 && q.mEvent instanceof MotionEvent
4873 && ((MotionEvent)q.mEvent).isTouchEvent()
4874 && isTerminalInputEvent(q.mEvent)) {
4875 mUnbufferedInputDispatch = false;
4876 scheduleConsumeBatchedInput();
4877 }
4878 super.onDeliverToNext(q);
4879 }
4880
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08004881 private boolean performFocusNavigation(KeyEvent event) {
4882 int direction = 0;
4883 switch (event.getKeyCode()) {
4884 case KeyEvent.KEYCODE_DPAD_LEFT:
4885 if (event.hasNoModifiers()) {
4886 direction = View.FOCUS_LEFT;
4887 }
4888 break;
4889 case KeyEvent.KEYCODE_DPAD_RIGHT:
4890 if (event.hasNoModifiers()) {
4891 direction = View.FOCUS_RIGHT;
4892 }
4893 break;
4894 case KeyEvent.KEYCODE_DPAD_UP:
4895 if (event.hasNoModifiers()) {
4896 direction = View.FOCUS_UP;
4897 }
4898 break;
4899 case KeyEvent.KEYCODE_DPAD_DOWN:
4900 if (event.hasNoModifiers()) {
4901 direction = View.FOCUS_DOWN;
4902 }
4903 break;
4904 case KeyEvent.KEYCODE_TAB:
4905 if (event.hasNoModifiers()) {
4906 direction = View.FOCUS_FORWARD;
4907 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
4908 direction = View.FOCUS_BACKWARD;
4909 }
4910 break;
4911 }
4912 if (direction != 0) {
4913 View focused = mView.findFocus();
4914 if (focused != null) {
4915 View v = focused.focusSearch(direction);
4916 if (v != null && v != focused) {
4917 // do the math the get the interesting rect
4918 // of previous focused into the coord system of
4919 // newly focused view
4920 focused.getFocusedRect(mTempRect);
4921 if (mView instanceof ViewGroup) {
4922 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
4923 focused, mTempRect);
4924 ((ViewGroup) mView).offsetRectIntoDescendantCoords(
4925 v, mTempRect);
4926 }
4927 if (v.requestFocus(direction, mTempRect)) {
4928 playSoundEffect(SoundEffectConstants
4929 .getContantForFocusDirection(direction));
4930 return true;
4931 }
4932 }
4933
4934 // Give the focused view a last chance to handle the dpad key.
4935 if (mView.dispatchUnhandledMove(focused, direction)) {
4936 return true;
4937 }
4938 } else {
Evan Rosky37df2db2017-01-24 16:35:52 -08004939 if (mView.restoreDefaultFocus()) {
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08004940 return true;
4941 }
4942 }
4943 }
4944 return false;
4945 }
4946
Vadim Tryshevb5ced222017-01-17 19:31:35 -08004947 private boolean performKeyboardGroupNavigation(int direction) {
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08004948 final View focused = mView.findFocus();
Evan Rosky37df2db2017-01-24 16:35:52 -08004949 if (focused == null && mView.restoreDefaultFocus()) {
4950 return true;
4951 }
Evan Rosky5b860712017-04-17 16:40:16 -07004952 View cluster = focused == null ? keyboardNavigationClusterSearch(null, direction)
4953 : focused.keyboardNavigationClusterSearch(null, direction);
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08004954
Evan Rosky53fcf112017-01-26 14:37:55 -08004955 // Since requestFocus only takes "real" focus directions (and therefore also
4956 // restoreFocusInCluster), convert forward/backward focus into FOCUS_DOWN.
4957 int realDirection = direction;
4958 if (direction == View.FOCUS_FORWARD || direction == View.FOCUS_BACKWARD) {
4959 realDirection = View.FOCUS_DOWN;
4960 }
4961
Evan Rosky3ac64632017-02-13 18:04:43 -08004962 if (cluster != null && cluster.isRootNamespace()) {
4963 // the default cluster. Try to find a non-clustered view to focus.
4964 if (cluster.restoreFocusNotInCluster()) {
Evan Roskybd10c522017-03-27 15:50:38 -07004965 playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
Evan Rosky3ac64632017-02-13 18:04:43 -08004966 return true;
4967 }
4968 // otherwise skip to next actual cluster
4969 cluster = keyboardNavigationClusterSearch(null, direction);
4970 }
4971
Evan Rosky53fcf112017-01-26 14:37:55 -08004972 if (cluster != null && cluster.restoreFocusInCluster(realDirection)) {
Evan Roskybd10c522017-03-27 15:50:38 -07004973 playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08004974 return true;
4975 }
4976
4977 return false;
4978 }
4979
Jeff Brownf9e989d2013-04-04 23:04:03 -07004980 private int processKeyEvent(QueuedInputEvent q) {
4981 final KeyEvent event = (KeyEvent)q.mEvent;
4982
Evan Rosky4807ae22018-03-22 16:04:15 -07004983 mUnhandledKeyManager.mDispatched = false;
Evan Rosky5e29c072017-06-02 17:31:22 -07004984
Evan Rosky4807ae22018-03-22 16:04:15 -07004985 if (mUnhandledKeyManager.hasFocus()
4986 && mUnhandledKeyManager.dispatchUnique(mView, event)) {
Evan Rosky5e29c072017-06-02 17:31:22 -07004987 return FINISH_HANDLED;
4988 }
4989
Jeff Brownf9e989d2013-04-04 23:04:03 -07004990 // Deliver the key to the view hierarchy.
4991 if (mView.dispatchKeyEvent(event)) {
4992 return FINISH_HANDLED;
Jeff Brown21bc5c92011-02-28 18:27:14 -08004993 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004994
Michael Wright17d28ca2013-10-31 17:47:45 -07004995 if (shouldDropInputEvent(q)) {
4996 return FINISH_NOT_HANDLED;
4997 }
4998
Evan Rosky4807ae22018-03-22 16:04:15 -07004999 if (mUnhandledKeyManager.dispatchUnique(mView, event)) {
Evan Rosky5e29c072017-06-02 17:31:22 -07005000 return FINISH_HANDLED;
5001 }
5002
Vadim Tryshev311a5b52017-01-05 18:54:11 -08005003 int groupNavigationDirection = 0;
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08005004
Evan Rosky516f9e62017-01-23 16:43:52 -08005005 if (event.getAction() == KeyEvent.ACTION_DOWN
5006 && event.getKeyCode() == KeyEvent.KEYCODE_TAB) {
5007 if (KeyEvent.metaStateHasModifiers(event.getMetaState(), KeyEvent.META_META_ON)) {
Vadim Tryshev311a5b52017-01-05 18:54:11 -08005008 groupNavigationDirection = View.FOCUS_FORWARD;
Evan Rosky516f9e62017-01-23 16:43:52 -08005009 } else if (KeyEvent.metaStateHasModifiers(event.getMetaState(),
5010 KeyEvent.META_META_ON | KeyEvent.META_SHIFT_ON)) {
Vadim Tryshev311a5b52017-01-05 18:54:11 -08005011 groupNavigationDirection = View.FOCUS_BACKWARD;
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08005012 }
5013 }
5014
Peeyush Agarwale631e322016-10-19 11:41:42 +01005015 // If a modifier is held, try to interpret the key as a shortcut.
Jeff Brownf9e989d2013-04-04 23:04:03 -07005016 if (event.getAction() == KeyEvent.ACTION_DOWN
Peeyush Agarwale631e322016-10-19 11:41:42 +01005017 && !KeyEvent.metaStateHasNoModifiers(event.getMetaState())
Jeff Brownf9e989d2013-04-04 23:04:03 -07005018 && event.getRepeatCount() == 0
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08005019 && !KeyEvent.isModifierKey(event.getKeyCode())
Vadim Tryshev311a5b52017-01-05 18:54:11 -08005020 && groupNavigationDirection == 0) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005021 if (mView.dispatchKeyShortcutEvent(event)) {
5022 return FINISH_HANDLED;
5023 }
Michael Wright17d28ca2013-10-31 17:47:45 -07005024 if (shouldDropInputEvent(q)) {
5025 return FINISH_NOT_HANDLED;
5026 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005027 }
5028
5029 // Apply the fallback event policy.
5030 if (mFallbackEventHandler.dispatchKeyEvent(event)) {
5031 return FINISH_HANDLED;
5032 }
Michael Wright17d28ca2013-10-31 17:47:45 -07005033 if (shouldDropInputEvent(q)) {
5034 return FINISH_NOT_HANDLED;
5035 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005036
5037 // Handle automatic focus changes.
5038 if (event.getAction() == KeyEvent.ACTION_DOWN) {
Vadim Tryshev311a5b52017-01-05 18:54:11 -08005039 if (groupNavigationDirection != 0) {
Vadim Tryshevb5ced222017-01-17 19:31:35 -08005040 if (performKeyboardGroupNavigation(groupNavigationDirection)) {
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08005041 return FINISH_HANDLED;
5042 }
5043 } else {
5044 if (performFocusNavigation(event)) {
5045 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005046 }
5047 }
5048 }
5049 return FORWARD;
Jeff Brown21bc5c92011-02-28 18:27:14 -08005050 }
5051
Jeff Brownf9e989d2013-04-04 23:04:03 -07005052 private int processPointerEvent(QueuedInputEvent q) {
5053 final MotionEvent event = (MotionEvent)q.mEvent;
5054
Vladislav Kaznacheev527905e2016-02-16 16:20:56 -08005055 mAttachInfo.mUnbufferedDispatchRequested = false;
Vladislav Kaznacheev527905e2016-02-16 16:20:56 -08005056 mAttachInfo.mHandlingPointerEvent = true;
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08005057 boolean handled = mView.dispatchPointerEvent(event);
Vladislav Kaznacheev527905e2016-02-16 16:20:56 -08005058 maybeUpdatePointerIcon(event);
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08005059 maybeUpdateTooltip(event);
Vladislav Kaznacheev527905e2016-02-16 16:20:56 -08005060 mAttachInfo.mHandlingPointerEvent = false;
5061 if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
5062 mUnbufferedInputDispatch = true;
5063 if (mConsumeBatchedInputScheduled) {
5064 scheduleConsumeBatchedInputImmediately();
5065 }
5066 }
5067 return handled ? FINISH_HANDLED : FORWARD;
5068 }
5069
5070 private void maybeUpdatePointerIcon(MotionEvent event) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005071 if (event.getPointerCount() == 1 && event.isFromSource(InputDevice.SOURCE_MOUSE)) {
Jun Mukai1db53972015-09-11 18:08:31 -07005072 if (event.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER
5073 || event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005074 // Other apps or the window manager may change the icon type outside of
5075 // this app, therefore the icon type has to be reset on enter/exit event.
5076 mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
Jun Mukai1db53972015-09-11 18:08:31 -07005077 }
5078
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005079 if (event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT) {
5080 if (!updatePointerIcon(event) &&
5081 event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005082 mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
Jun Mukai1db53972015-09-11 18:08:31 -07005083 }
5084 }
5085 }
Jeff Brown3915bb82010-11-05 15:02:16 -07005086 }
5087
Jeff Brownf9e989d2013-04-04 23:04:03 -07005088 private int processTrackballEvent(QueuedInputEvent q) {
5089 final MotionEvent event = (MotionEvent)q.mEvent;
5090
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08005091 if (event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) {
5092 if (!hasPointerCapture() || mView.dispatchCapturedPointerEvent(event)) {
5093 return FINISH_HANDLED;
5094 }
5095 }
5096
Jeff Brownf9e989d2013-04-04 23:04:03 -07005097 if (mView.dispatchTrackballEvent(event)) {
5098 return FINISH_HANDLED;
5099 }
5100 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005101 }
5102
Jeff Brownf9e989d2013-04-04 23:04:03 -07005103 private int processGenericMotionEvent(QueuedInputEvent q) {
5104 final MotionEvent event = (MotionEvent)q.mEvent;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07005105
Jeff Brownf9e989d2013-04-04 23:04:03 -07005106 // Deliver the event to the view.
5107 if (mView.dispatchGenericMotionEvent(event)) {
5108 return FINISH_HANDLED;
5109 }
5110 return FORWARD;
Jeff Brown3915bb82010-11-05 15:02:16 -07005111 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07005112 }
5113
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005114 private void resetPointerIcon(MotionEvent event) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005115 mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005116 updatePointerIcon(event);
5117 }
5118
5119 private boolean updatePointerIcon(MotionEvent event) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005120 final int pointerIndex = 0;
5121 final float x = event.getX(pointerIndex);
5122 final float y = event.getY(pointerIndex);
Andrii Kulian33c1bc52016-02-29 10:38:59 -08005123 if (mView == null) {
5124 // E.g. click outside a popup to dismiss it
5125 Slog.d(mTag, "updatePointerIcon called after view was removed");
5126 return false;
5127 }
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005128 if (x < 0 || x >= mView.getWidth() || y < 0 || y >= mView.getHeight()) {
Andrii Kulian33c1bc52016-02-29 10:38:59 -08005129 // E.g. when moving window divider with mouse
5130 Slog.d(mTag, "updatePointerIcon called with position out of bounds");
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005131 return false;
5132 }
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005133 final PointerIcon pointerIcon = mView.onResolvePointerIcon(event, pointerIndex);
5134 final int pointerType = (pointerIcon != null) ?
5135 pointerIcon.getType() : PointerIcon.TYPE_DEFAULT;
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005136
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005137 if (mPointerIconType != pointerType) {
5138 mPointerIconType = pointerType;
Vladislav Kaznacheeve40fb272017-01-03 16:45:42 -08005139 mCustomPointerIcon = null;
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005140 if (mPointerIconType != PointerIcon.TYPE_CUSTOM) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005141 InputManager.getInstance().setPointerIconType(pointerType);
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005142 return true;
5143 }
5144 }
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005145 if (mPointerIconType == PointerIcon.TYPE_CUSTOM &&
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005146 !pointerIcon.equals(mCustomPointerIcon)) {
5147 mCustomPointerIcon = pointerIcon;
5148 InputManager.getInstance().setCustomPointerIcon(mCustomPointerIcon);
5149 }
5150 return true;
5151 }
5152
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08005153 private void maybeUpdateTooltip(MotionEvent event) {
5154 if (event.getPointerCount() != 1) {
5155 return;
5156 }
5157 final int action = event.getActionMasked();
5158 if (action != MotionEvent.ACTION_HOVER_ENTER
5159 && action != MotionEvent.ACTION_HOVER_MOVE
5160 && action != MotionEvent.ACTION_HOVER_EXIT) {
5161 return;
5162 }
5163 AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
5164 if (manager.isEnabled() && manager.isTouchExplorationEnabled()) {
5165 return;
5166 }
5167 if (mView == null) {
5168 Slog.d(mTag, "maybeUpdateTooltip called after view was removed");
5169 return;
5170 }
5171 mView.dispatchTooltipHoverEvent(event);
5172 }
5173
Jeff Brownf9e989d2013-04-04 23:04:03 -07005174 /**
Jeff Brown678a1252013-04-09 17:46:25 -07005175 * Performs synthesis of new input events from unhandled input events.
Jeff Brownf9e989d2013-04-04 23:04:03 -07005176 */
5177 final class SyntheticInputStage extends InputStage {
Jeff Brown678a1252013-04-09 17:46:25 -07005178 private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler();
5179 private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
5180 private final SyntheticTouchNavigationHandler mTouchNavigation =
5181 new SyntheticTouchNavigationHandler();
Michael Wright899d7052014-04-23 17:23:39 -07005182 private final SyntheticKeyboardHandler mKeyboard = new SyntheticKeyboardHandler();
Jeff Brownf9e989d2013-04-04 23:04:03 -07005183
5184 public SyntheticInputStage() {
5185 super(null);
Jeff Brown21bc5c92011-02-28 18:27:14 -08005186 }
5187
Jeff Brownf9e989d2013-04-04 23:04:03 -07005188 @Override
5189 protected int onProcess(QueuedInputEvent q) {
5190 q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED;
5191 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07005192 final MotionEvent event = (MotionEvent)q.mEvent;
5193 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07005194 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07005195 mTrackball.process(event);
5196 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005197 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07005198 mJoystick.process(event);
5199 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005200 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
5201 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07005202 mTouchNavigation.process(event);
5203 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005204 }
Michael Wright899d7052014-04-23 17:23:39 -07005205 } else if ((q.mFlags & QueuedInputEvent.FLAG_UNHANDLED) != 0) {
5206 mKeyboard.process((KeyEvent)q.mEvent);
5207 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005208 }
Michael Wright899d7052014-04-23 17:23:39 -07005209
Jeff Brownf9e989d2013-04-04 23:04:03 -07005210 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005211 }
5212
Jeff Brownf9e989d2013-04-04 23:04:03 -07005213 @Override
5214 protected void onDeliverToNext(QueuedInputEvent q) {
5215 if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) {
5216 // Cancel related synthetic events if any prior stage has handled the event.
5217 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07005218 final MotionEvent event = (MotionEvent)q.mEvent;
5219 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07005220 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005221 mTrackball.cancel();
Jeff Brownf9e989d2013-04-04 23:04:03 -07005222 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005223 mJoystick.cancel();
Jeff Brownf9e989d2013-04-04 23:04:03 -07005224 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
5225 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07005226 mTouchNavigation.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07005227 }
5228 }
5229 }
5230 super.onDeliverToNext(q);
5231 }
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005232
5233 @Override
5234 protected void onWindowFocusChanged(boolean hasWindowFocus) {
5235 if (!hasWindowFocus) {
5236 mJoystick.cancel();
5237 }
5238 }
5239
5240 @Override
5241 protected void onDetachedFromWindow() {
5242 mJoystick.cancel();
5243 }
Jeff Brown678a1252013-04-09 17:46:25 -07005244 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005245
Jeff Brown678a1252013-04-09 17:46:25 -07005246 /**
5247 * Creates dpad events from unhandled trackball movements.
5248 */
5249 final class SyntheticTrackballHandler {
5250 private final TrackballAxis mX = new TrackballAxis();
5251 private final TrackballAxis mY = new TrackballAxis();
5252 private long mLastTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005253
Jeff Brown678a1252013-04-09 17:46:25 -07005254 public void process(MotionEvent event) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005255 // Translate the trackball event into DPAD keys and try to deliver those.
Jeff Brownf9e989d2013-04-04 23:04:03 -07005256 long curTime = SystemClock.uptimeMillis();
Jeff Brown678a1252013-04-09 17:46:25 -07005257 if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005258 // It has been too long since the last movement,
5259 // so restart at the beginning.
Jeff Brown678a1252013-04-09 17:46:25 -07005260 mX.reset(0);
5261 mY.reset(0);
5262 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005263 }
5264
5265 final int action = event.getAction();
5266 final int metaState = event.getMetaState();
5267 switch (action) {
5268 case MotionEvent.ACTION_DOWN:
Jeff Brown678a1252013-04-09 17:46:25 -07005269 mX.reset(2);
5270 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07005271 enqueueInputEvent(new KeyEvent(curTime, curTime,
5272 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
5273 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
5274 InputDevice.SOURCE_KEYBOARD));
5275 break;
5276 case MotionEvent.ACTION_UP:
Jeff Brown678a1252013-04-09 17:46:25 -07005277 mX.reset(2);
5278 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07005279 enqueueInputEvent(new KeyEvent(curTime, curTime,
5280 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
5281 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
5282 InputDevice.SOURCE_KEYBOARD));
5283 break;
5284 }
5285
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005286 if (DEBUG_TRACKBALL) Log.v(mTag, "TB X=" + mX.position + " step="
Jeff Brown678a1252013-04-09 17:46:25 -07005287 + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07005288 + " move=" + event.getX()
Jeff Brown678a1252013-04-09 17:46:25 -07005289 + " / Y=" + mY.position + " step="
5290 + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07005291 + " move=" + event.getY());
Jeff Brown678a1252013-04-09 17:46:25 -07005292 final float xOff = mX.collect(event.getX(), event.getEventTime(), "X");
5293 final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y");
Jeff Brownf9e989d2013-04-04 23:04:03 -07005294
5295 // Generate DPAD events based on the trackball movement.
5296 // We pick the axis that has moved the most as the direction of
5297 // the DPAD. When we generate DPAD events for one axis, then the
5298 // other axis is reset -- we don't want to perform DPAD jumps due
5299 // to slight movements in the trackball when making major movements
5300 // along the other axis.
5301 int keycode = 0;
5302 int movement = 0;
5303 float accel = 1;
5304 if (xOff > yOff) {
Jeff Brown678a1252013-04-09 17:46:25 -07005305 movement = mX.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07005306 if (movement != 0) {
5307 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
5308 : KeyEvent.KEYCODE_DPAD_LEFT;
Jeff Brown678a1252013-04-09 17:46:25 -07005309 accel = mX.acceleration;
5310 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07005311 }
5312 } else if (yOff > 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07005313 movement = mY.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07005314 if (movement != 0) {
5315 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
5316 : KeyEvent.KEYCODE_DPAD_UP;
Jeff Brown678a1252013-04-09 17:46:25 -07005317 accel = mY.acceleration;
5318 mX.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07005319 }
5320 }
5321
5322 if (keycode != 0) {
5323 if (movement < 0) movement = -movement;
5324 int accelMovement = (int)(movement * accel);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005325 if (DEBUG_TRACKBALL) Log.v(mTag, "Move: movement=" + movement
Jeff Brownf9e989d2013-04-04 23:04:03 -07005326 + " accelMovement=" + accelMovement
5327 + " accel=" + accel);
5328 if (accelMovement > movement) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005329 if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
Jeff Brownf9e989d2013-04-04 23:04:03 -07005330 + keycode);
5331 movement--;
5332 int repeatCount = accelMovement - movement;
5333 enqueueInputEvent(new KeyEvent(curTime, curTime,
5334 KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
5335 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
5336 InputDevice.SOURCE_KEYBOARD));
5337 }
5338 while (movement > 0) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005339 if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
Jeff Brownf9e989d2013-04-04 23:04:03 -07005340 + keycode);
5341 movement--;
5342 curTime = SystemClock.uptimeMillis();
5343 enqueueInputEvent(new KeyEvent(curTime, curTime,
5344 KeyEvent.ACTION_DOWN, keycode, 0, metaState,
5345 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
5346 InputDevice.SOURCE_KEYBOARD));
5347 enqueueInputEvent(new KeyEvent(curTime, curTime,
5348 KeyEvent.ACTION_UP, keycode, 0, metaState,
5349 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
5350 InputDevice.SOURCE_KEYBOARD));
5351 }
Jeff Brown678a1252013-04-09 17:46:25 -07005352 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005353 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005354 }
5355
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005356 public void cancel() {
Jeff Brown678a1252013-04-09 17:46:25 -07005357 mLastTime = Integer.MIN_VALUE;
Jeff Brown3915bb82010-11-05 15:02:16 -07005358
Jeff Brownf9e989d2013-04-04 23:04:03 -07005359 // If we reach this, we consumed a trackball event.
5360 // Because we will not translate the trackball event into a key event,
5361 // touch mode will not exit, so we exit touch mode here.
5362 if (mView != null && mAdded) {
5363 ensureTouchMode(false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07005364 }
5365 }
Jeff Brown678a1252013-04-09 17:46:25 -07005366 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005367
Jeff Brown678a1252013-04-09 17:46:25 -07005368 /**
5369 * Maintains state information for a single trackball axis, generating
5370 * discrete (DPAD) movements based on raw trackball motion.
5371 */
5372 static final class TrackballAxis {
5373 /**
5374 * The maximum amount of acceleration we will apply.
5375 */
5376 static final float MAX_ACCELERATION = 20;
5377
5378 /**
5379 * The maximum amount of time (in milliseconds) between events in order
5380 * for us to consider the user to be doing fast trackball movements,
5381 * and thus apply an acceleration.
5382 */
5383 static final long FAST_MOVE_TIME = 150;
5384
5385 /**
5386 * Scaling factor to the time (in milliseconds) between events to how
5387 * much to multiple/divide the current acceleration. When movement
5388 * is < FAST_MOVE_TIME this multiplies the acceleration; when >
5389 * FAST_MOVE_TIME it divides it.
5390 */
5391 static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
5392
5393 static final float FIRST_MOVEMENT_THRESHOLD = 0.5f;
5394 static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f;
5395 static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f;
5396
5397 float position;
5398 float acceleration = 1;
5399 long lastMoveTime = 0;
5400 int step;
5401 int dir;
5402 int nonAccelMovement;
5403
5404 void reset(int _step) {
5405 position = 0;
5406 acceleration = 1;
5407 lastMoveTime = 0;
5408 step = _step;
5409 dir = 0;
Jeff Brown6f2fba42011-02-19 01:08:02 -08005410 }
5411
Jeff Brown678a1252013-04-09 17:46:25 -07005412 /**
5413 * Add trackball movement into the state. If the direction of movement
5414 * has been reversed, the state is reset before adding the
5415 * movement (so that you don't have to compensate for any previously
5416 * collected movement before see the result of the movement in the
5417 * new direction).
5418 *
5419 * @return Returns the absolute value of the amount of movement
5420 * collected so far.
5421 */
5422 float collect(float off, long time, String axis) {
5423 long normTime;
5424 if (off > 0) {
5425 normTime = (long)(off * FAST_MOVE_TIME);
5426 if (dir < 0) {
5427 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
5428 position = 0;
5429 step = 0;
5430 acceleration = 1;
5431 lastMoveTime = 0;
5432 }
5433 dir = 1;
5434 } else if (off < 0) {
5435 normTime = (long)((-off) * FAST_MOVE_TIME);
5436 if (dir > 0) {
5437 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
5438 position = 0;
5439 step = 0;
5440 acceleration = 1;
5441 lastMoveTime = 0;
5442 }
5443 dir = -1;
5444 } else {
5445 normTime = 0;
5446 }
5447
5448 // The number of milliseconds between each movement that is
5449 // considered "normal" and will not result in any acceleration
5450 // or deceleration, scaled by the offset we have here.
5451 if (normTime > 0) {
5452 long delta = time - lastMoveTime;
5453 lastMoveTime = time;
5454 float acc = acceleration;
5455 if (delta < normTime) {
5456 // The user is scrolling rapidly, so increase acceleration.
5457 float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
5458 if (scale > 1) acc *= scale;
5459 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
5460 + off + " normTime=" + normTime + " delta=" + delta
5461 + " scale=" + scale + " acc=" + acc);
5462 acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
5463 } else {
5464 // The user is scrolling slowly, so decrease acceleration.
5465 float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
5466 if (scale > 1) acc /= scale;
5467 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
5468 + off + " normTime=" + normTime + " delta=" + delta
5469 + " scale=" + scale + " acc=" + acc);
5470 acceleration = acc > 1 ? acc : 1;
5471 }
5472 }
5473 position += off;
5474 return Math.abs(position);
Jeff Brown6f2fba42011-02-19 01:08:02 -08005475 }
Jeff Browncb1404e2011-01-15 18:14:15 -08005476
Jeff Brown678a1252013-04-09 17:46:25 -07005477 /**
5478 * Generate the number of discrete movement events appropriate for
5479 * the currently collected trackball movement.
5480 *
5481 * @return Returns the number of discrete movements, either positive
5482 * or negative, or 0 if there is not enough trackball movement yet
5483 * for a discrete movement.
5484 */
5485 int generate() {
5486 int movement = 0;
5487 nonAccelMovement = 0;
5488 do {
5489 final int dir = position >= 0 ? 1 : -1;
5490 switch (step) {
5491 // If we are going to execute the first step, then we want
5492 // to do this as soon as possible instead of waiting for
5493 // a full movement, in order to make things look responsive.
5494 case 0:
5495 if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) {
5496 return movement;
5497 }
5498 movement += dir;
5499 nonAccelMovement += dir;
5500 step = 1;
5501 break;
5502 // If we have generated the first movement, then we need
5503 // to wait for the second complete trackball motion before
5504 // generating the second discrete movement.
5505 case 1:
5506 if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) {
5507 return movement;
5508 }
5509 movement += dir;
5510 nonAccelMovement += dir;
5511 position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir;
5512 step = 2;
5513 break;
5514 // After the first two, we generate discrete movements
5515 // consistently with the trackball, applying an acceleration
5516 // if the trackball is moving quickly. This is a simple
5517 // acceleration on top of what we already compute based
5518 // on how quickly the wheel is being turned, to apply
5519 // a longer increasing acceleration to continuous movement
5520 // in one direction.
5521 default:
5522 if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) {
5523 return movement;
5524 }
5525 movement += dir;
5526 position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD;
5527 float acc = acceleration;
5528 acc *= 1.1f;
5529 acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
5530 break;
5531 }
5532 } while (true);
5533 }
5534 }
5535
5536 /**
5537 * Creates dpad events from unhandled joystick movements.
5538 */
5539 final class SyntheticJoystickHandler extends Handler {
5540 private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
5541 private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
5542
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005543 private final JoystickAxesState mJoystickAxesState = new JoystickAxesState();
5544 private final SparseArray<KeyEvent> mDeviceKeyEvents = new SparseArray<>();
Jeff Brown678a1252013-04-09 17:46:25 -07005545
5546 public SyntheticJoystickHandler() {
5547 super(true);
5548 }
5549
5550 @Override
5551 public void handleMessage(Message msg) {
5552 switch (msg.what) {
5553 case MSG_ENQUEUE_X_AXIS_KEY_REPEAT:
5554 case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: {
Jeff Brown678a1252013-04-09 17:46:25 -07005555 if (mAttachInfo.mHasWindowFocus) {
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005556 KeyEvent oldEvent = (KeyEvent) msg.obj;
5557 KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent,
5558 SystemClock.uptimeMillis(), oldEvent.getRepeatCount() + 1);
Jeff Brown678a1252013-04-09 17:46:25 -07005559 enqueueInputEvent(e);
5560 Message m = obtainMessage(msg.what, e);
5561 m.setAsynchronous(true);
5562 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay());
5563 }
5564 } break;
5565 }
5566 }
5567
5568 public void process(MotionEvent event) {
Michael Wright9adca062014-03-19 11:51:26 -07005569 switch(event.getActionMasked()) {
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005570 case MotionEvent.ACTION_CANCEL:
5571 cancel();
5572 break;
5573 case MotionEvent.ACTION_MOVE:
5574 update(event);
5575 break;
5576 default:
5577 Log.w(mTag, "Unexpected action: " + event.getActionMasked());
Michael Wright9adca062014-03-19 11:51:26 -07005578 }
Jeff Brown678a1252013-04-09 17:46:25 -07005579 }
5580
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005581 private void cancel() {
Michael Wright9adca062014-03-19 11:51:26 -07005582 removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
5583 removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005584 for (int i = 0; i < mDeviceKeyEvents.size(); i++) {
5585 final KeyEvent keyEvent = mDeviceKeyEvents.valueAt(i);
5586 if (keyEvent != null) {
5587 enqueueInputEvent(KeyEvent.changeTimeRepeat(keyEvent,
5588 SystemClock.uptimeMillis(), 0));
5589 }
5590 }
5591 mDeviceKeyEvents.clear();
5592 mJoystickAxesState.resetState();
Jeff Brown678a1252013-04-09 17:46:25 -07005593 }
5594
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005595 private void update(MotionEvent event) {
5596 final int historySize = event.getHistorySize();
5597 for (int h = 0; h < historySize; h++) {
5598 final long time = event.getHistoricalEventTime(h);
5599 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X,
5600 event.getHistoricalAxisValue(MotionEvent.AXIS_X, 0, h));
5601 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y,
5602 event.getHistoricalAxisValue(MotionEvent.AXIS_Y, 0, h));
5603 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X,
5604 event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_X, 0, h));
5605 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y,
5606 event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_Y, 0, h));
5607 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005608 final long time = event.getEventTime();
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005609 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X,
5610 event.getAxisValue(MotionEvent.AXIS_X));
5611 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y,
5612 event.getAxisValue(MotionEvent.AXIS_Y));
5613 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X,
Jeff Brownf9e989d2013-04-04 23:04:03 -07005614 event.getAxisValue(MotionEvent.AXIS_HAT_X));
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005615 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y,
Jeff Brownf9e989d2013-04-04 23:04:03 -07005616 event.getAxisValue(MotionEvent.AXIS_HAT_Y));
Jeff Browncb1404e2011-01-15 18:14:15 -08005617 }
5618
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005619 final class JoystickAxesState {
5620 // State machine: from neutral state (no button press) can go into
5621 // button STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state, emitting an ACTION_DOWN event.
5622 // From STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state can go into neutral state,
5623 // emitting an ACTION_UP event.
5624 private static final int STATE_UP_OR_LEFT = -1;
5625 private static final int STATE_NEUTRAL = 0;
5626 private static final int STATE_DOWN_OR_RIGHT = 1;
5627
5628 final int[] mAxisStatesHat = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_HAT_X, AXIS_HAT_Y}
5629 final int[] mAxisStatesStick = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_X, AXIS_Y}
5630
5631 void resetState() {
5632 mAxisStatesHat[0] = STATE_NEUTRAL;
5633 mAxisStatesHat[1] = STATE_NEUTRAL;
5634 mAxisStatesStick[0] = STATE_NEUTRAL;
5635 mAxisStatesStick[1] = STATE_NEUTRAL;
5636 }
5637
5638 void updateStateForAxis(MotionEvent event, long time, int axis, float value) {
5639 // Emit KeyEvent if necessary
5640 // axis can be AXIS_X, AXIS_Y, AXIS_HAT_X, AXIS_HAT_Y
5641 final int axisStateIndex;
5642 final int repeatMessage;
5643 if (isXAxis(axis)) {
5644 axisStateIndex = 0;
5645 repeatMessage = MSG_ENQUEUE_X_AXIS_KEY_REPEAT;
5646 } else if (isYAxis(axis)) {
5647 axisStateIndex = 1;
5648 repeatMessage = MSG_ENQUEUE_Y_AXIS_KEY_REPEAT;
5649 } else {
5650 Log.e(mTag, "Unexpected axis " + axis + " in updateStateForAxis!");
5651 return;
5652 }
5653 final int newState = joystickAxisValueToState(value);
5654
5655 final int currentState;
5656 if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) {
5657 currentState = mAxisStatesStick[axisStateIndex];
5658 } else {
5659 currentState = mAxisStatesHat[axisStateIndex];
5660 }
5661
5662 if (currentState == newState) {
5663 return;
5664 }
5665
5666 final int metaState = event.getMetaState();
5667 final int deviceId = event.getDeviceId();
5668 final int source = event.getSource();
5669
5670 if (currentState == STATE_DOWN_OR_RIGHT || currentState == STATE_UP_OR_LEFT) {
5671 // send a button release event
5672 final int keyCode = joystickAxisAndStateToKeycode(axis, currentState);
5673 if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
5674 enqueueInputEvent(new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode,
5675 0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
5676 // remove the corresponding pending UP event if focus lost/view detached
5677 mDeviceKeyEvents.put(deviceId, null);
5678 }
5679 removeMessages(repeatMessage);
5680 }
5681
5682 if (newState == STATE_DOWN_OR_RIGHT || newState == STATE_UP_OR_LEFT) {
5683 // send a button down event
5684 final int keyCode = joystickAxisAndStateToKeycode(axis, newState);
5685 if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
5686 KeyEvent keyEvent = new KeyEvent(time, time, KeyEvent.ACTION_DOWN, keyCode,
5687 0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
5688 enqueueInputEvent(keyEvent);
5689 Message m = obtainMessage(repeatMessage, keyEvent);
5690 m.setAsynchronous(true);
5691 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
5692 // store the corresponding ACTION_UP event so that it can be sent
5693 // if focus is lost or root view is removed
5694 mDeviceKeyEvents.put(deviceId,
5695 new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode,
5696 0, metaState, deviceId, 0,
5697 KeyEvent.FLAG_FALLBACK | KeyEvent.FLAG_CANCELED,
5698 source));
5699 }
5700 }
5701 if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) {
5702 mAxisStatesStick[axisStateIndex] = newState;
5703 } else {
5704 mAxisStatesHat[axisStateIndex] = newState;
5705 }
5706 }
5707
5708 private boolean isXAxis(int axis) {
5709 return axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_HAT_X;
5710 }
5711 private boolean isYAxis(int axis) {
5712 return axis == MotionEvent.AXIS_Y || axis == MotionEvent.AXIS_HAT_Y;
5713 }
5714
5715 private int joystickAxisAndStateToKeycode(int axis, int state) {
5716 if (isXAxis(axis) && state == STATE_UP_OR_LEFT) {
5717 return KeyEvent.KEYCODE_DPAD_LEFT;
5718 }
5719 if (isXAxis(axis) && state == STATE_DOWN_OR_RIGHT) {
5720 return KeyEvent.KEYCODE_DPAD_RIGHT;
5721 }
5722 if (isYAxis(axis) && state == STATE_UP_OR_LEFT) {
5723 return KeyEvent.KEYCODE_DPAD_UP;
5724 }
5725 if (isYAxis(axis) && state == STATE_DOWN_OR_RIGHT) {
5726 return KeyEvent.KEYCODE_DPAD_DOWN;
5727 }
5728 Log.e(mTag, "Unknown axis " + axis + " or direction " + state);
5729 return KeyEvent.KEYCODE_UNKNOWN; // should never happen
5730 }
5731
5732 private int joystickAxisValueToState(float value) {
5733 if (value >= 0.5f) {
5734 return STATE_DOWN_OR_RIGHT;
5735 } else if (value <= -0.5f) {
5736 return STATE_UP_OR_LEFT;
5737 } else {
5738 return STATE_NEUTRAL;
5739 }
Jeff Browncb1404e2011-01-15 18:14:15 -08005740 }
5741 }
Jeff Brown678a1252013-04-09 17:46:25 -07005742 }
Jeff Browncb1404e2011-01-15 18:14:15 -08005743
Jeff Brown678a1252013-04-09 17:46:25 -07005744 /**
5745 * Creates dpad events from unhandled touch navigation movements.
5746 */
5747 final class SyntheticTouchNavigationHandler extends Handler {
Jeff Brown4dac9012013-04-10 01:03:19 -07005748 private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler";
5749 private static final boolean LOCAL_DEBUG = false;
Jeff Brown678a1252013-04-09 17:46:25 -07005750
Jeff Brown4dac9012013-04-10 01:03:19 -07005751 // Assumed nominal width and height in millimeters of a touch navigation pad,
5752 // if no resolution information is available from the input system.
5753 private static final float DEFAULT_WIDTH_MILLIMETERS = 48;
5754 private static final float DEFAULT_HEIGHT_MILLIMETERS = 48;
Jeff Brown678a1252013-04-09 17:46:25 -07005755
Jeff Brown4dac9012013-04-10 01:03:19 -07005756 /* TODO: These constants should eventually be moved to ViewConfiguration. */
Jeff Brown678a1252013-04-09 17:46:25 -07005757
Jeff Brown4dac9012013-04-10 01:03:19 -07005758 // The nominal distance traveled to move by one unit.
5759 private static final int TICK_DISTANCE_MILLIMETERS = 12;
5760
5761 // Minimum and maximum fling velocity in ticks per second.
5762 // The minimum velocity should be set such that we perform enough ticks per
5763 // second that the fling appears to be fluid. For example, if we set the minimum
5764 // to 2 ticks per second, then there may be up to half a second delay between the next
5765 // to last and last ticks which is noticeably discrete and jerky. This value should
5766 // probably not be set to anything less than about 4.
5767 // If fling accuracy is a problem then consider tuning the tick distance instead.
5768 private static final float MIN_FLING_VELOCITY_TICKS_PER_SECOND = 6f;
5769 private static final float MAX_FLING_VELOCITY_TICKS_PER_SECOND = 20f;
5770
5771 // Fling velocity decay factor applied after each new key is emitted.
5772 // This parameter controls the deceleration and overall duration of the fling.
5773 // The fling stops automatically when its velocity drops below the minimum
5774 // fling velocity defined above.
5775 private static final float FLING_TICK_DECAY = 0.8f;
5776
5777 /* The input device that we are tracking. */
5778
5779 private int mCurrentDeviceId = -1;
5780 private int mCurrentSource;
5781 private boolean mCurrentDeviceSupported;
5782
5783 /* Configuration for the current input device. */
5784
Jeff Brown4dac9012013-04-10 01:03:19 -07005785 // The scaled tick distance. A movement of this amount should generally translate
5786 // into a single dpad event in a given direction.
5787 private float mConfigTickDistance;
5788
5789 // The minimum and maximum scaled fling velocity.
5790 private float mConfigMinFlingVelocity;
5791 private float mConfigMaxFlingVelocity;
5792
5793 /* Tracking state. */
5794
5795 // The velocity tracker for detecting flings.
5796 private VelocityTracker mVelocityTracker;
5797
5798 // The active pointer id, or -1 if none.
5799 private int mActivePointerId = -1;
5800
John Reck79d81e62013-11-05 13:26:57 -08005801 // Location where tracking started.
Jeff Brown4dac9012013-04-10 01:03:19 -07005802 private float mStartX;
5803 private float mStartY;
5804
5805 // Most recently observed position.
5806 private float mLastX;
5807 private float mLastY;
5808
5809 // Accumulated movement delta since the last direction key was sent.
Jeff Brown678a1252013-04-09 17:46:25 -07005810 private float mAccumulatedX;
5811 private float mAccumulatedY;
5812
Jeff Brown4dac9012013-04-10 01:03:19 -07005813 // Set to true if any movement was delivered to the app.
5814 // Implies that tap slop was exceeded.
5815 private boolean mConsumedMovement;
Jeff Brown678a1252013-04-09 17:46:25 -07005816
Jeff Brown4dac9012013-04-10 01:03:19 -07005817 // The most recently sent key down event.
5818 // The keycode remains set until the direction changes or a fling ends
5819 // so that repeated key events may be generated as required.
5820 private long mPendingKeyDownTime;
5821 private int mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
5822 private int mPendingKeyRepeatCount;
5823 private int mPendingKeyMetaState;
Jeff Brown678a1252013-04-09 17:46:25 -07005824
Jeff Brown4dac9012013-04-10 01:03:19 -07005825 // The current fling velocity while a fling is in progress.
5826 private boolean mFlinging;
5827 private float mFlingVelocity;
Jeff Brown678a1252013-04-09 17:46:25 -07005828
5829 public SyntheticTouchNavigationHandler() {
5830 super(true);
Jeff Brown678a1252013-04-09 17:46:25 -07005831 }
5832
5833 public void process(MotionEvent event) {
Jeff Brown4dac9012013-04-10 01:03:19 -07005834 // Update the current device information.
5835 final long time = event.getEventTime();
5836 final int deviceId = event.getDeviceId();
5837 final int source = event.getSource();
5838 if (mCurrentDeviceId != deviceId || mCurrentSource != source) {
5839 finishKeys(time);
5840 finishTracking(time);
5841 mCurrentDeviceId = deviceId;
5842 mCurrentSource = source;
5843 mCurrentDeviceSupported = false;
5844 InputDevice device = event.getDevice();
5845 if (device != null) {
5846 // In order to support an input device, we must know certain
5847 // characteristics about it, such as its size and resolution.
5848 InputDevice.MotionRange xRange = device.getMotionRange(MotionEvent.AXIS_X);
5849 InputDevice.MotionRange yRange = device.getMotionRange(MotionEvent.AXIS_Y);
5850 if (xRange != null && yRange != null) {
5851 mCurrentDeviceSupported = true;
Jeff Brown678a1252013-04-09 17:46:25 -07005852
Jeff Brown4dac9012013-04-10 01:03:19 -07005853 // Infer the resolution if it not actually known.
5854 float xRes = xRange.getResolution();
5855 if (xRes <= 0) {
5856 xRes = xRange.getRange() / DEFAULT_WIDTH_MILLIMETERS;
5857 }
5858 float yRes = yRange.getResolution();
5859 if (yRes <= 0) {
5860 yRes = yRange.getRange() / DEFAULT_HEIGHT_MILLIMETERS;
5861 }
5862 float nominalRes = (xRes + yRes) * 0.5f;
Jeff Brown678a1252013-04-09 17:46:25 -07005863
Jeff Brown4dac9012013-04-10 01:03:19 -07005864 // Precompute all of the configuration thresholds we will need.
Jeff Brown4dac9012013-04-10 01:03:19 -07005865 mConfigTickDistance = TICK_DISTANCE_MILLIMETERS * nominalRes;
5866 mConfigMinFlingVelocity =
5867 MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
5868 mConfigMaxFlingVelocity =
5869 MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
5870
5871 if (LOCAL_DEBUG) {
5872 Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId
5873 + " (" + Integer.toHexString(mCurrentSource) + "): "
Jeff Brown4dac9012013-04-10 01:03:19 -07005874 + ", mConfigTickDistance=" + mConfigTickDistance
5875 + ", mConfigMinFlingVelocity=" + mConfigMinFlingVelocity
5876 + ", mConfigMaxFlingVelocity=" + mConfigMaxFlingVelocity);
5877 }
5878 }
5879 }
Jeff Brown678a1252013-04-09 17:46:25 -07005880 }
Jeff Brown4dac9012013-04-10 01:03:19 -07005881 if (!mCurrentDeviceSupported) {
Jeff Brown678a1252013-04-09 17:46:25 -07005882 return;
5883 }
5884
Jeff Brown4dac9012013-04-10 01:03:19 -07005885 // Handle the event.
5886 final int action = event.getActionMasked();
5887 switch (action) {
Jeff Brown678a1252013-04-09 17:46:25 -07005888 case MotionEvent.ACTION_DOWN: {
Jeff Brown4dac9012013-04-10 01:03:19 -07005889 boolean caughtFling = mFlinging;
5890 finishKeys(time);
5891 finishTracking(time);
5892 mActivePointerId = event.getPointerId(0);
5893 mVelocityTracker = VelocityTracker.obtain();
5894 mVelocityTracker.addMovement(event);
Jeff Brown4dac9012013-04-10 01:03:19 -07005895 mStartX = event.getX();
5896 mStartY = event.getY();
5897 mLastX = mStartX;
5898 mLastY = mStartY;
Jeff Brown678a1252013-04-09 17:46:25 -07005899 mAccumulatedX = 0;
5900 mAccumulatedY = 0;
Jeff Brown4dac9012013-04-10 01:03:19 -07005901
5902 // If we caught a fling, then pretend that the tap slop has already
5903 // been exceeded to suppress taps whose only purpose is to stop the fling.
5904 mConsumedMovement = caughtFling;
Jeff Brown678a1252013-04-09 17:46:25 -07005905 break;
5906 }
5907
Jeff Brown4dac9012013-04-10 01:03:19 -07005908 case MotionEvent.ACTION_MOVE:
Jeff Brown678a1252013-04-09 17:46:25 -07005909 case MotionEvent.ACTION_UP: {
Jeff Brown4dac9012013-04-10 01:03:19 -07005910 if (mActivePointerId < 0) {
5911 break;
5912 }
5913 final int index = event.findPointerIndex(mActivePointerId);
5914 if (index < 0) {
5915 finishKeys(time);
5916 finishTracking(time);
5917 break;
5918 }
Jeff Brown678a1252013-04-09 17:46:25 -07005919
Jeff Brown4dac9012013-04-10 01:03:19 -07005920 mVelocityTracker.addMovement(event);
5921 final float x = event.getX(index);
5922 final float y = event.getY(index);
5923 mAccumulatedX += x - mLastX;
5924 mAccumulatedY += y - mLastY;
5925 mLastX = x;
5926 mLastY = y;
5927
5928 // Consume any accumulated movement so far.
5929 final int metaState = event.getMetaState();
5930 consumeAccumulatedMovement(time, metaState);
5931
5932 // Detect taps and flings.
5933 if (action == MotionEvent.ACTION_UP) {
Michael Wright88d7f792013-08-27 15:45:42 -07005934 if (mConsumedMovement && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
Jeff Brown4dac9012013-04-10 01:03:19 -07005935 // It might be a fling.
5936 mVelocityTracker.computeCurrentVelocity(1000, mConfigMaxFlingVelocity);
5937 final float vx = mVelocityTracker.getXVelocity(mActivePointerId);
5938 final float vy = mVelocityTracker.getYVelocity(mActivePointerId);
5939 if (!startFling(time, vx, vy)) {
5940 finishKeys(time);
Jeff Brown678a1252013-04-09 17:46:25 -07005941 }
5942 }
Jeff Brown4dac9012013-04-10 01:03:19 -07005943 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07005944 }
Jeff Brown4dac9012013-04-10 01:03:19 -07005945 break;
5946 }
5947
5948 case MotionEvent.ACTION_CANCEL: {
5949 finishKeys(time);
5950 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07005951 break;
5952 }
5953 }
Jeff Browncb1404e2011-01-15 18:14:15 -08005954 }
Jeff Brown4dac9012013-04-10 01:03:19 -07005955
5956 public void cancel(MotionEvent event) {
5957 if (mCurrentDeviceId == event.getDeviceId()
5958 && mCurrentSource == event.getSource()) {
5959 final long time = event.getEventTime();
5960 finishKeys(time);
5961 finishTracking(time);
5962 }
5963 }
5964
5965 private void finishKeys(long time) {
5966 cancelFling();
5967 sendKeyUp(time);
5968 }
5969
5970 private void finishTracking(long time) {
5971 if (mActivePointerId >= 0) {
5972 mActivePointerId = -1;
5973 mVelocityTracker.recycle();
5974 mVelocityTracker = null;
5975 }
5976 }
5977
5978 private void consumeAccumulatedMovement(long time, int metaState) {
5979 final float absX = Math.abs(mAccumulatedX);
5980 final float absY = Math.abs(mAccumulatedY);
5981 if (absX >= absY) {
5982 if (absX >= mConfigTickDistance) {
5983 mAccumulatedX = consumeAccumulatedMovement(time, metaState, mAccumulatedX,
5984 KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT);
5985 mAccumulatedY = 0;
5986 mConsumedMovement = true;
5987 }
5988 } else {
5989 if (absY >= mConfigTickDistance) {
5990 mAccumulatedY = consumeAccumulatedMovement(time, metaState, mAccumulatedY,
5991 KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN);
5992 mAccumulatedX = 0;
5993 mConsumedMovement = true;
5994 }
5995 }
5996 }
5997
5998 private float consumeAccumulatedMovement(long time, int metaState,
5999 float accumulator, int negativeKeyCode, int positiveKeyCode) {
6000 while (accumulator <= -mConfigTickDistance) {
6001 sendKeyDownOrRepeat(time, negativeKeyCode, metaState);
6002 accumulator += mConfigTickDistance;
6003 }
6004 while (accumulator >= mConfigTickDistance) {
6005 sendKeyDownOrRepeat(time, positiveKeyCode, metaState);
6006 accumulator -= mConfigTickDistance;
6007 }
6008 return accumulator;
6009 }
6010
6011 private void sendKeyDownOrRepeat(long time, int keyCode, int metaState) {
6012 if (mPendingKeyCode != keyCode) {
6013 sendKeyUp(time);
6014 mPendingKeyDownTime = time;
6015 mPendingKeyCode = keyCode;
6016 mPendingKeyRepeatCount = 0;
6017 } else {
6018 mPendingKeyRepeatCount += 1;
6019 }
6020 mPendingKeyMetaState = metaState;
6021
6022 // Note: Normally we would pass FLAG_LONG_PRESS when the repeat count is 1
6023 // but it doesn't quite make sense when simulating the events in this way.
6024 if (LOCAL_DEBUG) {
6025 Log.d(LOCAL_TAG, "Sending key down: keyCode=" + mPendingKeyCode
6026 + ", repeatCount=" + mPendingKeyRepeatCount
6027 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
6028 }
6029 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
6030 KeyEvent.ACTION_DOWN, mPendingKeyCode, mPendingKeyRepeatCount,
6031 mPendingKeyMetaState, mCurrentDeviceId,
6032 KeyEvent.FLAG_FALLBACK, mCurrentSource));
6033 }
6034
6035 private void sendKeyUp(long time) {
6036 if (mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
6037 if (LOCAL_DEBUG) {
6038 Log.d(LOCAL_TAG, "Sending key up: keyCode=" + mPendingKeyCode
6039 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
6040 }
6041 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
6042 KeyEvent.ACTION_UP, mPendingKeyCode, 0, mPendingKeyMetaState,
6043 mCurrentDeviceId, 0, KeyEvent.FLAG_FALLBACK,
6044 mCurrentSource));
6045 mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
6046 }
6047 }
6048
6049 private boolean startFling(long time, float vx, float vy) {
6050 if (LOCAL_DEBUG) {
6051 Log.d(LOCAL_TAG, "Considering fling: vx=" + vx + ", vy=" + vy
6052 + ", min=" + mConfigMinFlingVelocity);
6053 }
6054
6055 // Flings must be oriented in the same direction as the preceding movements.
6056 switch (mPendingKeyCode) {
6057 case KeyEvent.KEYCODE_DPAD_LEFT:
6058 if (-vx >= mConfigMinFlingVelocity
6059 && Math.abs(vy) < mConfigMinFlingVelocity) {
6060 mFlingVelocity = -vx;
6061 break;
6062 }
6063 return false;
6064
6065 case KeyEvent.KEYCODE_DPAD_RIGHT:
6066 if (vx >= mConfigMinFlingVelocity
6067 && Math.abs(vy) < mConfigMinFlingVelocity) {
6068 mFlingVelocity = vx;
6069 break;
6070 }
6071 return false;
6072
6073 case KeyEvent.KEYCODE_DPAD_UP:
6074 if (-vy >= mConfigMinFlingVelocity
6075 && Math.abs(vx) < mConfigMinFlingVelocity) {
6076 mFlingVelocity = -vy;
6077 break;
6078 }
6079 return false;
6080
6081 case KeyEvent.KEYCODE_DPAD_DOWN:
6082 if (vy >= mConfigMinFlingVelocity
6083 && Math.abs(vx) < mConfigMinFlingVelocity) {
6084 mFlingVelocity = vy;
6085 break;
6086 }
6087 return false;
6088 }
6089
6090 // Post the first fling event.
6091 mFlinging = postFling(time);
6092 return mFlinging;
6093 }
6094
6095 private boolean postFling(long time) {
6096 // The idea here is to estimate the time when the pointer would have
6097 // traveled one tick distance unit given the current fling velocity.
6098 // This effect creates continuity of motion.
6099 if (mFlingVelocity >= mConfigMinFlingVelocity) {
6100 long delay = (long)(mConfigTickDistance / mFlingVelocity * 1000);
6101 postAtTime(mFlingRunnable, time + delay);
6102 if (LOCAL_DEBUG) {
6103 Log.d(LOCAL_TAG, "Posted fling: velocity="
6104 + mFlingVelocity + ", delay=" + delay
6105 + ", keyCode=" + mPendingKeyCode);
6106 }
6107 return true;
6108 }
6109 return false;
6110 }
6111
6112 private void cancelFling() {
6113 if (mFlinging) {
6114 removeCallbacks(mFlingRunnable);
6115 mFlinging = false;
6116 }
6117 }
6118
6119 private final Runnable mFlingRunnable = new Runnable() {
6120 @Override
6121 public void run() {
6122 final long time = SystemClock.uptimeMillis();
6123 sendKeyDownOrRepeat(time, mPendingKeyCode, mPendingKeyMetaState);
6124 mFlingVelocity *= FLING_TICK_DECAY;
6125 if (!postFling(time)) {
6126 mFlinging = false;
6127 finishKeys(time);
6128 }
6129 }
6130 };
Jeff Browncb1404e2011-01-15 18:14:15 -08006131 }
6132
Michael Wright899d7052014-04-23 17:23:39 -07006133 final class SyntheticKeyboardHandler {
6134 public void process(KeyEvent event) {
6135 if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
6136 return;
6137 }
6138
6139 final KeyCharacterMap kcm = event.getKeyCharacterMap();
6140 final int keyCode = event.getKeyCode();
6141 final int metaState = event.getMetaState();
6142
6143 // Check for fallback actions specified by the key character map.
6144 KeyCharacterMap.FallbackAction fallbackAction =
6145 kcm.getFallbackAction(keyCode, metaState);
6146 if (fallbackAction != null) {
6147 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
6148 KeyEvent fallbackEvent = KeyEvent.obtain(
6149 event.getDownTime(), event.getEventTime(),
6150 event.getAction(), fallbackAction.keyCode,
6151 event.getRepeatCount(), fallbackAction.metaState,
6152 event.getDeviceId(), event.getScanCode(),
6153 flags, event.getSource(), null);
6154 fallbackAction.recycle();
6155 enqueueInputEvent(fallbackEvent);
6156 }
6157 }
6158 }
6159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006160 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08006161 * Returns true if the key is used for keyboard navigation.
6162 * @param keyEvent The key event.
6163 * @return True if the key is used for keyboard navigation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006164 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08006165 private static boolean isNavigationKey(KeyEvent keyEvent) {
6166 switch (keyEvent.getKeyCode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006167 case KeyEvent.KEYCODE_DPAD_LEFT:
6168 case KeyEvent.KEYCODE_DPAD_RIGHT:
6169 case KeyEvent.KEYCODE_DPAD_UP:
6170 case KeyEvent.KEYCODE_DPAD_DOWN:
Jeff Brown4e6319b2010-12-13 10:36:51 -08006171 case KeyEvent.KEYCODE_DPAD_CENTER:
6172 case KeyEvent.KEYCODE_PAGE_UP:
6173 case KeyEvent.KEYCODE_PAGE_DOWN:
6174 case KeyEvent.KEYCODE_MOVE_HOME:
6175 case KeyEvent.KEYCODE_MOVE_END:
6176 case KeyEvent.KEYCODE_TAB:
6177 case KeyEvent.KEYCODE_SPACE:
6178 case KeyEvent.KEYCODE_ENTER:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006179 return true;
6180 }
6181 return false;
6182 }
6183
6184 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08006185 * Returns true if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006186 * @param keyEvent The key event.
Jeff Brown4e6319b2010-12-13 10:36:51 -08006187 * @return True if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006188 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08006189 private static boolean isTypingKey(KeyEvent keyEvent) {
6190 return keyEvent.getUnicodeChar() > 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006191 }
6192
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006193 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08006194 * 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 -08006195 * @param event The key event.
6196 * @return Whether this key event should be consumed (meaning the act of
6197 * leaving touch mode alone is considered the event).
6198 */
6199 private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08006200 // Only relevant in touch mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006201 if (!mAttachInfo.mInTouchMode) {
6202 return false;
6203 }
6204
Jeff Brown4e6319b2010-12-13 10:36:51 -08006205 // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
6206 final int action = event.getAction();
6207 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006208 return false;
6209 }
6210
Jeff Brown4e6319b2010-12-13 10:36:51 -08006211 // Don't leave touch mode if the IME told us not to.
6212 if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
6213 return false;
6214 }
6215
6216 // If the key can be used for keyboard navigation then leave touch mode
6217 // and select a focused view if needed (in ensureTouchMode).
6218 // When a new focused view is selected, we consume the navigation key because
6219 // navigation doesn't make much sense unless a view already has focus so
6220 // the key's purpose is to set focus.
6221 if (isNavigationKey(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006222 return ensureTouchMode(false);
6223 }
Jeff Brown4e6319b2010-12-13 10:36:51 -08006224
6225 // If the key can be used for typing then leave touch mode
6226 // and select a focused view if needed (in ensureTouchMode).
6227 // Always allow the view to process the typing key.
6228 if (isTypingKey(event)) {
6229 ensureTouchMode(false);
6230 return false;
6231 }
6232
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006233 return false;
6234 }
6235
Christopher Tatea53146c2010-09-07 11:57:52 -07006236 /* drag/drop */
Christopher Tate407b4e92010-11-30 17:14:08 -08006237 void setLocalDragState(Object obj) {
6238 mLocalDragState = obj;
6239 }
6240
Christopher Tatea53146c2010-09-07 11:57:52 -07006241 private void handleDragEvent(DragEvent event) {
6242 // From the root, only drag start/end/location are dispatched. entered/exited
6243 // are determined and dispatched by the viewgroup hierarchy, who then report
6244 // that back here for ultimate reporting back to the framework.
6245 if (mView != null && mAdded) {
6246 final int what = event.mAction;
6247
Vladislav Kaznacheev7fe1f792016-07-14 17:15:02 -07006248 // Cache the drag description when the operation starts, then fill it in
6249 // on subsequent calls as a convenience
6250 if (what == DragEvent.ACTION_DRAG_STARTED) {
6251 mCurrentDragView = null; // Start the current-recipient tracking
6252 mDragDescription = event.mClipDescription;
6253 } else {
Vladislav Kaznacheevcd84cfa2016-07-26 15:17:49 -07006254 if (what == DragEvent.ACTION_DRAG_ENDED) {
6255 mDragDescription = null;
6256 }
Vladislav Kaznacheev7fe1f792016-07-14 17:15:02 -07006257 event.mClipDescription = mDragDescription;
6258 }
6259
Christopher Tatea53146c2010-09-07 11:57:52 -07006260 if (what == DragEvent.ACTION_DRAG_EXITED) {
6261 // A direct EXITED event means that the window manager knows we've just crossed
6262 // a window boundary, so the current drag target within this one must have
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006263 // just been exited. Send the EXITED notification to the current drag view, if any.
Vadim Tryshev45bee6b2016-09-19 11:00:37 -07006264 if (View.sCascadedDragDrop) {
Vadim Tryshevef128112016-09-16 14:05:53 -07006265 mView.dispatchDragEnterExitInPreN(event);
6266 }
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006267 setDragFocus(null, event);
Christopher Tatea53146c2010-09-07 11:57:52 -07006268 } else {
Christopher Tatea53146c2010-09-07 11:57:52 -07006269 // For events with a [screen] location, translate into window coordinates
6270 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
6271 mDragPoint.set(event.mX, event.mY);
6272 if (mTranslator != null) {
6273 mTranslator.translatePointInScreenToAppWindow(mDragPoint);
6274 }
6275
6276 if (mCurScrollY != 0) {
6277 mDragPoint.offset(0, mCurScrollY);
6278 }
6279
6280 event.mX = mDragPoint.x;
6281 event.mY = mDragPoint.y;
6282 }
6283
6284 // Remember who the current drag target is pre-dispatch
6285 final View prevDragView = mCurrentDragView;
6286
Vadim Tryshev69733172016-09-30 17:25:30 -07006287 if (what == DragEvent.ACTION_DROP && event.mClipData != null) {
6288 event.mClipData.prepareToEnterProcess();
Vladislav Kaznacheev854d3f22016-08-11 10:19:36 -07006289 }
6290
Christopher Tatea53146c2010-09-07 11:57:52 -07006291 // Now dispatch the drag/drop event
Chris Tated4533f12010-10-19 15:15:08 -07006292 boolean result = mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07006293
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006294 if (what == DragEvent.ACTION_DRAG_LOCATION && !event.mEventHandlerWasCalled) {
6295 // If the LOCATION event wasn't delivered to any handler, no view now has a drag
6296 // focus.
6297 setDragFocus(null, event);
6298 }
6299
Christopher Tatea53146c2010-09-07 11:57:52 -07006300 // If we changed apparent drag target, tell the OS about it
6301 if (prevDragView != mCurrentDragView) {
6302 try {
6303 if (prevDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07006304 mWindowSession.dragRecipientExited(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07006305 }
6306 if (mCurrentDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07006307 mWindowSession.dragRecipientEntered(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07006308 }
6309 } catch (RemoteException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006310 Slog.e(mTag, "Unable to note drag target change");
Christopher Tatea53146c2010-09-07 11:57:52 -07006311 }
Christopher Tatea53146c2010-09-07 11:57:52 -07006312 }
Chris Tated4533f12010-10-19 15:15:08 -07006313
Christopher Tate407b4e92010-11-30 17:14:08 -08006314 // Report the drop result when we're done
Chris Tated4533f12010-10-19 15:15:08 -07006315 if (what == DragEvent.ACTION_DROP) {
6316 try {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006317 Log.i(mTag, "Reporting drop result: " + result);
Jeff Brown98365d72012-08-19 20:30:52 -07006318 mWindowSession.reportDropResult(mWindow, result);
Chris Tated4533f12010-10-19 15:15:08 -07006319 } catch (RemoteException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006320 Log.e(mTag, "Unable to report drop result");
Chris Tated4533f12010-10-19 15:15:08 -07006321 }
6322 }
Christopher Tate407b4e92010-11-30 17:14:08 -08006323
Vladislav Kaznacheev82063912015-11-20 14:20:13 -08006324 // When the drag operation ends, reset drag-related state
Christopher Tate407b4e92010-11-30 17:14:08 -08006325 if (what == DragEvent.ACTION_DRAG_ENDED) {
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006326 mCurrentDragView = null;
Christopher Tate407b4e92010-11-30 17:14:08 -08006327 setLocalDragState(null);
Vladislav Kaznacheev82063912015-11-20 14:20:13 -08006328 mAttachInfo.mDragToken = null;
Vladislav Kaznacheev4f639742015-11-18 13:21:35 -08006329 if (mAttachInfo.mDragSurface != null) {
6330 mAttachInfo.mDragSurface.release();
6331 mAttachInfo.mDragSurface = null;
6332 }
Christopher Tate407b4e92010-11-30 17:14:08 -08006333 }
Christopher Tatea53146c2010-09-07 11:57:52 -07006334 }
6335 }
6336 event.recycle();
6337 }
6338
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006339 public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
6340 if (mSeq != args.seq) {
6341 // The sequence has changed, so we need to update our value and make
6342 // sure to do a traversal afterward so the window manager is given our
6343 // most recent data.
6344 mSeq = args.seq;
6345 mAttachInfo.mForceReportNewAttributes = true;
Igor Murashkina86ab6402013-08-30 12:58:36 -07006346 scheduleTraversals();
Joe Onorato14782f72011-01-25 19:53:17 -08006347 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006348 if (mView == null) return;
6349 if (args.localChanges != 0) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006350 mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006351 }
Chris Craikd36a81f2014-07-17 10:16:51 -07006352
6353 int visibility = args.globalVisibility&View.SYSTEM_UI_CLEARABLE_FLAGS;
6354 if (visibility != mAttachInfo.mGlobalSystemUiVisibility) {
6355 mAttachInfo.mGlobalSystemUiVisibility = visibility;
6356 mView.dispatchSystemUiVisibilityChanged(visibility);
Dianne Hackborncf675782012-05-10 15:07:24 -07006357 }
Joe Onorato664644d2011-01-23 17:53:23 -08006358 }
6359
Phil Weaver964c68e2016-10-27 16:22:05 -07006360 /**
6361 * Notify that the window title changed
6362 */
6363 public void onWindowTitleChanged() {
6364 mAttachInfo.mForceReportNewAttributes = true;
6365 }
6366
Craig Mautner9c795042014-10-28 19:59:59 -07006367 public void handleDispatchWindowShown() {
6368 mAttachInfo.mTreeObserver.dispatchOnWindowShown();
6369 }
6370
Clara Bayarrifcd7e802016-03-10 12:58:18 +00006371 public void handleRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
Clara Bayarri75e09792015-07-29 16:20:40 +01006372 Bundle data = new Bundle();
6373 ArrayList<KeyboardShortcutGroup> list = new ArrayList<>();
6374 if (mView != null) {
Clara Bayarrifcd7e802016-03-10 12:58:18 +00006375 mView.requestKeyboardShortcuts(list, deviceId);
Clara Bayarri75e09792015-07-29 16:20:40 +01006376 }
6377 data.putParcelableArrayList(WindowManager.PARCEL_KEY_SHORTCUTS_ARRAY, list);
6378 try {
6379 receiver.send(0, data);
6380 } catch (RemoteException e) {
6381 }
6382 }
6383
Christopher Tate2c095f32010-10-04 14:13:40 -07006384 public void getLastTouchPoint(Point outLocation) {
6385 outLocation.x = (int) mLastTouchPoint.x;
6386 outLocation.y = (int) mLastTouchPoint.y;
6387 }
6388
Vladislav Kaznacheevba761122016-01-22 12:09:45 -08006389 public int getLastTouchSource() {
6390 return mLastTouchSource;
6391 }
6392
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006393 public void setDragFocus(View newDragTarget, DragEvent event) {
Vadim Tryshev45bee6b2016-09-19 11:00:37 -07006394 if (mCurrentDragView != newDragTarget && !View.sCascadedDragDrop) {
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006395 // Send EXITED and ENTERED notifications to the old and new drag focus views.
6396
6397 final float tx = event.mX;
6398 final float ty = event.mY;
6399 final int action = event.mAction;
Vadim Trysheva61efa42016-09-28 15:15:52 -07006400 final ClipData td = event.mClipData;
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006401 // Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED.
6402 event.mX = 0;
6403 event.mY = 0;
Vadim Trysheva61efa42016-09-28 15:15:52 -07006404 event.mClipData = null;
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006405
6406 if (mCurrentDragView != null) {
6407 event.mAction = DragEvent.ACTION_DRAG_EXITED;
6408 mCurrentDragView.callDragEventHandler(event);
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006409 }
6410
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006411 if (newDragTarget != null) {
6412 event.mAction = DragEvent.ACTION_DRAG_ENTERED;
6413 newDragTarget.callDragEventHandler(event);
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006414 }
6415
6416 event.mAction = action;
6417 event.mX = tx;
6418 event.mY = ty;
Vadim Trysheva61efa42016-09-28 15:15:52 -07006419 event.mClipData = td;
Christopher Tatea53146c2010-09-07 11:57:52 -07006420 }
Vadim Tryshevef128112016-09-16 14:05:53 -07006421
6422 mCurrentDragView = newDragTarget;
Christopher Tatea53146c2010-09-07 11:57:52 -07006423 }
6424
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006425 private AudioManager getAudioManager() {
6426 if (mView == null) {
6427 throw new IllegalStateException("getAudioManager called when there is no mView");
6428 }
6429 if (mAudioManager == null) {
6430 mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
6431 }
6432 return mAudioManager;
6433 }
6434
Dake Gud9dbd272018-03-13 11:38:42 -07006435 private @Nullable AutofillManager getAutofillManager() {
6436 if (mView instanceof ViewGroup) {
6437 ViewGroup decorView = (ViewGroup) mView;
6438 if (decorView.getChildCount() > 0) {
6439 // We cannot use decorView's Context for querying AutofillManager: DecorView's
6440 // context is based on Application Context, it would allocate a different
6441 // AutofillManager instance.
6442 return decorView.getChildAt(0).getContext()
6443 .getSystemService(AutofillManager.class);
6444 }
6445 }
6446 return null;
6447 }
6448
6449 private boolean isAutofillUiShowing() {
6450 AutofillManager afm = getAutofillManager();
6451 if (afm == null) {
6452 return false;
6453 }
6454 return afm.isAutofillUiShowing();
6455 }
6456
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006457 public AccessibilityInteractionController getAccessibilityInteractionController() {
6458 if (mView == null) {
6459 throw new IllegalStateException("getAccessibilityInteractionController"
6460 + " called when there is no mView");
6461 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07006462 if (mAccessibilityInteractionController == null) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006463 mAccessibilityInteractionController = new AccessibilityInteractionController(this);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006464 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07006465 return mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006466 }
6467
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07006468 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
6469 boolean insetsPending) throws RemoteException {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006470
6471 float appScale = mAttachInfo.mApplicationScale;
Mitsuru Oshima3d914922009-05-13 22:29:15 -07006472 boolean restore = false;
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006473 if (params != null && mTranslator != null) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07006474 restore = true;
6475 params.backup();
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006476 mTranslator.translateWindowLayout(params);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07006477 }
Robert Carrc6d5af52018-02-26 17:46:00 -08006478
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006479 if (params != null) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006480 if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
Bryce Leef858b572017-06-29 14:03:33 -07006481
Robert Carrc6d5af52018-02-26 17:46:00 -08006482 if (mOrigWindowType != params.type) {
6483 // For compatibility with old apps, don't crash here.
6484 if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
6485 Slog.w(mTag, "Window type can not be changed after "
6486 + "the window is added; ignoring change of " + mView);
6487 params.type = mOrigWindowType;
6488 }
6489 }
Dianne Hackborn180c4842011-09-13 12:39:25 -07006490 }
Robert Carrc6d5af52018-02-26 17:46:00 -08006491
chaviwbe43ac82018-04-04 15:14:49 -07006492 long frameNumber = -1;
6493 if (mSurface.isValid()) {
6494 frameNumber = mSurface.getNextFrameNumber();
6495 }
6496
6497 int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params,
Dianne Hackborn189ee182010-12-02 21:48:53 -08006498 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
chaviwbe43ac82018-04-04 15:14:49 -07006499 (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
6500 insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006501 mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
Adrian Roos5c6b6222017-11-07 17:36:10 +01006502 mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout,
Andrii Kulian44607962017-03-16 11:06:24 -07006503 mPendingMergedConfiguration, mSurface);
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08006504
6505 mPendingAlwaysConsumeNavBar =
6506 (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR) != 0;
6507
Mitsuru Oshima3d914922009-05-13 22:29:15 -07006508 if (restore) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07006509 params.restore();
Mitsuru Oshima3d914922009-05-13 22:29:15 -07006510 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006511
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006512 if (mTranslator != null) {
6513 mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006514 mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006515 mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
6516 mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
Adrian Roosfa104232014-06-20 16:10:14 -07006517 mTranslator.translateRectInScreenToAppWindow(mPendingStableInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07006518 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07006519 return relayoutResult;
6520 }
Romain Guy8506ab42009-06-11 17:35:47 -07006521
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07006522 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006523 * {@inheritDoc}
6524 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07006525 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006526 public void playSoundEffect(int effectId) {
6527 checkThread();
6528
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07006529 try {
6530 final AudioManager audioManager = getAudioManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006531
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07006532 switch (effectId) {
6533 case SoundEffectConstants.CLICK:
6534 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
6535 return;
6536 case SoundEffectConstants.NAVIGATION_DOWN:
6537 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
6538 return;
6539 case SoundEffectConstants.NAVIGATION_LEFT:
6540 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
6541 return;
6542 case SoundEffectConstants.NAVIGATION_RIGHT:
6543 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
6544 return;
6545 case SoundEffectConstants.NAVIGATION_UP:
6546 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
6547 return;
6548 default:
6549 throw new IllegalArgumentException("unknown effect id " + effectId +
6550 " not defined in " + SoundEffectConstants.class.getCanonicalName());
6551 }
6552 } catch (IllegalStateException e) {
6553 // Exception thrown by getAudioManager() when mView is null
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006554 Log.e(mTag, "FATAL EXCEPTION when attempting to play sound effect: " + e);
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07006555 e.printStackTrace();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006556 }
6557 }
6558
6559 /**
6560 * {@inheritDoc}
6561 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07006562 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006563 public boolean performHapticFeedback(int effectId, boolean always) {
6564 try {
Jeff Brown98365d72012-08-19 20:30:52 -07006565 return mWindowSession.performHapticFeedback(mWindow, effectId, always);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006566 } catch (RemoteException e) {
6567 return false;
6568 }
6569 }
6570
6571 /**
6572 * {@inheritDoc}
6573 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07006574 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006575 public View focusSearch(View focused, int direction) {
6576 checkThread();
6577 if (!(mView instanceof ViewGroup)) {
6578 return null;
6579 }
6580 return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
6581 }
6582
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08006583 /**
6584 * {@inheritDoc}
6585 */
6586 @Override
Evan Rosky57223312017-02-08 14:42:45 -08006587 public View keyboardNavigationClusterSearch(View currentCluster,
6588 @FocusDirection int direction) {
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08006589 checkThread();
Vadim Tryshevb5ced222017-01-17 19:31:35 -08006590 return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
6591 mView, currentCluster, direction);
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08006592 }
6593
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006594 public void debug() {
6595 mView.debug();
6596 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006597
Jeff Brown5182c782013-10-15 20:31:52 -07006598 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
6599 String innerPrefix = prefix + " ";
6600 writer.print(prefix); writer.println("ViewRoot:");
6601 writer.print(innerPrefix); writer.print("mAdded="); writer.print(mAdded);
6602 writer.print(" mRemoved="); writer.println(mRemoved);
6603 writer.print(innerPrefix); writer.print("mConsumeBatchedInputScheduled=");
6604 writer.println(mConsumeBatchedInputScheduled);
Michael Wright9d744c72014-02-18 21:27:42 -08006605 writer.print(innerPrefix); writer.print("mConsumeBatchedInputImmediatelyScheduled=");
6606 writer.println(mConsumeBatchedInputImmediatelyScheduled);
Jeff Brown5182c782013-10-15 20:31:52 -07006607 writer.print(innerPrefix); writer.print("mPendingInputEventCount=");
6608 writer.println(mPendingInputEventCount);
6609 writer.print(innerPrefix); writer.print("mProcessInputEventsScheduled=");
6610 writer.println(mProcessInputEventsScheduled);
6611 writer.print(innerPrefix); writer.print("mTraversalScheduled=");
6612 writer.print(mTraversalScheduled);
Daniel Koulomzin087ae472015-12-16 17:52:25 -05006613 writer.print(innerPrefix); writer.print("mIsAmbientMode=");
6614 writer.print(mIsAmbientMode);
Jeff Brown5182c782013-10-15 20:31:52 -07006615 if (mTraversalScheduled) {
6616 writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
6617 } else {
6618 writer.println();
6619 }
6620 mFirstInputStage.dump(innerPrefix, writer);
6621
6622 mChoreographer.dump(prefix, writer);
6623
6624 writer.print(prefix); writer.println("View Hierarchy:");
6625 dumpViewHierarchy(innerPrefix, writer, mView);
6626 }
6627
6628 private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) {
6629 writer.print(prefix);
6630 if (view == null) {
6631 writer.println("null");
6632 return;
6633 }
6634 writer.println(view.toString());
6635 if (!(view instanceof ViewGroup)) {
6636 return;
6637 }
6638 ViewGroup grp = (ViewGroup)view;
6639 final int N = grp.getChildCount();
6640 if (N <= 0) {
6641 return;
6642 }
6643 prefix = prefix + " ";
6644 for (int i=0; i<N; i++) {
6645 dumpViewHierarchy(prefix, writer, grp.getChildAt(i));
6646 }
6647 }
6648
Romain Guy211370f2012-02-01 16:10:55 -08006649 public void dumpGfxInfo(int[] info) {
Romain Guy54ab3472012-06-14 12:52:53 -07006650 info[0] = info[1] = 0;
Romain Guy65b345f2011-07-27 18:51:50 -07006651 if (mView != null) {
6652 getGfxInfo(mView, info);
Romain Guy65b345f2011-07-27 18:51:50 -07006653 }
6654 }
6655
Romain Guya998dff2012-03-23 18:58:36 -07006656 private static void getGfxInfo(View view, int[] info) {
Chris Craik64a12e12014-03-28 18:12:12 -07006657 RenderNode renderNode = view.mRenderNode;
Romain Guy65b345f2011-07-27 18:51:50 -07006658 info[0]++;
Chris Craik64a12e12014-03-28 18:12:12 -07006659 if (renderNode != null) {
John Reckfe5e7b72014-05-23 17:42:28 -07006660 info[1] += renderNode.getDebugSize();
Romain Guy65b345f2011-07-27 18:51:50 -07006661 }
6662
6663 if (view instanceof ViewGroup) {
6664 ViewGroup group = (ViewGroup) view;
6665
6666 int count = group.getChildCount();
6667 for (int i = 0; i < count; i++) {
6668 getGfxInfo(group.getChildAt(i), info);
6669 }
6670 }
6671 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006672
Craig Mautner8f303ad2013-06-14 11:32:22 -07006673 /**
6674 * @param immediate True, do now if not in traversal. False, put on queue and do later.
6675 * @return True, request has been queued. False, request has been completed.
6676 */
6677 boolean die(boolean immediate) {
Craig Mautnerdf2390a2012-08-29 20:59:22 -07006678 // Make sure we do execute immediately if we are in the middle of a traversal or the damage
6679 // done by dispatchDetachedFromWindow will cause havoc on return.
6680 if (immediate && !mIsInTraversal) {
Dianne Hackborn94d69142009-09-28 22:14:42 -07006681 doDie();
Craig Mautner8f303ad2013-06-14 11:32:22 -07006682 return false;
Dianne Hackborn94d69142009-09-28 22:14:42 -07006683 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07006684
6685 if (!mIsDrawing) {
6686 destroyHardwareRenderer();
6687 } else {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006688 Log.e(mTag, "Attempting to destroy the window while drawing!\n" +
Craig Mautner8f303ad2013-06-14 11:32:22 -07006689 " window=" + this + ", title=" + mWindowAttributes.getTitle());
6690 }
6691 mHandler.sendEmptyMessage(MSG_DIE);
6692 return true;
Dianne Hackborn94d69142009-09-28 22:14:42 -07006693 }
6694
6695 void doDie() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006696 checkThread();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006697 if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006698 synchronized (this) {
Craig Mautner8f303ad2013-06-14 11:32:22 -07006699 if (mRemoved) {
6700 return;
6701 }
6702 mRemoved = true;
Romain Guy16260e72011-09-01 14:26:11 -07006703 if (mAdded) {
Romain Guy16260e72011-09-01 14:26:11 -07006704 dispatchDetachedFromWindow();
6705 }
6706
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006707 if (mAdded && !mFirst) {
Romain Guy29d89972010-09-22 16:10:57 -07006708 destroyHardwareRenderer();
6709
Romain Guyedbca122012-04-04 18:25:53 -07006710 if (mView != null) {
6711 int viewVisibility = mView.getVisibility();
6712 boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
6713 if (mWindowAttributesChanged || viewVisibilityChanged) {
6714 // If layout params have been changed, first give them
6715 // to the window manager to make sure it has the correct
6716 // animation info.
6717 try {
6718 if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
Jeff Brown98365d72012-08-19 20:30:52 -07006719 & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
6720 mWindowSession.finishDrawing(mWindow);
Romain Guyedbca122012-04-04 18:25:53 -07006721 }
6722 } catch (RemoteException e) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006723 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006724 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07006725
Romain Guyedbca122012-04-04 18:25:53 -07006726 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006727 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006728 }
Romain Guyedbca122012-04-04 18:25:53 -07006729
6730 mAdded = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006731 }
Craig Mautner05eb7302013-06-03 17:24:21 -07006732 WindowManagerGlobal.getInstance().doRemoveView(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006733 }
6734
Dianne Hackborn5fd21692011-06-07 14:09:47 -07006735 public void requestUpdateConfiguration(Configuration config) {
Jeff Browna175a5b2012-02-15 19:18:31 -08006736 Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
6737 mHandler.sendMessage(msg);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07006738 }
6739
Dianne Hackborna53de062012-05-08 18:53:51 -07006740 public void loadSystemProperties() {
Romain Guy5bb3c732012-11-29 17:52:58 -08006741 mHandler.post(new Runnable() {
6742 @Override
6743 public void run() {
6744 // Profiling
6745 mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false);
6746 profileRendering(mAttachInfo.mHasWindowFocus);
6747
6748 // Hardware rendering
Stan Iliev45faba52016-06-28 13:33:15 -04006749 if (mAttachInfo.mThreadedRenderer != null) {
6750 if (mAttachInfo.mThreadedRenderer.loadSystemProperties()) {
Romain Guy5bb3c732012-11-29 17:52:58 -08006751 invalidate();
6752 }
6753 }
6754
6755 // Layout debugging
6756 boolean layout = SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false);
6757 if (layout != mAttachInfo.mDebugLayout) {
6758 mAttachInfo.mDebugLayout = layout;
6759 if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
6760 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
6761 }
6762 }
Dianne Hackborna53de062012-05-08 18:53:51 -07006763 }
Romain Guy5bb3c732012-11-29 17:52:58 -08006764 });
Dianne Hackborna53de062012-05-08 18:53:51 -07006765 }
6766
Romain Guy29d89972010-09-22 16:10:57 -07006767 private void destroyHardwareRenderer() {
Stan Iliev45faba52016-06-28 13:33:15 -04006768 ThreadedRenderer hardwareRenderer = mAttachInfo.mThreadedRenderer;
Romain Guya998dff2012-03-23 18:58:36 -07006769
6770 if (hardwareRenderer != null) {
6771 if (mView != null) {
6772 hardwareRenderer.destroyHardwareResources(mView);
6773 }
John Reckf47a5942014-06-30 16:20:04 -07006774 hardwareRenderer.destroy();
Romain Guya998dff2012-03-23 18:58:36 -07006775 hardwareRenderer.setRequested(false);
6776
Stan Iliev45faba52016-06-28 13:33:15 -04006777 mAttachInfo.mThreadedRenderer = null;
Chris Craikd36a81f2014-07-17 10:16:51 -07006778 mAttachInfo.mHardwareAccelerated = false;
Romain Guy29d89972010-09-22 16:10:57 -07006779 }
6780 }
6781
Andrii Kulian44607962017-03-16 11:06:24 -07006782 private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Filip Gruszczynski2217f612015-05-26 11:32:08 -07006783 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
Andrii Kulian44607962017-03-16 11:06:24 -07006784 MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
Adrian Roos5c6b6222017-11-07 17:36:10 +01006785 boolean alwaysConsumeNavBar, int displayId,
6786 DisplayCutout.ParcelableWrapper displayCutout) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006787 if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
Svetoslav Ganov758143e2012-08-06 16:40:27 -07006788 + " contentInsets=" + contentInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006789 + " visibleInsets=" + visibleInsets.toShortString()
Chong Zhangd153c4f2015-11-06 20:26:40 -08006790 + " reportDraw=" + reportDraw
6791 + " backDropFrame=" + backDropFrame);
Chong Zhangdcee1de2015-10-06 10:26:00 -07006792
6793 // Tell all listeners that we are resizing the window so that the chrome can get
6794 // updated as fast as possible on a separate thread,
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09006795 if (mDragResizing && mUseMTRenderer) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08006796 boolean fullscreen = frame.equals(backDropFrame);
Chong Zhangdcee1de2015-10-06 10:26:00 -07006797 synchronized (mWindowCallbacks) {
6798 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08006799 mWindowCallbacks.get(i).onWindowSizeIsChanging(backDropFrame, fullscreen,
6800 visibleInsets, stableInsets);
Chong Zhangdcee1de2015-10-06 10:26:00 -07006801 }
6802 }
6803 }
6804
Svetoslav Ganov758143e2012-08-06 16:40:27 -07006805 Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006806 if (mTranslator != null) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07006807 mTranslator.translateRectInScreenToAppWindow(frame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006808 mTranslator.translateRectInScreenToAppWindow(overscanInsets);
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07006809 mTranslator.translateRectInScreenToAppWindow(contentInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006810 mTranslator.translateRectInScreenToAppWindow(visibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07006811 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07006812 SomeArgs args = SomeArgs.obtain();
6813 final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
6814 args.arg1 = sameProcessCall ? new Rect(frame) : frame;
6815 args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets;
6816 args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
Andrii Kulian44607962017-03-16 11:06:24 -07006817 args.arg4 = sameProcessCall && mergedConfiguration != null
Wale Ogunwalecdc8ada2017-03-30 13:55:36 -07006818 ? new MergedConfiguration(mergedConfiguration) : mergedConfiguration;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006819 args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
Adrian Roosfa104232014-06-20 16:10:14 -07006820 args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
Filip Gruszczynski2217f612015-05-26 11:32:08 -07006821 args.arg7 = sameProcessCall ? new Rect(outsets) : outsets;
Jorim Jaggia7262a82015-11-03 15:15:40 +01006822 args.arg8 = sameProcessCall ? new Rect(backDropFrame) : backDropFrame;
Adrian Roos5c6b6222017-11-07 17:36:10 +01006823 args.arg9 = displayCutout.get(); // DisplayCutout is immutable.
Jorim Jaggia4a58ef2016-01-27 02:10:08 -08006824 args.argi1 = forceLayout ? 1 : 0;
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08006825 args.argi2 = alwaysConsumeNavBar ? 1 : 0;
Andrii Kulianb047b8b2017-02-08 18:38:26 -08006826 args.argi3 = displayId;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07006827 msg.obj = args;
Jeff Browna175a5b2012-02-15 19:18:31 -08006828 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006829 }
Chet Haase1f4786b2011-11-02 10:51:52 -07006830
Craig Mautner5702d4d2012-06-30 14:10:16 -07006831 public void dispatchMoved(int newX, int newY) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006832 if (DEBUG_LAYOUT) Log.v(mTag, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
Craig Mautner5702d4d2012-06-30 14:10:16 -07006833 if (mTranslator != null) {
6834 PointF point = new PointF(newX, newY);
6835 mTranslator.translatePointInScreenToAppWindow(point);
6836 newX = (int) (point.x + 0.5);
6837 newY = (int) (point.y + 0.5);
6838 }
6839 Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY);
6840 mHandler.sendMessage(msg);
6841 }
6842
Jeff Brown4952dfd2011-11-30 19:23:22 -08006843 /**
6844 * Represents a pending input event that is waiting in a queue.
6845 *
6846 * Input events are processed in serial order by the timestamp specified by
Romain Guy211370f2012-02-01 16:10:55 -08006847 * {@link InputEvent#getEventTimeNano()}. In general, the input dispatcher delivers
Jeff Brown4952dfd2011-11-30 19:23:22 -08006848 * one input event to the application at a time and waits for the application
6849 * to finish handling it before delivering the next one.
6850 *
6851 * However, because the application or IME can synthesize and inject multiple
6852 * key events at a time without going through the input dispatcher, we end up
6853 * needing a queue on the application's side.
6854 */
6855 private static final class QueuedInputEvent {
Jeff Brownf9e989d2013-04-04 23:04:03 -07006856 public static final int FLAG_DELIVER_POST_IME = 1 << 0;
6857 public static final int FLAG_DEFERRED = 1 << 1;
6858 public static final int FLAG_FINISHED = 1 << 2;
6859 public static final int FLAG_FINISHED_HANDLED = 1 << 3;
6860 public static final int FLAG_RESYNTHESIZED = 1 << 4;
Michael Wright899d7052014-04-23 17:23:39 -07006861 public static final int FLAG_UNHANDLED = 1 << 5;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006862
6863 public QueuedInputEvent mNext;
6864
6865 public InputEvent mEvent;
Jeff Brown32cbc38552011-12-01 14:01:49 -08006866 public InputEventReceiver mReceiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006867 public int mFlags;
Jeff Brownf9e989d2013-04-04 23:04:03 -07006868
6869 public boolean shouldSkipIme() {
6870 if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
6871 return true;
6872 }
6873 return mEvent instanceof MotionEvent
Prashant Malanifecbc672016-07-22 15:38:05 -07006874 && (mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
6875 || mEvent.isFromSource(InputDevice.SOURCE_ROTARY_ENCODER));
Jeff Brownf9e989d2013-04-04 23:04:03 -07006876 }
Michael Wright899d7052014-04-23 17:23:39 -07006877
6878 public boolean shouldSendToSynthesizer() {
6879 if ((mFlags & FLAG_UNHANDLED) != 0) {
6880 return true;
6881 }
6882
6883 return false;
6884 }
Michael Wright06a79252014-05-05 17:45:29 -07006885
6886 @Override
6887 public String toString() {
6888 StringBuilder sb = new StringBuilder("QueuedInputEvent{flags=");
6889 boolean hasPrevious = false;
6890 hasPrevious = flagToString("DELIVER_POST_IME", FLAG_DELIVER_POST_IME, hasPrevious, sb);
6891 hasPrevious = flagToString("DEFERRED", FLAG_DEFERRED, hasPrevious, sb);
6892 hasPrevious = flagToString("FINISHED", FLAG_FINISHED, hasPrevious, sb);
6893 hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb);
6894 hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb);
6895 hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb);
6896 if (!hasPrevious) {
6897 sb.append("0");
6898 }
6899 sb.append(", hasNextQueuedEvent=" + (mEvent != null ? "true" : "false"));
6900 sb.append(", hasInputEventReceiver=" + (mReceiver != null ? "true" : "false"));
6901 sb.append(", mEvent=" + mEvent + "}");
6902 return sb.toString();
6903 }
6904
6905 private boolean flagToString(String name, int flag,
6906 boolean hasPrevious, StringBuilder sb) {
6907 if ((mFlags & flag) != 0) {
6908 if (hasPrevious) {
6909 sb.append("|");
6910 }
6911 sb.append(name);
6912 return true;
6913 }
6914 return hasPrevious;
6915 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08006916 }
6917
6918 private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
Jeff Brown32cbc38552011-12-01 14:01:49 -08006919 InputEventReceiver receiver, int flags) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08006920 QueuedInputEvent q = mQueuedInputEventPool;
6921 if (q != null) {
6922 mQueuedInputEventPoolSize -= 1;
6923 mQueuedInputEventPool = q.mNext;
6924 q.mNext = null;
6925 } else {
6926 q = new QueuedInputEvent();
Jeff Brown46b9ac02010-04-22 18:58:52 -07006927 }
6928
Jeff Brown4952dfd2011-11-30 19:23:22 -08006929 q.mEvent = event;
Jeff Brown32cbc38552011-12-01 14:01:49 -08006930 q.mReceiver = receiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006931 q.mFlags = flags;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006932 return q;
6933 }
6934
6935 private void recycleQueuedInputEvent(QueuedInputEvent q) {
6936 q.mEvent = null;
Jeff Brown32cbc38552011-12-01 14:01:49 -08006937 q.mReceiver = null;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006938
6939 if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
6940 mQueuedInputEventPoolSize += 1;
6941 q.mNext = mQueuedInputEventPool;
6942 mQueuedInputEventPool = q;
6943 }
6944 }
6945
Jeff Brownf9261d22012-02-03 13:49:15 -08006946 void enqueueInputEvent(InputEvent event) {
6947 enqueueInputEvent(event, null, 0, false);
6948 }
6949
Jeff Brown4952dfd2011-11-30 19:23:22 -08006950 void enqueueInputEvent(InputEvent event,
Jeff Brownf9261d22012-02-03 13:49:15 -08006951 InputEventReceiver receiver, int flags, boolean processImmediately) {
Michael Wright5bd69e62015-05-14 14:48:08 +01006952 adjustInputEventForCompatibility(event);
Jeff Brown32cbc38552011-12-01 14:01:49 -08006953 QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
Jeff Brown4952dfd2011-11-30 19:23:22 -08006954
Jeff Brown4952dfd2011-11-30 19:23:22 -08006955 // Always enqueue the input event in order, regardless of its time stamp.
6956 // We do this because the application or the IME may inject key events
6957 // in response to touch events and we want to ensure that the injected keys
6958 // are processed in the order they were received and we cannot trust that
6959 // the time stamp of injected events are monotonic.
Michael Wrightc8a7e542013-03-20 17:58:33 -07006960 QueuedInputEvent last = mPendingInputEventTail;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006961 if (last == null) {
Michael Wrightc8a7e542013-03-20 17:58:33 -07006962 mPendingInputEventHead = q;
6963 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006964 } else {
Jeff Brown4952dfd2011-11-30 19:23:22 -08006965 last.mNext = q;
Michael Wrightc8a7e542013-03-20 17:58:33 -07006966 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006967 }
Michael Wright95ae9422013-03-14 10:58:50 -07006968 mPendingInputEventCount += 1;
6969 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
6970 mPendingInputEventCount);
Jeff Brown4952dfd2011-11-30 19:23:22 -08006971
Jeff Brownf9261d22012-02-03 13:49:15 -08006972 if (processImmediately) {
6973 doProcessInputEvents();
6974 } else {
6975 scheduleProcessInputEvents();
6976 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08006977 }
6978
6979 private void scheduleProcessInputEvents() {
Jeff Brown96e942d2011-11-30 19:55:01 -08006980 if (!mProcessInputEventsScheduled) {
6981 mProcessInputEventsScheduled = true;
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006982 Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
6983 msg.setAsynchronous(true);
6984 mHandler.sendMessage(msg);
Jeff Brown4952dfd2011-11-30 19:23:22 -08006985 }
6986 }
6987
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006988 void doProcessInputEvents() {
Jeff Brownf9e989d2013-04-04 23:04:03 -07006989 // Deliver all pending input events in the queue.
Michael Wrightc8a7e542013-03-20 17:58:33 -07006990 while (mPendingInputEventHead != null) {
6991 QueuedInputEvent q = mPendingInputEventHead;
6992 mPendingInputEventHead = q.mNext;
6993 if (mPendingInputEventHead == null) {
6994 mPendingInputEventTail = null;
6995 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08006996 q.mNext = null;
Jeff Brown29c0ed22013-01-14 13:50:37 -08006997
Michael Wright95ae9422013-03-14 10:58:50 -07006998 mPendingInputEventCount -= 1;
6999 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
7000 mPendingInputEventCount);
7001
John Reckba6adf62015-02-19 14:36:50 -08007002 long eventTime = q.mEvent.getEventTimeNano();
7003 long oldestEventTime = eventTime;
7004 if (q.mEvent instanceof MotionEvent) {
7005 MotionEvent me = (MotionEvent)q.mEvent;
7006 if (me.getHistorySize() > 0) {
7007 oldestEventTime = me.getHistoricalEventTimeNano(0);
7008 }
7009 }
7010 mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
7011
Jeff Brownf9e989d2013-04-04 23:04:03 -07007012 deliverInputEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08007013 }
7014
7015 // We are done processing all input events that we can process right now
7016 // so we can clear the pending flag immediately.
Jeff Brown96e942d2011-11-30 19:55:01 -08007017 if (mProcessInputEventsScheduled) {
7018 mProcessInputEventsScheduled = false;
Jeff Browna175a5b2012-02-15 19:18:31 -08007019 mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
Jeff Brown4952dfd2011-11-30 19:23:22 -08007020 }
7021 }
7022
Jeff Brownf9e989d2013-04-04 23:04:03 -07007023 private void deliverInputEvent(QueuedInputEvent q) {
Michael Wrightd2c3adc2014-02-18 22:50:50 -08007024 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
7025 q.mEvent.getSequenceNumber());
7026 if (mInputEventConsistencyVerifier != null) {
7027 mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
7028 }
Michael Wrightc8a7e542013-03-20 17:58:33 -07007029
Michael Wright899d7052014-04-23 17:23:39 -07007030 InputStage stage;
7031 if (q.shouldSendToSynthesizer()) {
7032 stage = mSyntheticInputStage;
7033 } else {
7034 stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
7035 }
7036
Michael Wrightd2c3adc2014-02-18 22:50:50 -08007037 if (stage != null) {
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08007038 handleWindowFocusChanged();
Michael Wrightd2c3adc2014-02-18 22:50:50 -08007039 stage.deliver(q);
7040 } else {
7041 finishInputEvent(q);
Michael Wrightbf020962013-03-28 17:27:50 -07007042 }
Michael Wrightbf020962013-03-28 17:27:50 -07007043 }
7044
Jeff Brownf9e989d2013-04-04 23:04:03 -07007045 private void finishInputEvent(QueuedInputEvent q) {
Michael Wrightd2c3adc2014-02-18 22:50:50 -08007046 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
7047 q.mEvent.getSequenceNumber());
Michael Wright9d744c72014-02-18 21:27:42 -08007048
Jeff Brown32cbc38552011-12-01 14:01:49 -08007049 if (q.mReceiver != null) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07007050 boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
Jeff Brown32cbc38552011-12-01 14:01:49 -08007051 q.mReceiver.finishInputEvent(q.mEvent, handled);
Jeff Brown92cc2d82011-12-02 01:19:47 -08007052 } else {
7053 q.mEvent.recycleIfNeededAfterDispatch();
Jeff Brown4952dfd2011-11-30 19:23:22 -08007054 }
7055
7056 recycleQueuedInputEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08007057 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08007058
Michael Wright5bd69e62015-05-14 14:48:08 +01007059 private void adjustInputEventForCompatibility(InputEvent e) {
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07007060 if (mTargetSdkVersion < Build.VERSION_CODES.M && e instanceof MotionEvent) {
Michael Wright5bd69e62015-05-14 14:48:08 +01007061 MotionEvent motion = (MotionEvent) e;
7062 final int mask =
7063 MotionEvent.BUTTON_STYLUS_PRIMARY | MotionEvent.BUTTON_STYLUS_SECONDARY;
7064 final int buttonState = motion.getButtonState();
7065 final int compatButtonState = (buttonState & mask) >> 4;
7066 if (compatButtonState != 0) {
7067 motion.setButtonState(buttonState | compatButtonState);
7068 }
7069 }
7070 }
7071
Jeff Brownf9e989d2013-04-04 23:04:03 -07007072 static boolean isTerminalInputEvent(InputEvent event) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08007073 if (event instanceof KeyEvent) {
7074 final KeyEvent keyEvent = (KeyEvent)event;
7075 return keyEvent.getAction() == KeyEvent.ACTION_UP;
7076 } else {
7077 final MotionEvent motionEvent = (MotionEvent)event;
7078 final int action = motionEvent.getAction();
7079 return action == MotionEvent.ACTION_UP
7080 || action == MotionEvent.ACTION_CANCEL
7081 || action == MotionEvent.ACTION_HOVER_EXIT;
Jeff Brown4952dfd2011-11-30 19:23:22 -08007082 }
7083 }
7084
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007085 void scheduleConsumeBatchedInput() {
7086 if (!mConsumeBatchedInputScheduled) {
7087 mConsumeBatchedInputScheduled = true;
7088 mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
7089 mConsumedBatchedInputRunnable, null);
Jeff Brown4a06c802012-02-15 15:06:01 -08007090 }
7091 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007092
7093 void unscheduleConsumeBatchedInput() {
7094 if (mConsumeBatchedInputScheduled) {
7095 mConsumeBatchedInputScheduled = false;
7096 mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT,
7097 mConsumedBatchedInputRunnable, null);
7098 }
7099 }
7100
Michael Wright9d744c72014-02-18 21:27:42 -08007101 void scheduleConsumeBatchedInputImmediately() {
7102 if (!mConsumeBatchedInputImmediatelyScheduled) {
7103 unscheduleConsumeBatchedInput();
7104 mConsumeBatchedInputImmediatelyScheduled = true;
7105 mHandler.post(mConsumeBatchedInputImmediatelyRunnable);
7106 }
7107 }
7108
Jeff Brown771526c2012-04-27 15:13:25 -07007109 void doConsumeBatchedInput(long frameTimeNanos) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007110 if (mConsumeBatchedInputScheduled) {
7111 mConsumeBatchedInputScheduled = false;
Jeff Brown330314c2012-04-27 02:20:22 -07007112 if (mInputEventReceiver != null) {
Michael Wright9d744c72014-02-18 21:27:42 -08007113 if (mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos)
7114 && frameTimeNanos != -1) {
Michael Wright62ce65d2013-10-25 14:50:36 -07007115 // If we consumed a batch here, we want to go ahead and schedule the
7116 // consumption of batched input events on the next frame. Otherwise, we would
7117 // wait until we have more input events pending and might get starved by other
Michael Wright9d744c72014-02-18 21:27:42 -08007118 // things occurring in the process. If the frame time is -1, however, then
7119 // we're in a non-batching mode, so there's no need to schedule this.
Michael Wright62ce65d2013-10-25 14:50:36 -07007120 scheduleConsumeBatchedInput();
7121 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007122 }
Jeff Brown330314c2012-04-27 02:20:22 -07007123 doProcessInputEvents();
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007124 }
7125 }
7126
7127 final class TraversalRunnable implements Runnable {
7128 @Override
7129 public void run() {
7130 doTraversal();
7131 }
7132 }
7133 final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
Jeff Brown4a06c802012-02-15 15:06:01 -08007134
Jeff Brown32cbc38552011-12-01 14:01:49 -08007135 final class WindowInputEventReceiver extends InputEventReceiver {
7136 public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
7137 super(inputChannel, looper);
Jeff Brown46b9ac02010-04-22 18:58:52 -07007138 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08007139
7140 @Override
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -07007141 public void onInputEvent(InputEvent event, int displayId) {
Jeff Brownf9261d22012-02-03 13:49:15 -08007142 enqueueInputEvent(event, this, 0, true);
Jeff Brown32cbc38552011-12-01 14:01:49 -08007143 }
Jeff Brown072ec962012-02-07 14:46:57 -08007144
7145 @Override
7146 public void onBatchedInputEventPending() {
Michael Wright9d744c72014-02-18 21:27:42 -08007147 if (mUnbufferedInputDispatch) {
7148 super.onBatchedInputEventPending();
7149 } else {
7150 scheduleConsumeBatchedInput();
7151 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007152 }
7153
7154 @Override
7155 public void dispose() {
7156 unscheduleConsumeBatchedInput();
7157 super.dispose();
Jeff Brown072ec962012-02-07 14:46:57 -08007158 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08007159 }
7160 WindowInputEventReceiver mInputEventReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007161
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007162 final class ConsumeBatchedInputRunnable implements Runnable {
7163 @Override
7164 public void run() {
Jeff Brown771526c2012-04-27 15:13:25 -07007165 doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007166 }
7167 }
7168 final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =
7169 new ConsumeBatchedInputRunnable();
7170 boolean mConsumeBatchedInputScheduled;
7171
Michael Wright9d744c72014-02-18 21:27:42 -08007172 final class ConsumeBatchedInputImmediatelyRunnable implements Runnable {
7173 @Override
7174 public void run() {
7175 doConsumeBatchedInput(-1);
7176 }
7177 }
7178 final ConsumeBatchedInputImmediatelyRunnable mConsumeBatchedInputImmediatelyRunnable =
7179 new ConsumeBatchedInputImmediatelyRunnable();
7180 boolean mConsumeBatchedInputImmediatelyScheduled;
7181
Jeff Brown6cb7b462012-03-05 13:21:17 -08007182 final class InvalidateOnAnimationRunnable implements Runnable {
7183 private boolean mPosted;
Igor Murashkina86ab6402013-08-30 12:58:36 -07007184 private final ArrayList<View> mViews = new ArrayList<View>();
7185 private final ArrayList<AttachInfo.InvalidateInfo> mViewRects =
Jeff Brown6cb7b462012-03-05 13:21:17 -08007186 new ArrayList<AttachInfo.InvalidateInfo>();
7187 private View[] mTempViews;
7188 private AttachInfo.InvalidateInfo[] mTempViewRects;
7189
7190 public void addView(View view) {
7191 synchronized (this) {
7192 mViews.add(view);
7193 postIfNeededLocked();
7194 }
7195 }
7196
7197 public void addViewRect(AttachInfo.InvalidateInfo info) {
7198 synchronized (this) {
7199 mViewRects.add(info);
7200 postIfNeededLocked();
7201 }
7202 }
7203
7204 public void removeView(View view) {
7205 synchronized (this) {
7206 mViews.remove(view);
7207
7208 for (int i = mViewRects.size(); i-- > 0; ) {
7209 AttachInfo.InvalidateInfo info = mViewRects.get(i);
7210 if (info.target == view) {
7211 mViewRects.remove(i);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08007212 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08007213 }
7214 }
7215
7216 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007217 mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08007218 mPosted = false;
7219 }
7220 }
7221 }
7222
7223 @Override
7224 public void run() {
7225 final int viewCount;
7226 final int viewRectCount;
7227 synchronized (this) {
7228 mPosted = false;
7229
7230 viewCount = mViews.size();
7231 if (viewCount != 0) {
7232 mTempViews = mViews.toArray(mTempViews != null
7233 ? mTempViews : new View[viewCount]);
7234 mViews.clear();
7235 }
7236
7237 viewRectCount = mViewRects.size();
7238 if (viewRectCount != 0) {
7239 mTempViewRects = mViewRects.toArray(mTempViewRects != null
7240 ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]);
7241 mViewRects.clear();
7242 }
7243 }
7244
7245 for (int i = 0; i < viewCount; i++) {
7246 mTempViews[i].invalidate();
Adam Powell3e3c4ee2012-05-16 17:34:21 -07007247 mTempViews[i] = null;
Jeff Brown6cb7b462012-03-05 13:21:17 -08007248 }
7249
7250 for (int i = 0; i < viewRectCount; i++) {
7251 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
7252 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08007253 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08007254 }
7255 }
7256
7257 private void postIfNeededLocked() {
7258 if (!mPosted) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007259 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08007260 mPosted = true;
7261 }
7262 }
7263 }
7264 final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
7265 new InvalidateOnAnimationRunnable();
7266
Jeff Browna175a5b2012-02-15 19:18:31 -08007267 public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
7268 Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
7269 mHandler.sendMessageDelayed(msg, delayMilliseconds);
7270 }
7271
Jeff Browna175a5b2012-02-15 19:18:31 -08007272 public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
7273 long delayMilliseconds) {
7274 final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
7275 mHandler.sendMessageDelayed(msg, delayMilliseconds);
7276 }
7277
Jeff Brown6cb7b462012-03-05 13:21:17 -08007278 public void dispatchInvalidateOnAnimation(View view) {
7279 mInvalidateOnAnimationRunnable.addView(view);
7280 }
7281
7282 public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) {
7283 mInvalidateOnAnimationRunnable.addViewRect(info);
7284 }
7285
7286 public void cancelInvalidate(View view) {
7287 mHandler.removeMessages(MSG_INVALIDATE, view);
7288 // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning
7289 // them to the pool
7290 mHandler.removeMessages(MSG_INVALIDATE_RECT, view);
7291 mInvalidateOnAnimationRunnable.removeView(view);
7292 }
7293
keunyoung30f420f2013-08-02 14:23:10 -07007294 public void dispatchInputEvent(InputEvent event) {
Jae Seo6a6059a2014-04-17 21:35:29 -07007295 dispatchInputEvent(event, null);
7296 }
7297
7298 public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
7299 SomeArgs args = SomeArgs.obtain();
7300 args.arg1 = event;
7301 args.arg2 = receiver;
7302 Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
Jeff Browne0dbd002012-02-15 19:34:58 -08007303 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08007304 mHandler.sendMessage(msg);
7305 }
7306
Michael Wright899d7052014-04-23 17:23:39 -07007307 public void synthesizeInputEvent(InputEvent event) {
7308 Message msg = mHandler.obtainMessage(MSG_SYNTHESIZE_INPUT_EVENT, event);
7309 msg.setAsynchronous(true);
7310 mHandler.sendMessage(msg);
7311 }
7312
Jeff Browna175a5b2012-02-15 19:18:31 -08007313 public void dispatchKeyFromIme(KeyEvent event) {
7314 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
Jeff Browne0dbd002012-02-15 19:34:58 -08007315 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08007316 mHandler.sendMessage(msg);
Jeff Browncb1404e2011-01-15 18:14:15 -08007317 }
7318
Dake Gu6a20a192018-02-08 12:09:30 -08007319 public void dispatchKeyFromAutofill(KeyEvent event) {
7320 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_AUTOFILL, event);
7321 msg.setAsynchronous(true);
7322 mHandler.sendMessage(msg);
7323 }
7324
Michael Wright899d7052014-04-23 17:23:39 -07007325 /**
7326 * Reinject unhandled {@link InputEvent}s in order to synthesize fallbacks events.
7327 *
7328 * Note that it is the responsibility of the caller of this API to recycle the InputEvent it
7329 * passes in.
7330 */
Michael Wright3da28342014-04-22 17:00:11 -07007331 public void dispatchUnhandledInputEvent(InputEvent event) {
Michael Wright899d7052014-04-23 17:23:39 -07007332 if (event instanceof MotionEvent) {
7333 event = MotionEvent.obtain((MotionEvent) event);
Michael Wright3da28342014-04-22 17:00:11 -07007334 }
Michael Wright899d7052014-04-23 17:23:39 -07007335 synthesizeInputEvent(event);
Michael Wright3da28342014-04-22 17:00:11 -07007336 }
7337
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007338 public void dispatchAppVisibility(boolean visible) {
Jeff Browna175a5b2012-02-15 19:18:31 -08007339 Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007340 msg.arg1 = visible ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08007341 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007342 }
7343
7344 public void dispatchGetNewSurface() {
Jeff Browna175a5b2012-02-15 19:18:31 -08007345 Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
7346 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007347 }
7348
7349 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08007350 synchronized (this) {
Dianne Hackborn011944c2017-12-15 15:44:55 -08007351 mWindowFocusChanged = true;
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08007352 mUpcomingWindowFocus = hasFocus;
7353 mUpcomingInTouchMode = inTouchMode;
7354 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007355 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08007356 msg.what = MSG_WINDOW_FOCUS_CHANGED;
Jeff Browna175a5b2012-02-15 19:18:31 -08007357 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007358 }
7359
Craig Mautner9c795042014-10-28 19:59:59 -07007360 public void dispatchWindowShown() {
7361 mHandler.sendEmptyMessage(MSG_DISPATCH_WINDOW_SHOWN);
7362 }
7363
Dianne Hackbornffa42482009-09-23 22:20:11 -07007364 public void dispatchCloseSystemDialogs(String reason) {
7365 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08007366 msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
Dianne Hackbornffa42482009-09-23 22:20:11 -07007367 msg.obj = reason;
Jeff Browna175a5b2012-02-15 19:18:31 -08007368 mHandler.sendMessage(msg);
Dianne Hackbornffa42482009-09-23 22:20:11 -07007369 }
Christopher Tatea53146c2010-09-07 11:57:52 -07007370
7371 public void dispatchDragEvent(DragEvent event) {
Chris Tate91e9bb32010-10-12 12:58:43 -07007372 final int what;
7373 if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
Jeff Browna175a5b2012-02-15 19:18:31 -08007374 what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
7375 mHandler.removeMessages(what);
Chris Tate91e9bb32010-10-12 12:58:43 -07007376 } else {
Jeff Browna175a5b2012-02-15 19:18:31 -08007377 what = MSG_DISPATCH_DRAG_EVENT;
Chris Tate91e9bb32010-10-12 12:58:43 -07007378 }
Jeff Browna175a5b2012-02-15 19:18:31 -08007379 Message msg = mHandler.obtainMessage(what, event);
7380 mHandler.sendMessage(msg);
Christopher Tatea53146c2010-09-07 11:57:52 -07007381 }
7382
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08007383 public void updatePointerIcon(float x, float y) {
7384 final int what = MSG_UPDATE_POINTER_ICON;
7385 mHandler.removeMessages(what);
7386 final long now = SystemClock.uptimeMillis();
7387 final MotionEvent event = MotionEvent.obtain(
7388 0, now, MotionEvent.ACTION_HOVER_MOVE, x, y, 0);
7389 Message msg = mHandler.obtainMessage(what, event);
7390 mHandler.sendMessage(msg);
7391 }
7392
Dianne Hackborn9a230e02011-10-06 11:51:27 -07007393 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
7394 int localValue, int localChanges) {
7395 SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
7396 args.seq = seq;
7397 args.globalVisibility = globalVisibility;
7398 args.localValue = localValue;
7399 args.localChanges = localChanges;
Jeff Browna175a5b2012-02-15 19:18:31 -08007400 mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
7401 }
7402
7403 public void dispatchCheckFocus() {
7404 if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
7405 // This will result in a call to checkFocus() below.
7406 mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
7407 }
Joe Onorato664644d2011-01-23 17:53:23 -08007408 }
7409
Clara Bayarrifcd7e802016-03-10 12:58:18 +00007410 public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
7411 mHandler.obtainMessage(
7412 MSG_REQUEST_KEYBOARD_SHORTCUTS, deviceId, 0, receiver).sendToTarget();
Clara Bayarri75e09792015-07-29 16:20:40 +01007413 }
7414
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08007415 public void dispatchPointerCaptureChanged(boolean on) {
7416 final int what = MSG_POINTER_CAPTURE_CHANGED;
7417 mHandler.removeMessages(what);
7418 Message msg = mHandler.obtainMessage(what);
7419 msg.arg1 = on ? 1 : 0;
7420 mHandler.sendMessage(msg);
7421 }
7422
svetoslavganov75986cf2009-05-14 22:28:01 -07007423 /**
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07007424 * Post a callback to send a
7425 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
Svetoslav Ganova0156172011-06-26 17:55:44 -07007426 * This event is send at most once every
7427 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07007428 */
Alan Viverette77e9a282013-09-12 17:16:09 -07007429 private void postSendWindowContentChangedCallback(View source, int changeType) {
Eugene Susla72c510f2018-01-23 21:12:11 +00007430 if (mSendWindowContentChangedAccessibilityEvent == null) {
7431 mSendWindowContentChangedAccessibilityEvent =
7432 new SendWindowContentChangedAccessibilityEvent();
7433 }
7434 mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07007435 }
7436
7437 /**
7438 * Remove a posted callback to send a
7439 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
7440 */
7441 private void removeSendWindowContentChangedCallback() {
Eugene Susla72c510f2018-01-23 21:12:11 +00007442 if (mSendWindowContentChangedAccessibilityEvent != null) {
7443 mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07007444 }
7445 }
7446
Igor Murashkina86ab6402013-08-30 12:58:36 -07007447 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007448 public boolean showContextMenuForChild(View originalView) {
7449 return false;
7450 }
7451
Igor Murashkina86ab6402013-08-30 12:58:36 -07007452 @Override
Oren Blasberged391262015-09-01 12:12:51 -07007453 public boolean showContextMenuForChild(View originalView, float x, float y) {
7454 return false;
7455 }
7456
7457 @Override
Adam Powell6e346362010-07-23 10:18:23 -07007458 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
7459 return null;
7460 }
7461
Igor Murashkina86ab6402013-08-30 12:58:36 -07007462 @Override
Clara Bayarri4423d912015-03-02 19:42:48 +00007463 public ActionMode startActionModeForChild(
7464 View originalView, ActionMode.Callback callback, int type) {
7465 return null;
7466 }
7467
7468 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007469 public void createContextMenu(ContextMenu menu) {
7470 }
7471
Igor Murashkina86ab6402013-08-30 12:58:36 -07007472 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007473 public void childDrawableStateChanged(View child) {
7474 }
7475
Igor Murashkina86ab6402013-08-30 12:58:36 -07007476 @Override
Svetoslav Ganov736c2752011-04-22 18:30:36 -07007477 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
George Mount41725de2015-04-09 08:23:05 -07007478 if (mView == null || mStopped || mPausedForTransition) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -07007479 return false;
7480 }
Eugene Suslaccce5c92017-05-22 13:14:57 -07007481
Eugene Susla72c510f2018-01-23 21:12:11 +00007482 // Immediately flush pending content changed event (if any) to preserve event order
7483 if (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
7484 && mSendWindowContentChangedAccessibilityEvent != null
7485 && mSendWindowContentChangedAccessibilityEvent.mSource != null) {
7486 mSendWindowContentChangedAccessibilityEvent.removeCallbacksAndRun();
7487 }
Eugene Suslaccce5c92017-05-22 13:14:57 -07007488
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07007489 // Intercept accessibility focus events fired by virtual nodes to keep
7490 // track of accessibility focus position in such nodes.
Svetoslav Ganov791fd312012-05-14 15:12:30 -07007491 final int eventType = event.getEventType();
7492 switch (eventType) {
7493 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07007494 final long sourceNodeId = event.getSourceNodeId();
7495 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
7496 sourceNodeId);
7497 View source = mView.findViewByAccessibilityId(accessibilityViewId);
7498 if (source != null) {
7499 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
7500 if (provider != null) {
Svetoslavb3ba1d42014-09-26 15:20:40 -07007501 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
7502 sourceNodeId);
7503 final AccessibilityNodeInfo node;
Phil Weaverf00cd142017-03-03 13:44:00 -08007504 node = provider.createAccessibilityNodeInfo(virtualNodeId);
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07007505 setAccessibilityFocus(source, node);
7506 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07007507 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07007508 } break;
7509 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07007510 final long sourceNodeId = event.getSourceNodeId();
7511 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
7512 sourceNodeId);
7513 View source = mView.findViewByAccessibilityId(accessibilityViewId);
7514 if (source != null) {
7515 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
7516 if (provider != null) {
7517 setAccessibilityFocus(null, null);
7518 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07007519 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07007520 } break;
Svetoslavf0c758b2014-09-03 17:47:37 -07007521
7522
7523 case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: {
Alan Viverette34457f52015-03-25 13:09:20 -07007524 handleWindowContentChangedEvent(event);
Svetoslavf0c758b2014-09-03 17:47:37 -07007525 } break;
Svetoslav Ganov791fd312012-05-14 15:12:30 -07007526 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007527 mAccessibilityManager.sendAccessibilityEvent(event);
Svetoslav Ganov736c2752011-04-22 18:30:36 -07007528 return true;
7529 }
7530
Alan Viverette34457f52015-03-25 13:09:20 -07007531 /**
7532 * Updates the focused virtual view, when necessary, in response to a
7533 * content changed event.
7534 * <p>
7535 * This is necessary to get updated bounds after a position change.
7536 *
7537 * @param event an accessibility event of type
7538 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}
7539 */
7540 private void handleWindowContentChangedEvent(AccessibilityEvent event) {
Alan Viverette25acc7e2015-05-19 11:32:08 -07007541 final View focusedHost = mAccessibilityFocusedHost;
7542 if (focusedHost == null || mAccessibilityFocusedVirtualView == null) {
7543 // No virtual view focused, nothing to do here.
Alan Viverette34457f52015-03-25 13:09:20 -07007544 return;
7545 }
7546
Alan Viverette25acc7e2015-05-19 11:32:08 -07007547 final AccessibilityNodeProvider provider = focusedHost.getAccessibilityNodeProvider();
Alan Viverette34457f52015-03-25 13:09:20 -07007548 if (provider == null) {
Alan Viverette25acc7e2015-05-19 11:32:08 -07007549 // Error state: virtual view with no provider. Clear focus.
7550 mAccessibilityFocusedHost = null;
7551 mAccessibilityFocusedVirtualView = null;
Phil Weavere37cfab2016-04-07 21:01:57 -07007552 focusedHost.clearAccessibilityFocusNoCallbacks(0);
Alan Viverette34457f52015-03-25 13:09:20 -07007553 return;
7554 }
7555
7556 // We only care about change types that may affect the bounds of the
7557 // focused virtual view.
7558 final int changes = event.getContentChangeTypes();
7559 if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) == 0
7560 && changes != AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) {
7561 return;
7562 }
7563
7564 final long eventSourceNodeId = event.getSourceNodeId();
7565 final int changedViewId = AccessibilityNodeInfo.getAccessibilityViewId(eventSourceNodeId);
7566
7567 // Search up the tree for subtree containment.
7568 boolean hostInSubtree = false;
7569 View root = mAccessibilityFocusedHost;
7570 while (root != null && !hostInSubtree) {
7571 if (changedViewId == root.getAccessibilityViewId()) {
7572 hostInSubtree = true;
7573 } else {
7574 final ViewParent parent = root.getParent();
7575 if (parent instanceof View) {
7576 root = (View) parent;
7577 } else {
7578 root = null;
7579 }
7580 }
7581 }
7582
7583 // We care only about changes in subtrees containing the host view.
7584 if (!hostInSubtree) {
7585 return;
7586 }
7587
7588 final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId();
7589 int focusedChildId = AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId);
Alan Viverette34457f52015-03-25 13:09:20 -07007590
7591 // Refresh the node for the focused virtual view.
Alan Viverettea7ea65e2015-05-15 11:30:21 -07007592 final Rect oldBounds = mTempRect;
7593 mAccessibilityFocusedVirtualView.getBoundsInScreen(oldBounds);
Alan Viverette34457f52015-03-25 13:09:20 -07007594 mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo(focusedChildId);
Alan Viverette25acc7e2015-05-19 11:32:08 -07007595 if (mAccessibilityFocusedVirtualView == null) {
7596 // Error state: The node no longer exists. Clear focus.
7597 mAccessibilityFocusedHost = null;
Phil Weavere37cfab2016-04-07 21:01:57 -07007598 focusedHost.clearAccessibilityFocusNoCallbacks(0);
Alan Viverette25acc7e2015-05-19 11:32:08 -07007599
7600 // This will probably fail, but try to keep the provider's internal
7601 // state consistent by clearing focus.
7602 provider.performAction(focusedChildId,
7603 AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(), null);
Alan Viverettea7ea65e2015-05-15 11:30:21 -07007604 invalidateRectOnScreen(oldBounds);
Alan Viverette25acc7e2015-05-19 11:32:08 -07007605 } else {
7606 // The node was refreshed, invalidate bounds if necessary.
7607 final Rect newBounds = mAccessibilityFocusedVirtualView.getBoundsInScreen();
7608 if (!oldBounds.equals(newBounds)) {
7609 oldBounds.union(newBounds);
7610 invalidateRectOnScreen(oldBounds);
7611 }
Alan Viverettea7ea65e2015-05-15 11:30:21 -07007612 }
Alan Viverette34457f52015-03-25 13:09:20 -07007613 }
7614
Svetoslav Ganov42138042012-03-20 11:51:39 -07007615 @Override
Alan Viverette77e9a282013-09-12 17:16:09 -07007616 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
Phil Weaver63e45032017-05-11 10:54:37 -07007617 postSendWindowContentChangedCallback(Preconditions.checkNotNull(source), changeType);
Svetoslav Ganov42138042012-03-20 11:51:39 -07007618 }
7619
Fabrice Di Meglio9dd4c5c2013-02-08 18:15:07 -08007620 @Override
7621 public boolean canResolveLayoutDirection() {
7622 return true;
7623 }
7624
7625 @Override
7626 public boolean isLayoutDirectionResolved() {
7627 return true;
7628 }
7629
7630 @Override
7631 public int getLayoutDirection() {
7632 return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT;
7633 }
7634
7635 @Override
7636 public boolean canResolveTextDirection() {
7637 return true;
7638 }
7639
7640 @Override
7641 public boolean isTextDirectionResolved() {
7642 return true;
7643 }
7644
7645 @Override
7646 public int getTextDirection() {
7647 return View.TEXT_DIRECTION_RESOLVED_DEFAULT;
7648 }
7649
7650 @Override
7651 public boolean canResolveTextAlignment() {
7652 return true;
7653 }
7654
7655 @Override
7656 public boolean isTextAlignmentResolved() {
7657 return true;
7658 }
7659
7660 @Override
7661 public int getTextAlignment() {
7662 return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT;
7663 }
7664
Eugene Susla72c510f2018-01-23 21:12:11 +00007665 private View getCommonPredecessor(View first, View second) {
7666 if (mTempHashSet == null) {
7667 mTempHashSet = new HashSet<View>();
7668 }
7669 HashSet<View> seen = mTempHashSet;
7670 seen.clear();
7671 View firstCurrent = first;
7672 while (firstCurrent != null) {
7673 seen.add(firstCurrent);
7674 ViewParent firstCurrentParent = firstCurrent.mParent;
7675 if (firstCurrentParent instanceof View) {
7676 firstCurrent = (View) firstCurrentParent;
7677 } else {
7678 firstCurrent = null;
7679 }
7680 }
7681 View secondCurrent = second;
7682 while (secondCurrent != null) {
7683 if (seen.contains(secondCurrent)) {
7684 seen.clear();
7685 return secondCurrent;
7686 }
7687 ViewParent secondCurrentParent = secondCurrent.mParent;
7688 if (secondCurrentParent instanceof View) {
7689 secondCurrent = (View) secondCurrentParent;
7690 } else {
7691 secondCurrent = null;
7692 }
7693 }
7694 seen.clear();
7695 return null;
7696 }
7697
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007698 void checkThread() {
7699 if (mThread != Thread.currentThread()) {
7700 throw new CalledFromWrongThreadException(
7701 "Only the original thread that created a view hierarchy can touch its views.");
7702 }
7703 }
7704
Igor Murashkina86ab6402013-08-30 12:58:36 -07007705 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007706 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Joe Onoratoc6cc0f82011-04-12 11:53:13 -07007707 // ViewAncestor never intercepts touch event, so this can be a no-op
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007708 }
7709
Igor Murashkina86ab6402013-08-30 12:58:36 -07007710 @Override
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07007711 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
Yigit Boyard62d5e92016-01-19 18:56:20 -08007712 if (rectangle == null) {
7713 return scrollToRectOrFocus(null, immediate);
7714 }
7715 rectangle.offset(child.getLeft() - child.getScrollX(),
7716 child.getTop() - child.getScrollY());
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07007717 final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
Yigit Boyard62d5e92016-01-19 18:56:20 -08007718 mTempRect.set(rectangle);
7719 mTempRect.offset(0, -mCurScrollY);
7720 mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
7721 try {
7722 mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect);
7723 } catch (RemoteException re) {
7724 /* ignore */
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07007725 }
7726 return scrolled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007727 }
Romain Guy8506ab42009-06-11 17:35:47 -07007728
Igor Murashkina86ab6402013-08-30 12:58:36 -07007729 @Override
Adam Powell539ee872012-02-03 19:00:49 -08007730 public void childHasTransientStateChanged(View child, boolean hasTransientState) {
7731 // Do nothing.
7732 }
7733
Adam Powell10ba2772014-04-15 09:46:51 -07007734 @Override
7735 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
7736 return false;
7737 }
7738
7739 @Override
7740 public void onStopNestedScroll(View target) {
7741 }
7742
7743 @Override
7744 public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
7745 }
7746
7747 @Override
7748 public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
7749 int dxUnconsumed, int dyUnconsumed) {
7750 }
7751
7752 @Override
7753 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
7754 }
7755
7756 @Override
Adam Powellb36e4f92014-05-01 10:23:33 -07007757 public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
Adam Powell10ba2772014-04-15 09:46:51 -07007758 return false;
7759 }
7760
Adam Powellb72be592014-07-16 21:41:31 -07007761 @Override
7762 public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
7763 return false;
7764 }
7765
Adam Powellb6ab0982015-01-07 17:00:12 -08007766 @Override
7767 public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
7768 return false;
7769 }
7770
Robert Carr49cd9f82017-05-25 18:24:42 -07007771
7772 private void reportNextDraw() {
7773 if (mReportNextDraw == false) {
7774 drawPending();
7775 }
7776 mReportNextDraw = true;
7777 }
7778
Jorim Jaggib774e552015-08-24 14:52:45 -07007779 /**
7780 * Force the window to report its next draw.
7781 * <p>
7782 * This method is only supposed to be used to speed up the interaction from SystemUI and window
7783 * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE
7784 * unless you fully understand this interaction.
7785 * @hide
7786 */
7787 public void setReportNextDraw() {
Robert Carr49cd9f82017-05-25 18:24:42 -07007788 reportNextDraw();
Jorim Jaggib774e552015-08-24 14:52:45 -07007789 invalidate();
7790 }
7791
Craig Mautnerbc57cd12013-08-19 15:47:42 -07007792 void changeCanvasOpacity(boolean opaque) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08007793 Log.d(mTag, "changeCanvasOpacity: opaque=" + opaque);
Stan Iliev45faba52016-06-28 13:33:15 -04007794 if (mAttachInfo.mThreadedRenderer != null) {
7795 mAttachInfo.mThreadedRenderer.setOpaque(opaque);
John Reck63a06672014-05-07 13:45:54 -07007796 }
Craig Mautnerbc57cd12013-08-19 15:47:42 -07007797 }
7798
Evan Rosky5e29c072017-06-02 17:31:22 -07007799 /**
7800 * Dispatches a KeyEvent to all registered key fallback handlers.
7801 *
7802 * @param event
7803 * @return {@code true} if the event was handled, {@code false} otherwise.
7804 */
7805 public boolean dispatchKeyFallbackEvent(KeyEvent event) {
Evan Rosky4807ae22018-03-22 16:04:15 -07007806 return mUnhandledKeyManager.dispatch(mView, event);
Evan Rosky5e29c072017-06-02 17:31:22 -07007807 }
7808
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07007809 class TakenSurfaceHolder extends BaseSurfaceHolder {
7810 @Override
7811 public boolean onAllowLockCanvas() {
7812 return mDrawingAllowed;
7813 }
7814
7815 @Override
7816 public void onRelayoutContainer() {
7817 // Not currently interesting -- from changing between fixed and layout size.
7818 }
7819
Igor Murashkina86ab6402013-08-30 12:58:36 -07007820 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07007821 public void setFormat(int format) {
7822 ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
7823 }
7824
Igor Murashkina86ab6402013-08-30 12:58:36 -07007825 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07007826 public void setType(int type) {
7827 ((RootViewSurfaceTaker)mView).setSurfaceType(type);
7828 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07007829
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07007830 @Override
7831 public void onUpdateSurface() {
7832 // We take care of format and type changes on our own.
7833 throw new IllegalStateException("Shouldn't be here");
7834 }
7835
Igor Murashkina86ab6402013-08-30 12:58:36 -07007836 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07007837 public boolean isCreating() {
7838 return mIsCreating;
7839 }
7840
7841 @Override
7842 public void setFixedSize(int width, int height) {
7843 throw new UnsupportedOperationException(
7844 "Currently only support sizing from layout");
7845 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07007846
7847 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07007848 public void setKeepScreenOn(boolean screenOn) {
7849 ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
7850 }
7851 }
Romain Guy8506ab42009-06-11 17:35:47 -07007852
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007853 static class W extends IWindow.Stub {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007854 private final WeakReference<ViewRootImpl> mViewAncestor;
Jeff Brown98365d72012-08-19 20:30:52 -07007855 private final IWindowSession mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007856
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007857 W(ViewRootImpl viewAncestor) {
7858 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
Jeff Brown98365d72012-08-19 20:30:52 -07007859 mWindowSession = viewAncestor.mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007860 }
7861
Igor Murashkina86ab6402013-08-30 12:58:36 -07007862 @Override
Dianne Hackbornc4aad012013-02-22 15:05:25 -08007863 public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Filip Gruszczynski2217f612015-05-26 11:32:08 -07007864 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
Andrii Kulian44607962017-03-16 11:06:24 -07007865 MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
Adrian Roos5c6b6222017-11-07 17:36:10 +01007866 boolean alwaysConsumeNavBar, int displayId,
7867 DisplayCutout.ParcelableWrapper displayCutout) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007868 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007869 if (viewAncestor != null) {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08007870 viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
Andrii Kulian44607962017-03-16 11:06:24 -07007871 visibleInsets, stableInsets, outsets, reportDraw, mergedConfiguration,
Adrian Roos5c6b6222017-11-07 17:36:10 +01007872 backDropFrame, forceLayout, alwaysConsumeNavBar, displayId, displayCutout);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007873 }
7874 }
7875
Craig Mautner5702d4d2012-06-30 14:10:16 -07007876 @Override
7877 public void moved(int newX, int newY) {
7878 final ViewRootImpl viewAncestor = mViewAncestor.get();
7879 if (viewAncestor != null) {
7880 viewAncestor.dispatchMoved(newX, newY);
7881 }
7882 }
7883
Igor Murashkina86ab6402013-08-30 12:58:36 -07007884 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007885 public void dispatchAppVisibility(boolean visible) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007886 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007887 if (viewAncestor != null) {
7888 viewAncestor.dispatchAppVisibility(visible);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007889 }
7890 }
7891
Igor Murashkina86ab6402013-08-30 12:58:36 -07007892 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007893 public void dispatchGetNewSurface() {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007894 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007895 if (viewAncestor != null) {
7896 viewAncestor.dispatchGetNewSurface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007897 }
7898 }
7899
Igor Murashkina86ab6402013-08-30 12:58:36 -07007900 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007901 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007902 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007903 if (viewAncestor != null) {
7904 viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007905 }
7906 }
7907
7908 private static int checkCallingPermission(String permission) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007909 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08007910 return ActivityManager.getService().checkPermission(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007911 permission, Binder.getCallingPid(), Binder.getCallingUid());
7912 } catch (RemoteException e) {
7913 return PackageManager.PERMISSION_DENIED;
7914 }
7915 }
7916
Igor Murashkina86ab6402013-08-30 12:58:36 -07007917 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007918 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007919 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007920 if (viewAncestor != null) {
7921 final View view = viewAncestor.mView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007922 if (view != null) {
7923 if (checkCallingPermission(Manifest.permission.DUMP) !=
7924 PackageManager.PERMISSION_GRANTED) {
7925 throw new SecurityException("Insufficient permissions to invoke"
7926 + " executeCommand() from pid=" + Binder.getCallingPid()
7927 + ", uid=" + Binder.getCallingUid());
7928 }
7929
7930 OutputStream clientStream = null;
7931 try {
7932 clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
7933 ViewDebug.dispatchCommand(view, command, parameters, clientStream);
7934 } catch (IOException e) {
7935 e.printStackTrace();
7936 } finally {
7937 if (clientStream != null) {
7938 try {
7939 clientStream.close();
7940 } catch (IOException e) {
7941 e.printStackTrace();
7942 }
7943 }
7944 }
7945 }
7946 }
7947 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07007948
7949 @Override
Dianne Hackbornffa42482009-09-23 22:20:11 -07007950 public void closeSystemDialogs(String reason) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007951 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007952 if (viewAncestor != null) {
7953 viewAncestor.dispatchCloseSystemDialogs(reason);
Dianne Hackbornffa42482009-09-23 22:20:11 -07007954 }
7955 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07007956
7957 @Override
Marco Nelissenbf6956b2009-11-09 15:21:13 -08007958 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
7959 boolean sync) {
Dianne Hackborn19382ac2009-09-11 21:13:37 -07007960 if (sync) {
7961 try {
Jeff Brown98365d72012-08-19 20:30:52 -07007962 mWindowSession.wallpaperOffsetsComplete(asBinder());
Dianne Hackborn19382ac2009-09-11 21:13:37 -07007963 } catch (RemoteException e) {
7964 }
7965 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07007966 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007967
Igor Murashkina86ab6402013-08-30 12:58:36 -07007968 @Override
Dianne Hackborn75804932009-10-20 20:15:20 -07007969 public void dispatchWallpaperCommand(String action, int x, int y,
7970 int z, Bundle extras, boolean sync) {
7971 if (sync) {
7972 try {
Jeff Brown98365d72012-08-19 20:30:52 -07007973 mWindowSession.wallpaperCommandComplete(asBinder(), null);
Dianne Hackborn75804932009-10-20 20:15:20 -07007974 } catch (RemoteException e) {
7975 }
7976 }
7977 }
Christopher Tatea53146c2010-09-07 11:57:52 -07007978
7979 /* Drag/drop */
Igor Murashkina86ab6402013-08-30 12:58:36 -07007980 @Override
Christopher Tatea53146c2010-09-07 11:57:52 -07007981 public void dispatchDragEvent(DragEvent event) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007982 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007983 if (viewAncestor != null) {
7984 viewAncestor.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07007985 }
7986 }
Joe Onorato664644d2011-01-23 17:53:23 -08007987
Igor Murashkina86ab6402013-08-30 12:58:36 -07007988 @Override
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08007989 public void updatePointerIcon(float x, float y) {
7990 final ViewRootImpl viewAncestor = mViewAncestor.get();
7991 if (viewAncestor != null) {
7992 viewAncestor.updatePointerIcon(x, y);
7993 }
7994 }
7995
7996 @Override
Dianne Hackborn9a230e02011-10-06 11:51:27 -07007997 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
7998 int localValue, int localChanges) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007999 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008000 if (viewAncestor != null) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07008001 viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility,
8002 localValue, localChanges);
Joe Onorato664644d2011-01-23 17:53:23 -08008003 }
8004 }
Dianne Hackborn12d3a942012-04-27 14:16:30 -07008005
Igor Murashkina86ab6402013-08-30 12:58:36 -07008006 @Override
Craig Mautner9c795042014-10-28 19:59:59 -07008007 public void dispatchWindowShown() {
8008 final ViewRootImpl viewAncestor = mViewAncestor.get();
8009 if (viewAncestor != null) {
8010 viewAncestor.dispatchWindowShown();
8011 }
8012 }
Clara Bayarri75e09792015-07-29 16:20:40 +01008013
8014 @Override
Clara Bayarrifcd7e802016-03-10 12:58:18 +00008015 public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
8016 ViewRootImpl viewAncestor = mViewAncestor.get();
8017 if (viewAncestor != null) {
8018 viewAncestor.dispatchRequestKeyboardShortcuts(receiver, deviceId);
8019 }
Clara Bayarri75e09792015-07-29 16:20:40 +01008020 }
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08008021
8022 @Override
8023 public void dispatchPointerCaptureChanged(boolean hasCapture) {
8024 final ViewRootImpl viewAncestor = mViewAncestor.get();
8025 if (viewAncestor != null) {
8026 viewAncestor.dispatchPointerCaptureChanged(hasCapture);
8027 }
8028 }
8029
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008030 }
8031
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008032 public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
8033 public CalledFromWrongThreadException(String msg) {
8034 super(msg);
8035 }
8036 }
8037
Alan Viverettebea0c7da2015-09-01 16:00:20 -04008038 static HandlerActionQueue getRunQueue() {
8039 HandlerActionQueue rq = sRunQueues.get();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008040 if (rq != null) {
8041 return rq;
8042 }
Alan Viverettebea0c7da2015-09-01 16:00:20 -04008043 rq = new HandlerActionQueue();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008044 sRunQueues.set(rq);
8045 return rq;
8046 }
Romain Guy8506ab42009-06-11 17:35:47 -07008047
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008048 /**
Skuhneb8160872015-09-22 09:51:39 -07008049 * Start a drag resizing which will inform all listeners that a window resize is taking place.
8050 */
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08008051 private void startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets,
Jorim Jaggic39c7b02016-03-24 10:47:07 -07008052 Rect stableInsets, int resizeMode) {
Skuhneb8160872015-09-22 09:51:39 -07008053 if (!mDragResizing) {
8054 mDragResizing = true;
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09008055 if (mUseMTRenderer) {
8056 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
8057 mWindowCallbacks.get(i).onWindowDragResizeStart(
8058 initialBounds, fullscreen, systemInsets, stableInsets, resizeMode);
8059 }
Skuhneb8160872015-09-22 09:51:39 -07008060 }
8061 mFullRedrawNeeded = true;
8062 }
8063 }
8064
8065 /**
8066 * End a drag resize which will inform all listeners that a window resize has ended.
8067 */
8068 private void endDragResizing() {
8069 if (mDragResizing) {
8070 mDragResizing = false;
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09008071 if (mUseMTRenderer) {
8072 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
8073 mWindowCallbacks.get(i).onWindowDragResizeEnd();
8074 }
Skuhneb8160872015-09-22 09:51:39 -07008075 }
8076 mFullRedrawNeeded = true;
8077 }
8078 }
8079
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07008080 private boolean updateContentDrawBounds() {
8081 boolean updated = false;
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09008082 if (mUseMTRenderer) {
8083 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
8084 updated |=
8085 mWindowCallbacks.get(i).onContentDrawn(mWindowAttributes.surfaceInsets.left,
8086 mWindowAttributes.surfaceInsets.top, mWidth, mHeight);
8087 }
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07008088 }
8089 return updated | (mDragResizing && mReportNextDraw);
8090 }
8091
8092 private void requestDrawWindow() {
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09008093 if (!mUseMTRenderer) {
8094 return;
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07008095 }
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09008096 mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size());
Jorim Jaggi16b63192016-03-25 18:32:19 -07008097 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
8098 mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw);
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07008099 }
8100 }
8101
Skuhneb8160872015-09-22 09:51:39 -07008102 /**
Jorim Jaggi4846ee32016-01-07 17:39:12 +01008103 * Tells this instance that its corresponding activity has just relaunched. In this case, we
8104 * need to force a relayout of the window to make sure we get the correct bounds from window
8105 * manager.
8106 */
8107 public void reportActivityRelaunched() {
8108 mActivityRelaunched = true;
8109 }
8110
8111 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008112 * Class for managing the accessibility interaction connection
8113 * based on the global accessibility state.
8114 */
8115 final class AccessibilityInteractionConnectionManager
8116 implements AccessibilityStateChangeListener {
Igor Murashkina86ab6402013-08-30 12:58:36 -07008117 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008118 public void onAccessibilityStateChanged(boolean enabled) {
8119 if (enabled) {
8120 ensureConnection();
Phil Weaver05a29822017-09-22 11:03:06 -07008121 if (mAttachInfo.mHasWindowFocus && (mView != null)) {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08008122 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
8123 View focusedView = mView.findFocus();
8124 if (focusedView != null && focusedView != mView) {
8125 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
8126 }
8127 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008128 } else {
8129 ensureNoConnection();
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07008130 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008131 }
8132 }
8133
8134 public void ensureConnection() {
Phil Weaverf00cd142017-03-03 13:44:00 -08008135 final boolean registered = mAttachInfo.mAccessibilityWindowId
8136 != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
Chris Craikcce47eb2014-07-16 15:12:15 -07008137 if (!registered) {
8138 mAttachInfo.mAccessibilityWindowId =
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08008139 mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
Svet Ganov240aed92017-12-02 12:32:23 -08008140 mContext.getPackageName(),
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08008141 new AccessibilityInteractionConnection(ViewRootImpl.this));
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008142 }
8143 }
8144
8145 public void ensureNoConnection() {
Phil Weaverf00cd142017-03-03 13:44:00 -08008146 final boolean registered = mAttachInfo.mAccessibilityWindowId
8147 != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008148 if (registered) {
Phil Weaverf00cd142017-03-03 13:44:00 -08008149 mAttachInfo.mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008150 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
8151 }
8152 }
8153 }
8154
Chris Craikcce47eb2014-07-16 15:12:15 -07008155 final class HighContrastTextManager implements HighTextContrastChangeListener {
8156 HighContrastTextManager() {
John Reck938e8842017-08-24 13:41:59 -07008157 ThreadedRenderer.setHighContrastText(mAccessibilityManager.isHighTextContrastEnabled());
Chris Craikcce47eb2014-07-16 15:12:15 -07008158 }
8159 @Override
8160 public void onHighTextContrastStateChanged(boolean enabled) {
John Reck938e8842017-08-24 13:41:59 -07008161 ThreadedRenderer.setHighContrastText(enabled);
Chris Craikcce47eb2014-07-16 15:12:15 -07008162
8163 // Destroy Displaylists so they can be recreated with high contrast recordings
8164 destroyHardwareResources();
Chris Craikd36a81f2014-07-17 10:16:51 -07008165
8166 // Schedule redraw, which will rerecord + redraw all text
8167 invalidate();
Chris Craikcce47eb2014-07-16 15:12:15 -07008168 }
8169 }
8170
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008171 /**
8172 * This class is an interface this ViewAncestor provides to the
8173 * AccessibilityManagerService to the latter can interact with
8174 * the view hierarchy in this ViewAncestor.
8175 */
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07008176 static final class AccessibilityInteractionConnection
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008177 extends IAccessibilityInteractionConnection.Stub {
Svetoslav Ganov02107852011-10-03 17:06:56 -07008178 private final WeakReference<ViewRootImpl> mViewRootImpl;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008179
Svetoslav Ganovf79f4762011-10-28 15:40:32 -07008180 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) {
8181 mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008182 }
8183
Svetoslav Ganov42138042012-03-20 11:51:39 -07008184 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07008185 public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07008186 Region interactiveRegion, int interactionId,
8187 IAccessibilityInteractionConnectionCallback callback, int flags,
Phil Weaverc2e28932016-12-08 12:29:25 -08008188 int interrogatingPid, long interrogatingTid, MagnificationSpec spec, Bundle args) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07008189 ViewRootImpl viewRootImpl = mViewRootImpl.get();
8190 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07008191 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov02107852011-10-03 17:06:56 -07008192 .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07008193 interactiveRegion, interactionId, callback, flags, interrogatingPid,
Phil Weaverc2e28932016-12-08 12:29:25 -08008194 interrogatingTid, spec, args);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008195 } else {
8196 // We cannot make the call and notify the caller so it does not wait.
8197 try {
8198 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
8199 } catch (RemoteException re) {
8200 /* best effort - ignore */
8201 }
Svetoslav Ganov601ad802011-06-09 14:47:38 -07008202 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008203 }
8204
Svetoslav Ganov42138042012-03-20 11:51:39 -07008205 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07008206 public void performAccessibilityAction(long accessibilityNodeId, int action,
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07008207 Bundle arguments, int interactionId,
8208 IAccessibilityInteractionConnectionCallback callback, int flags,
Svet Ganov7498efd2014-09-03 21:33:00 -07008209 int interrogatingPid, long interrogatingTid) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07008210 ViewRootImpl viewRootImpl = mViewRootImpl.get();
8211 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07008212 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07008213 .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
Svet Ganov7498efd2014-09-03 21:33:00 -07008214 interactionId, callback, flags, interrogatingPid, interrogatingTid);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008215 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008216 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008217 try {
8218 callback.setPerformAccessibilityActionResult(false, interactionId);
8219 } catch (RemoteException re) {
8220 /* best effort - ignore */
8221 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008222 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008223 }
8224
Svetoslav Ganov42138042012-03-20 11:51:39 -07008225 @Override
Svetoslav Ganov80943d82013-01-02 10:25:37 -08008226 public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07008227 String viewId, Region interactiveRegion, int interactionId,
Svetoslav Ganov80943d82013-01-02 10:25:37 -08008228 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07008229 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07008230 ViewRootImpl viewRootImpl = mViewRootImpl.get();
8231 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07008232 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov80943d82013-01-02 10:25:37 -08008233 .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07008234 viewId, interactiveRegion, interactionId, callback, flags,
8235 interrogatingPid, interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008236 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008237 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008238 try {
8239 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
8240 } catch (RemoteException re) {
8241 /* best effort - ignore */
8242 }
8243 }
8244 }
8245
Svetoslav Ganov42138042012-03-20 11:51:39 -07008246 @Override
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008247 public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
Svetoslav9ae9ed22014-09-02 16:36:35 -07008248 Region interactiveRegion, int interactionId,
8249 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07008250 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008251 ViewRootImpl viewRootImpl = mViewRootImpl.get();
8252 if (viewRootImpl != null && viewRootImpl.mView != null) {
8253 viewRootImpl.getAccessibilityInteractionController()
8254 .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
Svetoslav9ae9ed22014-09-02 16:36:35 -07008255 interactiveRegion, interactionId, callback, flags, interrogatingPid,
8256 interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008257 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008258 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008259 try {
8260 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
8261 } catch (RemoteException re) {
8262 /* best effort - ignore */
8263 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008264 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008265 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008266
Svetoslav Ganov42138042012-03-20 11:51:39 -07008267 @Override
Svetoslav9ae9ed22014-09-02 16:36:35 -07008268 public void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion,
8269 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07008270 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008271 ViewRootImpl viewRootImpl = mViewRootImpl.get();
8272 if (viewRootImpl != null && viewRootImpl.mView != null) {
8273 viewRootImpl.getAccessibilityInteractionController()
Svetoslav9ae9ed22014-09-02 16:36:35 -07008274 .findFocusClientThread(accessibilityNodeId, focusType, interactiveRegion,
8275 interactionId, callback, flags, interrogatingPid, interrogatingTid,
8276 spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07008277 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008278 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008279 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008280 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008281 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008282 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008283 }
8284 }
8285 }
8286
Svetoslav Ganov42138042012-03-20 11:51:39 -07008287 @Override
Svetoslav9ae9ed22014-09-02 16:36:35 -07008288 public void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion,
8289 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07008290 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008291 ViewRootImpl viewRootImpl = mViewRootImpl.get();
8292 if (viewRootImpl != null && viewRootImpl.mView != null) {
8293 viewRootImpl.getAccessibilityInteractionController()
Svetoslav9ae9ed22014-09-02 16:36:35 -07008294 .focusSearchClientThread(accessibilityNodeId, direction, interactiveRegion,
8295 interactionId, callback, flags, interrogatingPid, interrogatingTid,
8296 spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07008297 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008298 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008299 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008300 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008301 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008302 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008303 }
8304 }
8305 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008306 }
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07008307
Eugene Susla72c510f2018-01-23 21:12:11 +00008308 private class SendWindowContentChangedAccessibilityEvent implements Runnable {
8309 private int mChangeTypes = 0;
8310
8311 public View mSource;
8312 public long mLastEventTimeMillis;
Eugene Susla9af1378c2018-03-22 16:29:10 -07008313 /**
8314 * Override for {@link AccessibilityEvent#originStackTrace} to provide the stack trace
8315 * of the original {@link #runOrPost} call instead of one for sending the delayed event
8316 * from a looper.
8317 */
8318 public StackTraceElement[] mOrigin;
Eugene Susla72c510f2018-01-23 21:12:11 +00008319
8320 @Override
8321 public void run() {
8322 // Protect against re-entrant code and attempt to do the right thing in the case that
8323 // we're multithreaded.
8324 View source = mSource;
8325 mSource = null;
8326 if (source == null) {
8327 Log.e(TAG, "Accessibility content change has no source");
8328 return;
8329 }
8330 // The accessibility may be turned off while we were waiting so check again.
8331 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
8332 mLastEventTimeMillis = SystemClock.uptimeMillis();
8333 AccessibilityEvent event = AccessibilityEvent.obtain();
8334 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
8335 event.setContentChangeTypes(mChangeTypes);
Eugene Susla9af1378c2018-03-22 16:29:10 -07008336 if (AccessibilityEvent.DEBUG_ORIGIN) event.originStackTrace = mOrigin;
Eugene Susla72c510f2018-01-23 21:12:11 +00008337 source.sendAccessibilityEventUnchecked(event);
8338 } else {
8339 mLastEventTimeMillis = 0;
8340 }
8341 // In any case reset to initial state.
8342 source.resetSubtreeAccessibilityStateChanged();
8343 mChangeTypes = 0;
Eugene Susla9af1378c2018-03-22 16:29:10 -07008344 if (AccessibilityEvent.DEBUG_ORIGIN) mOrigin = null;
Eugene Susla72c510f2018-01-23 21:12:11 +00008345 }
8346
8347 public void runOrPost(View source, int changeType) {
8348 if (mHandler.getLooper() != Looper.myLooper()) {
8349 CalledFromWrongThreadException e = new CalledFromWrongThreadException("Only the "
8350 + "original thread that created a view hierarchy can touch its views.");
8351 // TODO: Throw the exception
8352 Log.e(TAG, "Accessibility content change on non-UI thread. Future Android "
8353 + "versions will throw an exception.", e);
8354 // Attempt to recover. This code does not eliminate the thread safety issue, but
8355 // it should force any issues to happen near the above log.
8356 mHandler.removeCallbacks(this);
8357 if (mSource != null) {
8358 // Dispatch whatever was pending. It's still possible that the runnable started
8359 // just before we removed the callbacks, and bad things will happen, but at
8360 // least they should happen very close to the logged error.
8361 run();
8362 }
8363 }
8364 if (mSource != null) {
8365 // If there is no common predecessor, then mSource points to
8366 // a removed view, hence in this case always prefer the source.
8367 View predecessor = getCommonPredecessor(mSource, source);
Eugene Susla9af1378c2018-03-22 16:29:10 -07008368 if (predecessor != null) {
8369 predecessor = predecessor.getSelfOrParentImportantForA11y();
8370 }
Eugene Susla72c510f2018-01-23 21:12:11 +00008371 mSource = (predecessor != null) ? predecessor : source;
8372 mChangeTypes |= changeType;
8373 return;
8374 }
8375 mSource = source;
8376 mChangeTypes = changeType;
Eugene Susla9af1378c2018-03-22 16:29:10 -07008377 if (AccessibilityEvent.DEBUG_ORIGIN) {
8378 mOrigin = Thread.currentThread().getStackTrace();
8379 }
Eugene Susla72c510f2018-01-23 21:12:11 +00008380 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
8381 final long minEventIntevalMillis =
8382 ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
8383 if (timeSinceLastMillis >= minEventIntevalMillis) {
8384 removeCallbacksAndRun();
8385 } else {
8386 mHandler.postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
8387 }
8388 }
8389
8390 public void removeCallbacksAndRun() {
8391 mHandler.removeCallbacks(this);
8392 run();
8393 }
8394 }
8395
Evan Rosky4807ae22018-03-22 16:04:15 -07008396 private static class UnhandledKeyManager {
Evan Rosky5e29c072017-06-02 17:31:22 -07008397
Evan Rosky4807ae22018-03-22 16:04:15 -07008398 // This is used to ensure that unhandled events are only dispatched once. We attempt
Evan Rosky5e29c072017-06-02 17:31:22 -07008399 // to dispatch more than once in order to achieve a certain order. Specifically, if we
Evan Rosky4807ae22018-03-22 16:04:15 -07008400 // are in an Activity or Dialog (and have a Window.Callback), the unhandled events should
Evan Rosky5e29c072017-06-02 17:31:22 -07008401 // be dispatched after the view hierarchy, but before the Activity. However, if we aren't
Evan Rosky4807ae22018-03-22 16:04:15 -07008402 // in an activity, we still want unhandled keys to be dispatched.
Evan Rosky5e29c072017-06-02 17:31:22 -07008403 boolean mDispatched = false;
8404
8405 SparseBooleanArray mCapturedKeys = new SparseBooleanArray();
Evan Rosky4807ae22018-03-22 16:04:15 -07008406 WeakReference<View> mCurrentReceiver = null;
Evan Rosky5e29c072017-06-02 17:31:22 -07008407
8408 private void updateCaptureState(KeyEvent event) {
8409 if (event.getAction() == KeyEvent.ACTION_DOWN) {
8410 mCapturedKeys.append(event.getKeyCode(), true);
8411 }
8412 if (event.getAction() == KeyEvent.ACTION_UP) {
8413 mCapturedKeys.delete(event.getKeyCode());
8414 }
8415 }
8416
8417 boolean dispatch(View root, KeyEvent event) {
8418 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "KeyFallback dispatch");
8419 mDispatched = true;
8420
8421 updateCaptureState(event);
8422
Evan Rosky4807ae22018-03-22 16:04:15 -07008423 if (mCurrentReceiver != null) {
8424 View target = mCurrentReceiver.get();
Evan Rosky5e29c072017-06-02 17:31:22 -07008425 if (mCapturedKeys.size() == 0) {
Evan Rosky4807ae22018-03-22 16:04:15 -07008426 mCurrentReceiver = null;
Evan Rosky5e29c072017-06-02 17:31:22 -07008427 }
8428 if (target != null && target.isAttachedToWindow()) {
Evan Rosky4807ae22018-03-22 16:04:15 -07008429 target.onUnhandledKeyEvent(event);
Evan Rosky5e29c072017-06-02 17:31:22 -07008430 }
8431 // consume anyways so that we don't feed uncaptured key events to other views
8432 return true;
8433 }
8434
Evan Rosky4807ae22018-03-22 16:04:15 -07008435 View consumer = root.dispatchUnhandledKeyEvent(event);
8436 if (consumer != null) {
8437 mCurrentReceiver = new WeakReference<>(consumer);
8438 }
Evan Rosky5e29c072017-06-02 17:31:22 -07008439 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
Evan Rosky4807ae22018-03-22 16:04:15 -07008440 return consumer != null;
Evan Rosky5e29c072017-06-02 17:31:22 -07008441 }
8442
8443 boolean hasFocus() {
Evan Rosky4807ae22018-03-22 16:04:15 -07008444 return mCurrentReceiver != null;
Evan Rosky5e29c072017-06-02 17:31:22 -07008445 }
8446
8447 boolean dispatchUnique(View root, KeyEvent event) {
8448 if (mDispatched) {
8449 return false;
8450 }
8451 return dispatch(root, event);
8452 }
8453 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008454}