blob: 2355c87b66e3dc2f5b9ce54aa6f7d5978dc74729 [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;
Mathew Inwoode5ad5982018-08-17 15:07:52 +010033import android.annotation.UnsupportedAppUsage;
Sudheer Shankadc589ac2016-11-10 15:30:17 -080034import android.app.ActivityManager;
Andrii Kulian44607962017-03-16 11:06:24 -070035import android.app.ActivityThread;
Adam Lesinski4ece3d62016-06-16 18:05:41 -070036import android.app.ResourcesManager;
Vadim Trysheva61efa42016-09-28 15:15:52 -070037import android.content.ClipData;
Romain Guy6b7bd242010-10-06 19:49:23 -070038import android.content.ClipDescription;
Romain Guy6b7bd242010-10-06 19:49:23 -070039import android.content.Context;
Romain Guy26a2b972017-04-17 09:39:51 -070040import android.content.pm.ActivityInfo;
Romain Guy6b7bd242010-10-06 19:49:23 -070041import android.content.pm.PackageManager;
42import android.content.res.CompatibilityInfo;
43import android.content.res.Configuration;
44import android.content.res.Resources;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.graphics.Canvas;
John Reck3e04f092017-06-02 15:50:09 -070046import android.graphics.Color;
Alan Viverettefed3f722013-11-14 14:48:20 -080047import android.graphics.Matrix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.graphics.PixelFormat;
Christopher Tate2c095f32010-10-04 14:13:40 -070049import android.graphics.Point;
Christopher Tatea53146c2010-09-07 11:57:52 -070050import android.graphics.PointF;
Romain Guy6b7bd242010-10-06 19:49:23 -070051import android.graphics.PorterDuff;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.graphics.Rect;
53import android.graphics.Region;
Doris Liu718cd3e2016-05-17 16:50:31 -070054import android.graphics.drawable.AnimatedVectorDrawable;
Svetoslav Ganov42138042012-03-20 11:51:39 -070055import android.graphics.drawable.Drawable;
Jeff Brownd912e1f2014-04-11 18:46:22 -070056import android.hardware.display.DisplayManager;
57import android.hardware.display.DisplayManager.DisplayListener;
Jun Mukai347e5d42015-12-03 01:13:31 -080058import android.hardware.input.InputManager;
Romain Guy6b7bd242010-10-06 19:49:23 -070059import android.media.AudioManager;
60import android.os.Binder;
Michael Wright5bd69e62015-05-14 14:48:08 +010061import android.os.Build;
Romain Guy6b7bd242010-10-06 19:49:23 -070062import android.os.Bundle;
63import android.os.Debug;
64import android.os.Handler;
Romain Guy6b7bd242010-10-06 19:49:23 -070065import android.os.Looper;
66import android.os.Message;
67import android.os.ParcelFileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068import android.os.Process;
Romain Guy6b7bd242010-10-06 19:49:23 -070069import android.os.RemoteException;
Romain Guy6b7bd242010-10-06 19:49:23 -070070import android.os.SystemClock;
Romain Guy59a12ca2011-06-09 17:48:21 -070071import android.os.SystemProperties;
Jeff Brown481c1572012-03-09 14:41:15 -080072import android.os.Trace;
Kiyoung Kim89052d92018-12-20 18:26:10 +090073import android.sysprop.DisplayProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074import android.util.AndroidRuntimeException;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070075import android.util.DisplayMetrics;
Romain Guy6b7bd242010-10-06 19:49:23 -070076import android.util.Log;
Svetoslav Ganov24c90452017-12-27 15:17:14 -080077import android.util.LongArray;
Andrii Kulian44607962017-03-16 11:06:24 -070078import android.util.MergedConfiguration;
Chet Haase949dbf72010-08-11 18:41:06 -070079import android.util.Slog;
Siarhei Vishniakou461faf92017-06-26 11:24:25 -070080import android.util.SparseArray;
John Reckba6adf62015-02-19 14:36:50 -080081import android.util.TimeUtils;
Dianne Hackborn711e62a2010-11-29 16:38:22 -080082import android.util.TypedValue;
John Reck44fd8d22014-02-26 11:00:11 -080083import android.view.Surface.OutOfResourcesException;
Jorim Jaggi64be98d2018-04-26 23:23:29 +020084import android.view.ThreadedRenderer.FrameDrawingCallback;
Jeff Browna175a5b2012-02-15 19:18:31 -080085import android.view.View.AttachInfo;
Evan Rosky57223312017-02-08 14:42:45 -080086import android.view.View.FocusDirection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087import android.view.View.MeasureSpec;
Yohei Yukawa22dac1c2017-02-12 16:54:16 -080088import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
svetoslavganov75986cf2009-05-14 22:28:01 -070089import android.view.accessibility.AccessibilityEvent;
90import android.view.accessibility.AccessibilityManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070091import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
Chris Craikcce47eb2014-07-16 15:12:15 -070092import android.view.accessibility.AccessibilityManager.HighTextContrastChangeListener;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070093import android.view.accessibility.AccessibilityNodeInfo;
Alan Viverette25acc7e2015-05-19 11:32:08 -070094import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
Svetoslav Ganov02107852011-10-03 17:06:56 -070095import android.view.accessibility.AccessibilityNodeProvider;
Phil Weaverf00cd142017-03-03 13:44:00 -080096import android.view.accessibility.AccessibilityWindowInfo;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070097import android.view.accessibility.IAccessibilityInteractionConnection;
98import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
Dianne Hackborn0f761d62010-11-30 22:06:10 -080099import android.view.animation.AccelerateDecelerateInterpolator;
100import android.view.animation.Interpolator;
Dake Gub0fa3782018-02-26 12:25:14 -0800101import android.view.autofill.AutofillManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102import android.view.inputmethod.InputMethodManager;
103import android.widget.Scroller;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700104
Svetoslav Ganov42138042012-03-20 11:51:39 -0700105import com.android.internal.R;
Jorim Jaggi16b63192016-03-25 18:32:19 -0700106import com.android.internal.annotations.GuardedBy;
Clara Bayarri75e09792015-07-29 16:20:40 +0100107import com.android.internal.os.IResultReceiver;
Svetoslav Ganov758143e2012-08-06 16:40:27 -0700108import com.android.internal.os.SomeArgs;
Adam Powell6711f3b2015-05-06 15:57:09 -0700109import com.android.internal.policy.PhoneFallbackEventHandler;
Phil Weaver63e45032017-05-11 10:54:37 -0700110import com.android.internal.util.Preconditions;
Romain Guy6b7bd242010-10-06 19:49:23 -0700111import com.android.internal.view.BaseSurfaceHolder;
Romain Guy6b7bd242010-10-06 19:49:23 -0700112import com.android.internal.view.RootViewSurfaceTaker;
Robert Carr25cfa132016-11-16 13:24:09 -0800113import com.android.internal.view.SurfaceCallbackHelper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114
Jeff Brown5182c782013-10-15 20:31:52 -0700115import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116import java.io.IOException;
117import java.io.OutputStream;
Jeff Brown5182c782013-10-15 20:31:52 -0700118import java.io.PrintWriter;
Romain Guy6b7bd242010-10-06 19:49:23 -0700119import java.lang.ref.WeakReference;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120import java.util.ArrayList;
Eugene Susla72c510f2018-01-23 21:12:11 +0000121import java.util.HashSet;
Svetoslav Ganov24c90452017-12-27 15:17:14 -0800122import java.util.LinkedList;
123import java.util.Queue;
Jorim Jaggic39c7b02016-03-24 10:47:07 -0700124import java.util.concurrent.CountDownLatch;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126/**
127 * The top of a view hierarchy, implementing the needed protocol between View
128 * and the WindowManager. This is for the most part an internal implementation
Jeff Brown98365d72012-08-19 20:30:52 -0700129 * detail of {@link WindowManagerGlobal}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 *
131 * {@hide}
132 */
Romain Guy812ccbe2010-06-01 14:07:24 -0700133@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
Jeff Browna175a5b2012-02-15 19:18:31 -0800134public final class ViewRootImpl implements ViewParent,
Stan Iliev45faba52016-06-28 13:33:15 -0400135 View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
Dianne Hackborn70a3f672011-08-08 14:32:41 -0700136 private static final String TAG = "ViewRootImpl";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 private static final boolean DBG = false;
Romain Guy812ccbe2010-06-01 14:07:24 -0700138 private static final boolean LOCAL_LOGV = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 /** @noinspection PointlessBooleanExpression*/
140 private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
141 private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800142 private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
144 private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
145 private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
146 private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700147 private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
Chet Haase2f2022a2011-10-11 06:41:59 -0700148 private static final boolean DEBUG_FPS = false;
Michael Wright06a79252014-05-05 17:45:29 -0700149 private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV;
Chong Zhang44aabe42016-05-10 11:20:14 -0700150 private static final boolean DEBUG_KEEP_SCREEN_ON = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151
Romain Guy59a12ca2011-06-09 17:48:21 -0700152 /**
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +0900153 * Set to false if we do not want to use the multi threaded renderer even though
154 * threaded renderer (aka hardware renderering) is used. Note that by disabling
Skuhneb8160872015-09-22 09:51:39 -0700155 * this, WindowCallbacks will not fire.
156 */
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +0900157 private static final boolean MT_RENDERER_AVAILABLE = true;
Skuhneb8160872015-09-22 09:51:39 -0700158
159 /**
Romain Guy59a12ca2011-06-09 17:48:21 -0700160 * Set this system property to true to force the view hierarchy to render
161 * at 60 Hz. This can be used to measure the potential framerate.
162 */
Romain Guye9bc11f2013-05-23 12:47:26 -0700163 private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering";
Michael Chan53071d62009-05-13 17:29:48 -0700164
Griff Hazena0938022015-03-13 10:01:41 -0700165 // properties used by emulator to determine display shape
Griff Hazena0938022015-03-13 10:01:41 -0700166 public static final String PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX =
167 "ro.emu.win_outset_bottom_px";
Michael Kolb437d3132014-06-20 13:28:44 -0700168
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 /**
170 * Maximum time we allow the user to roll the trackball enough to generate
171 * a key event, before resetting the counters.
172 */
173 static final int MAX_TRACKBALL_DELAY = 250;
174
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100175 @UnsupportedAppUsage
Alan Viverettebea0c7da2015-09-01 16:00:20 -0400176 static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177
Skuhneb8160872015-09-22 09:51:39 -0700178 static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList();
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800179 static boolean sFirstDrawComplete = false;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700180
Jorim Jaggi64be98d2018-04-26 23:23:29 +0200181 private FrameDrawingCallback mNextRtFrameCallback;
182
Andrii Kulian44607962017-03-16 11:06:24 -0700183 /**
184 * Callback for notifying about global configuration changes.
185 */
186 public interface ConfigChangedCallback {
187
188 /** Notifies about global config change. */
189 void onConfigurationChanged(Configuration globalConfig);
190 }
191
192 private static final ArrayList<ConfigChangedCallback> sConfigCallbacks = new ArrayList<>();
193
194 /**
195 * Callback for notifying activities about override configuration changes.
196 */
197 public interface ActivityConfigCallback {
198
199 /**
200 * Notifies about override config change and/or move to different display.
201 * @param overrideConfig New override config to apply to activity.
202 * @param newDisplayId New display id, {@link Display#INVALID_DISPLAY} if not changed.
203 */
204 void onConfigurationChanged(Configuration overrideConfig, int newDisplayId);
205 }
206
207 /**
208 * Callback used to notify corresponding activity about override configuration change and make
209 * sure that all resources are set correctly before updating the ViewRootImpl's internal state.
210 */
211 private ActivityConfigCallback mActivityConfigCallback;
212
213 /**
214 * Used when configuration change first updates the config of corresponding activity.
215 * In that case we receive a call back from {@link ActivityThread} and this flag is used to
216 * preserve the initial value.
217 *
218 * @see #performConfigurationChange(Configuration, Configuration, boolean, int)
219 */
220 private boolean mForceNextConfigUpdate;
Romain Guy59a12ca2011-06-09 17:48:21 -0700221
Jorim Jaggi16b63192016-03-25 18:32:19 -0700222 /**
Evan Rosky37df2db2017-01-24 16:35:52 -0800223 * Signals that compatibility booleans have been initialized according to
224 * target SDK versions.
225 */
226 private static boolean sCompatibilityDone = false;
227
228 /**
229 * Always assign focus if a focusable View is available.
230 */
Evan Roskyc5420ea2017-07-13 15:24:16 -0700231 private static boolean sAlwaysAssignFocus;
Evan Rosky37df2db2017-01-24 16:35:52 -0800232
233 /**
Jorim Jaggi16b63192016-03-25 18:32:19 -0700234 * This list must only be modified by the main thread, so a lock is only needed when changing
235 * the list or when accessing the list from a non-main thread.
236 */
237 @GuardedBy("mWindowCallbacks")
238 final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList<>();
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100239 @UnsupportedAppUsage
Jeff Brownf9e989d2013-04-04 23:04:03 -0700240 final Context mContext;
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100241 @UnsupportedAppUsage
Jeff Brown98365d72012-08-19 20:30:52 -0700242 final IWindowSession mWindowSession;
Adam Lesinski4ece3d62016-06-16 18:05:41 -0700243 @NonNull Display mDisplay;
Jeff Brownd912e1f2014-04-11 18:46:22 -0700244 final DisplayManager mDisplayManager;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800245 final String mBasePackageName;
Jeff Brown98365d72012-08-19 20:30:52 -0700246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 final int[] mTmpLocation = new int[2];
Romain Guy8506ab42009-06-11 17:35:47 -0700248
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800249 final TypedValue mTmpValue = new TypedValue();
Jeff Brownf9e989d2013-04-04 23:04:03 -0700250
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 final Thread mThread;
252
253 final WindowLeaked mLocation;
254
Mihai Popa0450a162018-04-27 13:09:12 +0100255 public final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256
257 final W mWindow;
258
Dianne Hackborn180c4842011-09-13 12:39:25 -0700259 final int mTargetSdkVersion;
260
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700261 int mSeq;
262
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100263 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 View mView;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700265
266 View mAccessibilityFocusedHost;
267 AccessibilityNodeInfo mAccessibilityFocusedVirtualView;
268
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -0800269 // True if the window currently has pointer capture enabled.
270 boolean mPointerCapture;
Jun Mukai347e5d42015-12-03 01:13:31 -0800271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 int mViewVisibility;
273 boolean mAppVisible = true;
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800274 // For recents to freeform transition we need to keep drawing after the app receives information
275 // that it became invisible. This will ignore that information and depend on the decor view
276 // visibility to control drawing. The decor view visibility will get adjusted when the app get
277 // stopped and that's when the app will stop drawing further frames.
278 private boolean mForceDecorViewVisibility = false;
Andrii Kulian74b561a2017-08-11 09:06:46 -0700279 // Used for tracking app visibility updates separately in case we get double change. This will
280 // make sure that we always call relayout for the corresponding window.
281 private boolean mAppVisibilityChanged;
Dianne Hackborn180c4842011-09-13 12:39:25 -0700282 int mOrigWindowType = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283
Alan Viverette64bf97a2015-09-18 16:42:00 -0400284 /** Whether the window had focus during the most recent traversal. */
285 boolean mHadWindowFocus;
286
287 /**
288 * Whether the window lost focus during a previous traversal and has not
289 * yet gained it back. Used to determine whether a WINDOW_STATE_CHANGE
290 * accessibility events should be sent during traversal.
291 */
292 boolean mLostWindowFocus;
293
Dianne Hackbornce418e62011-03-01 14:31:38 -0800294 // Set to true if the owner of this window is in the stopped state,
295 // so the window should no longer be active.
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100296 @UnsupportedAppUsage
Dianne Hackbornce418e62011-03-01 14:31:38 -0800297 boolean mStopped = false;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700298
Daniel Koulomzin087ae472015-12-16 17:52:25 -0500299 // Set to true if the owner of this window is in ambient mode,
300 // which means it won't receive input events.
301 boolean mIsAmbientMode = false;
302
George Mount41725de2015-04-09 08:23:05 -0700303 // Set to true to stop input during an Activity Transition.
304 boolean mPausedForTransition = false;
305
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700306 boolean mLastInCompatMode = false;
307
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700308 SurfaceHolder.Callback2 mSurfaceHolderCallback;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700309 BaseSurfaceHolder mSurfaceHolder;
310 boolean mIsCreating;
311 boolean mDrawingAllowed;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313 final Region mTransparentRegion;
314 final Region mPreviousTransparentRegion;
315
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100316 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317 int mWidth;
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100318 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 int mHeight;
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100320 @UnsupportedAppUsage
Romain Guy7d7b5492011-01-24 16:33:45 -0800321 Rect mDirty;
Chris Craik3f06c6d2017-01-09 18:19:48 +0000322 public boolean mIsAnimating;
Romain Guy8506ab42009-06-11 17:35:47 -0700323
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +0900324 private boolean mUseMTRenderer;
Chong Zhang0275e392015-09-17 10:41:44 -0700325 private boolean mDragResizing;
Jorim Jaggic39c7b02016-03-24 10:47:07 -0700326 private boolean mInvalidateRootRequested;
Jorim Jaggi4846ee32016-01-07 17:39:12 +0100327 private int mResizeMode;
Chong Zhang0275e392015-09-17 10:41:44 -0700328 private int mCanvasOffsetX;
329 private int mCanvasOffsetY;
Jorim Jaggi4846ee32016-01-07 17:39:12 +0100330 private boolean mActivityRelaunched;
Chong Zhang0275e392015-09-17 10:41:44 -0700331
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700332 CompatibilityInfo.Translator mTranslator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800333
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100334 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335 final View.AttachInfo mAttachInfo;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700336 InputChannel mInputChannel;
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -0700337 InputQueue.Callback mInputQueueCallback;
338 InputQueue mInputQueue;
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100339 @UnsupportedAppUsage
Joe Onorato86f67862010-11-05 18:57:34 -0700340 FallbackEventHandler mFallbackEventHandler;
Jeff Brown96e942d2011-11-30 19:55:01 -0800341 Choreographer mChoreographer;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700342
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343 final Rect mTempRect; // used in the transaction to not thrash the heap.
344 final Rect mVisRect; // used to retrieve visible rect of focused view.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800346 // This is used to reduce the race between window focus changes being dispatched from
347 // the window manager and input events coming through the input system.
348 @GuardedBy("this")
Dianne Hackborn011944c2017-12-15 15:44:55 -0800349 boolean mWindowFocusChanged;
350 @GuardedBy("this")
Dianne Hackborn5c3296a2017-12-13 17:52:26 -0800351 boolean mUpcomingWindowFocus;
352 @GuardedBy("this")
353 boolean mUpcomingInTouchMode;
354
Chris Craik3f06c6d2017-01-09 18:19:48 +0000355 public boolean mTraversalScheduled;
Jeff Browne0dbd002012-02-15 19:34:58 -0800356 int mTraversalBarrier;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 boolean mWillDrawSoon;
Craig Mautnerdf2390a2012-08-29 20:59:22 -0700358 /** Set to true while in performTraversals for detecting when die(true) is called from internal
359 * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */
360 boolean mIsInTraversal;
Adrian Roosfa104232014-06-20 16:10:14 -0700361 boolean mApplyInsetsRequested;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 boolean mLayoutRequested;
363 boolean mFirst;
364 boolean mReportNextDraw;
365 boolean mFullRedrawNeeded;
366 boolean mNewSurfaceNeeded;
367 boolean mHasHadWindowFocus;
368 boolean mLastWasImTarget;
Jorim Jaggia4a58ef2016-01-27 02:10:08 -0800369 boolean mForceNextWindowRelayout;
Chong Zhang8dbd9ad2015-10-09 10:06:11 -0700370 CountDownLatch mWindowDrawCountDown;
Jorim Jaggi827e0fa2015-05-07 11:41:41 -0700371
Romain Guy1f59e5c2012-05-06 14:11:16 -0700372 boolean mIsDrawing;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700373 int mLastSystemUiVisibility;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700374 int mClientWindowLayoutFlags;
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800375 boolean mLastOverscanRequested;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800376
377 // Pool of queued input events.
378 private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
379 private QueuedInputEvent mQueuedInputEventPool;
380 private int mQueuedInputEventPoolSize;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800381
Michael Wrightc8a7e542013-03-20 17:58:33 -0700382 /* Input event queue.
Jeff Brownf9e989d2013-04-04 23:04:03 -0700383 * Pending input events are input events waiting to be delivered to the input stages
384 * and handled by the application.
Michael Wrightc8a7e542013-03-20 17:58:33 -0700385 */
386 QueuedInputEvent mPendingInputEventHead;
387 QueuedInputEvent mPendingInputEventTail;
Michael Wright95ae9422013-03-14 10:58:50 -0700388 int mPendingInputEventCount;
Jeff Brown96e942d2011-11-30 19:55:01 -0800389 boolean mProcessInputEventsScheduled;
Michael Wright9d744c72014-02-18 21:27:42 -0800390 boolean mUnbufferedInputDispatch;
Michael Wright95ae9422013-03-14 10:58:50 -0700391 String mPendingInputEventQueueLengthCounterName = "pq";
Jeff Brownf9e989d2013-04-04 23:04:03 -0700392
393 InputStage mFirstInputStage;
394 InputStage mFirstPostImeInputStage;
Michael Wright899d7052014-04-23 17:23:39 -0700395 InputStage mSyntheticInputStage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396
Evan Rosky4807ae22018-03-22 16:04:15 -0700397 private final UnhandledKeyManager mUnhandledKeyManager = new UnhandledKeyManager();
Evan Rosky5e29c072017-06-02 17:31:22 -0700398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 boolean mWindowAttributesChanged = false;
Romain Guyf21c9b02011-09-06 16:56:54 -0700400 int mWindowAttributesChangesFlag = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401
402 // These can be accessed by any thread, must be protected with a lock.
Mathias Agopian5583dc62009-07-09 16:28:11 -0700403 // Surface can never be reassigned or cleared (use Surface.clear()).
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100404 @UnsupportedAppUsage
Andrei Stingaceanud2eadfa2017-09-22 15:32:13 +0100405 public final Surface mSurface = new Surface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100407 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408 boolean mAdded;
409 boolean mAddedTouchMode;
410
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 // These are accessed by multiple threads.
412 final Rect mWinFrame; // frame given by window manager.
413
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800414 final Rect mPendingOverscanInsets = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 final Rect mPendingVisibleInsets = new Rect();
Adrian Roosfa104232014-06-20 16:10:14 -0700416 final Rect mPendingStableInsets = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 final Rect mPendingContentInsets = new Rect();
Filip Gruszczynski2217f612015-05-26 11:32:08 -0700418 final Rect mPendingOutsets = new Rect();
Jorim Jaggia7262a82015-11-03 15:15:40 +0100419 final Rect mPendingBackDropFrame = new Rect();
Adrian Roos5c6b6222017-11-07 17:36:10 +0100420 final DisplayCutout.ParcelableWrapper mPendingDisplayCutout =
421 new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT);
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -0800422 boolean mPendingAlwaysConsumeNavBar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
424 = new ViewTreeObserver.InternalInsetsInfo();
425
Adrian Roosfa104232014-06-20 16:10:14 -0700426 final Rect mDispatchContentInsets = new Rect();
427 final Rect mDispatchStableInsets = new Rect();
Adrian Roos5c6b6222017-11-07 17:36:10 +0100428 DisplayCutout mDispatchDisplayCutout = DisplayCutout.NO_CUTOUT;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700429
Filip Gruszczynski954289d2015-02-26 15:46:47 -0800430 private WindowInsets mLastWindowInsets;
431
Andrii Kulian44607962017-03-16 11:06:24 -0700432 /** Last applied configuration obtained from resources. */
433 private final Configuration mLastConfigurationFromResources = new Configuration();
434 /** Last configuration reported from WM or via {@link #MSG_UPDATE_CONFIGURATION}. */
435 private final MergedConfiguration mLastReportedMergedConfiguration = new MergedConfiguration();
436 /** Configurations waiting to be applied. */
437 private final MergedConfiguration mPendingMergedConfiguration = new MergedConfiguration();
Romain Guy59a12ca2011-06-09 17:48:21 -0700438
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 boolean mScrollMayChange;
Yohei Yukawa22dac1c2017-02-12 16:54:16 -0800440 @SoftInputModeFlags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441 int mSoftInputMode;
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100442 @UnsupportedAppUsage
Svetoslav Ganov149567f2013-01-08 15:23:34 -0800443 WeakReference<View> mLastScrolledFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 int mScrollY;
445 int mCurScrollY;
446 Scroller mScroller;
John Recke56e9df2014-02-21 15:45:10 -0800447 static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
Chet Haasecca2c982011-05-20 14:34:18 -0700448 private ArrayList<LayoutTransition> mPendingTransitions;
Romain Guy8506ab42009-06-11 17:35:47 -0700449
Romain Guy8506ab42009-06-11 17:35:47 -0700450 final ViewConfiguration mViewConfiguration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451
Christopher Tatea53146c2010-09-07 11:57:52 -0700452 /* Drag/drop */
453 ClipDescription mDragDescription;
454 View mCurrentDragView;
Christopher Tate7fb8b562011-01-20 13:46:41 -0800455 volatile Object mLocalDragState;
Christopher Tatea53146c2010-09-07 11:57:52 -0700456 final PointF mDragPoint = new PointF();
Christopher Tate2c095f32010-10-04 14:13:40 -0700457 final PointF mLastTouchPoint = new PointF();
Vladislav Kaznacheevba761122016-01-22 12:09:45 -0800458 int mLastTouchSource;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700459
460 private boolean mProfileRendering;
Romain Guyd0750312012-11-29 11:34:43 -0800461 private Choreographer.FrameCallback mRenderProfiler;
462 private boolean mRenderProfilingEnabled;
Christopher Tatea53146c2010-09-07 11:57:52 -0700463
Chet Haase2f2022a2011-10-11 06:41:59 -0700464 // Variables to track frames per second, enabled via DEBUG_FPS flag
465 private long mFpsStartTime = -1;
466 private long mFpsPrevTime = -1;
467 private int mFpsNumFrames;
468
Michael Wrightf9d9ce772016-05-13 17:44:16 +0100469 private int mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
Jun Mukaid4eaef72015-10-30 15:54:33 -0700470 private PointerIcon mCustomPointerIcon = null;
Jun Mukai1db53972015-09-11 18:08:31 -0700471
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 /**
473 * see {@link #playSoundEffect(int)}
474 */
475 AudioManager mAudioManager;
476
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700477 final AccessibilityManager mAccessibilityManager;
478
Gilles Debunne5ac84422011-10-19 09:35:58 -0700479 AccessibilityInteractionController mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700480
Phil Weaver26d709f2017-04-20 17:19:14 -0700481 final AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager =
482 new AccessibilityInteractionConnectionManager();
483 final HighContrastTextManager mHighContrastTextManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700484
Eugene Susla72c510f2018-01-23 21:12:11 +0000485 SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
486
487 HashSet<View> mTempHashSet;
488
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700489 private final int mDensity;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700490 private final int mNoncompatDensity;
Adam Powellb08013c2010-09-16 16:28:11 -0700491
Chet Haase97140572012-09-13 14:56:47 -0700492 private boolean mInLayout = false;
493 ArrayList<View> mLayoutRequesters = new ArrayList<View>();
494 boolean mHandlingLayoutInLayoutRequest = false;
495
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700496 private int mViewLayoutDirectionInitial;
Chet Haase97140572012-09-13 14:56:47 -0700497
Craig Mautner8f303ad2013-06-14 11:32:22 -0700498 /** Set to true once doDie() has been called. */
499 private boolean mRemoved;
500
Stan Iliev45faba52016-06-28 13:33:15 -0400501 private boolean mNeedsRendererSetup;
Robert Carr1bccabf2016-04-28 13:27:08 -0700502
Jeff Brown21bc5c92011-02-28 18:27:14 -0800503 /**
504 * Consistency verifier for debugging purposes.
505 */
506 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
507 InputEventConsistencyVerifier.isInstrumentationEnabled() ?
508 new InputEventConsistencyVerifier(this, 0) : null;
509
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700510 static final class SystemUiVisibilityInfo {
511 int seq;
512 int globalVisibility;
513 int localValue;
514 int localChanges;
515 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700516
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800517 private String mTag = TAG;
518
Jeff Brown98365d72012-08-19 20:30:52 -0700519 public ViewRootImpl(Context context, Display display) {
Jeff Brownf9e989d2013-04-04 23:04:03 -0700520 mContext = context;
521 mWindowSession = WindowManagerGlobal.getWindowSession();
Jeff Brown98365d72012-08-19 20:30:52 -0700522 mDisplay = display;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800523 mBasePackageName = context.getBasePackageName();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 mThread = Thread.currentThread();
525 mLocation = new WindowLeaked(null);
526 mLocation.fillInStackTrace();
527 mWidth = -1;
528 mHeight = -1;
529 mDirty = new Rect();
530 mTempRect = new Rect();
531 mVisRect = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800532 mWinFrame = new Rect();
Romain Guyfb8b7632010-08-23 21:05:08 -0700533 mWindow = new W(this);
Dianne Hackborn180c4842011-09-13 12:39:25 -0700534 mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 mViewVisibility = View.GONE;
536 mTransparentRegion = new Region();
537 mPreviousTransparentRegion = new Region();
538 mFirst = true; // true for the first time the view is added
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 mAdded = false;
John Reckd94094e2016-09-08 14:12:26 -0700540 mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
541 context);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700542 mAccessibilityManager = AccessibilityManager.getInstance(context);
Svetoslav Ganov00d0c142012-02-24 11:30:49 -0800543 mAccessibilityManager.addAccessibilityStateChangeListener(
Phil Weaver26d709f2017-04-20 17:19:14 -0700544 mAccessibilityInteractionConnectionManager, mHandler);
Chris Craikcce47eb2014-07-16 15:12:15 -0700545 mHighContrastTextManager = new HighContrastTextManager();
546 mAccessibilityManager.addHighTextContrastStateChangeListener(
Phil Weaver26d709f2017-04-20 17:19:14 -0700547 mHighContrastTextManager, mHandler);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 mViewConfiguration = ViewConfiguration.get(context);
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700549 mDensity = context.getResources().getDisplayMetrics().densityDpi;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700550 mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
Jorim Jaggib10e33f2015-02-04 21:57:40 +0100551 mFallbackEventHandler = new PhoneFallbackEventHandler(context);
Jeff Brown96e942d2011-11-30 19:55:01 -0800552 mChoreographer = Choreographer.getInstance();
Jeff Brownd912e1f2014-04-11 18:46:22 -0700553 mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
Evan Rosky37df2db2017-01-24 16:35:52 -0800554
555 if (!sCompatibilityDone) {
Evan Roskybdc66cb2017-09-08 14:27:24 -0700556 sAlwaysAssignFocus = mTargetSdkVersion < Build.VERSION_CODES.P;
Evan Rosky37df2db2017-01-24 16:35:52 -0800557
558 sCompatibilityDone = true;
559 }
560
Dianne Hackborna53de062012-05-08 18:53:51 -0700561 loadSystemProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 }
563
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800564 public static void addFirstDrawHandler(Runnable callback) {
565 synchronized (sFirstDrawHandlers) {
566 if (!sFirstDrawComplete) {
567 sFirstDrawHandlers.add(callback);
568 }
569 }
570 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700571
Andrii Kulian44607962017-03-16 11:06:24 -0700572 /** Add static config callback to be notified about global config changes. */
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100573 @UnsupportedAppUsage
Andrii Kulian44607962017-03-16 11:06:24 -0700574 public static void addConfigCallback(ConfigChangedCallback callback) {
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800575 synchronized (sConfigCallbacks) {
576 sConfigCallbacks.add(callback);
577 }
578 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700579
Andrii Kulian44607962017-03-16 11:06:24 -0700580 /** Add activity config callback to be notified about override config changes. */
581 public void setActivityConfigCallback(ActivityConfigCallback callback) {
582 mActivityConfigCallback = callback;
583 }
584
Chong Zhangdcee1de2015-10-06 10:26:00 -0700585 public void addWindowCallbacks(WindowCallbacks callback) {
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +0900586 synchronized (mWindowCallbacks) {
587 mWindowCallbacks.add(callback);
Skuhneb8160872015-09-22 09:51:39 -0700588 }
589 }
590
Chong Zhangdcee1de2015-10-06 10:26:00 -0700591 public void removeWindowCallbacks(WindowCallbacks callback) {
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +0900592 synchronized (mWindowCallbacks) {
593 mWindowCallbacks.remove(callback);
Skuhneb8160872015-09-22 09:51:39 -0700594 }
595 }
596
Chong Zhang8dbd9ad2015-10-09 10:06:11 -0700597 public void reportDrawFinish() {
598 if (mWindowDrawCountDown != null) {
599 mWindowDrawCountDown.countDown();
600 }
601 }
602
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603 // FIXME for perf testing only
604 private boolean mProfile = false;
605
606 /**
607 * Call this to profile the next traversal call.
608 * FIXME for perf testing only. Remove eventually
609 */
610 public void profile() {
611 mProfile = true;
612 }
613
614 /**
615 * Indicates whether we are in touch mode. Calling this method triggers an IPC
616 * call and should be avoided whenever possible.
617 *
618 * @return True, if the device is in touch mode, false otherwise.
619 *
620 * @hide
621 */
622 static boolean isInTouchMode() {
Jeff Brown98365d72012-08-19 20:30:52 -0700623 IWindowSession windowSession = WindowManagerGlobal.peekWindowSession();
624 if (windowSession != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800625 try {
Jeff Brown98365d72012-08-19 20:30:52 -0700626 return windowSession.getInTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800627 } catch (RemoteException e) {
628 }
629 }
630 return false;
631 }
632
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 /**
Robert Carrb2594852016-04-25 16:21:13 -0700634 * Notifies us that our child has been rebuilt, following
635 * a window preservation operation. In these cases we
636 * keep the same DecorView, but the activity controlling it
637 * is a different instance, and we need to update our
638 * callbacks.
639 *
640 * @hide
641 */
642 public void notifyChildRebuilt() {
643 if (mView instanceof RootViewSurfaceTaker) {
Robert Carr25cfa132016-11-16 13:24:09 -0800644 if (mSurfaceHolderCallback != null) {
645 mSurfaceHolder.removeCallback(mSurfaceHolderCallback);
646 }
647
Robert Carrb2594852016-04-25 16:21:13 -0700648 mSurfaceHolderCallback =
649 ((RootViewSurfaceTaker)mView).willYouTakeTheSurface();
Robert Carr25cfa132016-11-16 13:24:09 -0800650
Robert Carrb2594852016-04-25 16:21:13 -0700651 if (mSurfaceHolderCallback != null) {
652 mSurfaceHolder = new TakenSurfaceHolder();
653 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
Robert Carr25cfa132016-11-16 13:24:09 -0800654 mSurfaceHolder.addCallback(mSurfaceHolderCallback);
Robert Carrb2594852016-04-25 16:21:13 -0700655 } else {
656 mSurfaceHolder = null;
657 }
658
659 mInputQueueCallback =
660 ((RootViewSurfaceTaker)mView).willYouTakeTheInputQueue();
661 if (mInputQueueCallback != null) {
662 mInputQueueCallback.onInputQueueCreated(mInputQueue);
663 }
664 }
665 }
666
667 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 * We have one child
669 */
Romain Guye4d01122010-06-16 18:44:05 -0700670 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 synchronized (this) {
672 if (mView == null) {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700673 mView = view;
Jeff Brownd912e1f2014-04-11 18:46:22 -0700674
675 mAttachInfo.mDisplayState = mDisplay.getState();
676 mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
677
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700678 mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
Joe Onorato86f67862010-11-05 18:57:34 -0700679 mFallbackEventHandler.setView(view);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700680 mWindowAttributes.copyFrom(attrs);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800681 if (mWindowAttributes.packageName == null) {
682 mWindowAttributes.packageName = mBasePackageName;
683 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700684 attrs = mWindowAttributes;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800685 setTag();
Chong Zhang4ffc3182016-05-04 15:06:02 -0700686
Chong Zhang44aabe42016-05-10 11:20:14 -0700687 if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
688 & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
Chong Zhang4ffc3182016-05-04 15:06:02 -0700689 && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) {
Chong Zhang44aabe42016-05-10 11:20:14 -0700690 Slog.d(mTag, "setView: FLAG_KEEP_SCREEN_ON changed from true to false!");
Chong Zhang4ffc3182016-05-04 15:06:02 -0700691 }
Dianne Hackborn9d090892012-06-11 18:35:41 -0700692 // Keep track of the actual window flags supplied by the client.
693 mClientWindowLayoutFlags = attrs.flags;
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700694
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700695 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700696
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700697 if (view instanceof RootViewSurfaceTaker) {
698 mSurfaceHolderCallback =
699 ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
700 if (mSurfaceHolderCallback != null) {
701 mSurfaceHolder = new TakenSurfaceHolder();
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700702 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
Robert Carr25cfa132016-11-16 13:24:09 -0800703 mSurfaceHolder.addCallback(mSurfaceHolderCallback);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700704 }
705 }
Romain Guy1aec9a22011-01-05 09:37:12 -0800706
Alan Viverette49a22e82014-07-12 20:01:27 -0700707 // Compute surface insets required to draw at specified Z value.
708 // TODO: Use real shadow insets for a constant max Z.
Alan Viverette5435a302015-01-29 10:25:34 -0800709 if (!attrs.hasManualSurfaceInsets) {
Wale Ogunwale246c2092016-04-07 14:12:44 -0700710 attrs.setSurfaceInsets(view, false /*manual*/, true /*preservePrevious*/);
Alan Viverette5435a302015-01-29 10:25:34 -0800711 }
Alan Viverette49a22e82014-07-12 20:01:27 -0700712
Adam Lesinski4ece3d62016-06-16 18:05:41 -0700713 CompatibilityInfo compatibilityInfo =
714 mDisplay.getDisplayAdjustments().getCompatibilityInfo();
Romain Guy856d4e12011-10-14 15:47:55 -0700715 mTranslator = compatibilityInfo.getTranslator();
716
Romain Guy1aec9a22011-01-05 09:37:12 -0800717 // If the application owns the surface, don't enable hardware acceleration
718 if (mSurfaceHolder == null) {
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +0900719 // While this is supposed to enable only, it can effectively disable
720 // the acceleration too.
Romain Guy3b748a42013-04-17 18:54:38 -0700721 enableHardwareAcceleration(attrs);
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +0900722 final boolean useMTRenderer = MT_RENDERER_AVAILABLE
723 && mAttachInfo.mThreadedRenderer != null;
724 if (mUseMTRenderer != useMTRenderer) {
725 // Shouldn't be resizing, as it's done only in window setup,
726 // but end just in case.
727 endDragResizing();
728 mUseMTRenderer = useMTRenderer;
729 }
Romain Guy1aec9a22011-01-05 09:37:12 -0800730 }
731
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700732 boolean restore = false;
Romain Guy35b38ce2009-10-07 13:38:55 -0700733 if (mTranslator != null) {
Romain Guy856d4e12011-10-14 15:47:55 -0700734 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700735 restore = true;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700736 attrs.backup();
737 mTranslator.translateWindowLayout(attrs);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700738 }
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800739 if (DEBUG_LAYOUT) Log.d(mTag, "WindowLayout in setView:" + attrs);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700740
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700741 if (!compatibilityInfo.supportsScreen()) {
Adam Lesinski95c42972013-10-02 10:13:27 -0700742 attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700743 mLastInCompatMode = true;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700744 }
745
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800746 mSoftInputMode = attrs.softInputMode;
747 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -0700748 mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800749 mAttachInfo.mRootView = view;
Romain Guy35b38ce2009-10-07 13:38:55 -0700750 mAttachInfo.mScalingRequired = mTranslator != null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700751 mAttachInfo.mApplicationScale =
752 mTranslator == null ? 1.0f : mTranslator.applicationScale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800753 if (panelParentView != null) {
754 mAttachInfo.mPanelParentWindowToken
755 = panelParentView.getApplicationWindowToken();
756 }
757 mAdded = true;
758 int res; /* = WindowManagerImpl.ADD_OKAY; */
Romain Guy8506ab42009-06-11 17:35:47 -0700759
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 // Schedule the first layout -before- adding to the window
761 // manager, to make sure we do the relayout before receiving
762 // any other events from the system.
763 requestLayout();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700764 if ((mWindowAttributes.inputFeatures
765 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
766 mInputChannel = new InputChannel();
767 }
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800768 mForceDecorViewVisibility = (mWindowAttributes.privateFlags
769 & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 try {
Dianne Hackborn180c4842011-09-13 12:39:25 -0700771 mOrigWindowType = mWindowAttributes.type;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700772 mAttachInfo.mRecomputeGlobalAttributes = true;
773 collectViewAttributes();
Jeff Brown98365d72012-08-19 20:30:52 -0700774 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
Adrian Roos9e370f22018-03-06 18:19:45 +0100775 getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
Filip Gruszczynski0ec13282015-06-25 11:26:01 -0700776 mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
Adrian Roos5c6b6222017-11-07 17:36:10 +0100777 mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800778 } catch (RemoteException e) {
779 mAdded = false;
780 mView = null;
781 mAttachInfo.mRootView = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700782 mInputChannel = null;
Joe Onorato86f67862010-11-05 18:57:34 -0700783 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700785 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 throw new RuntimeException("Adding window failed", e);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700787 } finally {
788 if (restore) {
789 attrs.restore();
790 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800791 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700792
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700793 if (mTranslator != null) {
794 mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700795 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800796 mPendingOverscanInsets.set(0, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797 mPendingContentInsets.set(mAttachInfo.mContentInsets);
Adrian Roosfa104232014-06-20 16:10:14 -0700798 mPendingStableInsets.set(mAttachInfo.mStableInsets);
Adrian Roos5c6b6222017-11-07 17:36:10 +0100799 mPendingDisplayCutout.set(mAttachInfo.mDisplayCutout);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800 mPendingVisibleInsets.set(0, 0, 0, 0);
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -0800801 mAttachInfo.mAlwaysConsumeNavBar =
802 (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR) != 0;
803 mPendingAlwaysConsumeNavBar = mAttachInfo.mAlwaysConsumeNavBar;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800804 if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
Jeff Brown98365d72012-08-19 20:30:52 -0700805 if (res < WindowManagerGlobal.ADD_OKAY) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800806 mAttachInfo.mRootView = null;
807 mAdded = false;
Joe Onorato86f67862010-11-05 18:57:34 -0700808 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700810 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811 switch (res) {
Jeff Brown98365d72012-08-19 20:30:52 -0700812 case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
813 case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
814 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800815 "Unable to add window -- token " + attrs.token
816 + " is not valid; is your activity running?");
Jeff Brown98365d72012-08-19 20:30:52 -0700817 case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
818 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800819 "Unable to add window -- token " + attrs.token
820 + " is not for an application");
Jeff Brown98365d72012-08-19 20:30:52 -0700821 case WindowManagerGlobal.ADD_APP_EXITING:
822 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800823 "Unable to add window -- app for token " + attrs.token
824 + " is exiting");
Jeff Brown98365d72012-08-19 20:30:52 -0700825 case WindowManagerGlobal.ADD_DUPLICATE_ADD:
826 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800827 "Unable to add window -- window " + mWindow
828 + " has already been added");
Jeff Brown98365d72012-08-19 20:30:52 -0700829 case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800830 // Silently ignore -- we would have just removed it
831 // right away, anyway.
832 return;
Jeff Brown98365d72012-08-19 20:30:52 -0700833 case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
Alan Viverette73f6d602015-09-14 16:01:19 -0400834 throw new WindowManager.BadTokenException("Unable to add window "
835 + mWindow + " -- another window of type "
836 + mWindowAttributes.type + " already exists");
Jeff Brown98365d72012-08-19 20:30:52 -0700837 case WindowManagerGlobal.ADD_PERMISSION_DENIED:
Alan Viverette73f6d602015-09-14 16:01:19 -0400838 throw new WindowManager.BadTokenException("Unable to add window "
839 + mWindow + " -- permission denied for window type "
840 + mWindowAttributes.type);
Craig Mautner6018aee2012-10-23 14:27:49 -0700841 case WindowManagerGlobal.ADD_INVALID_DISPLAY:
Alan Viverette73f6d602015-09-14 16:01:19 -0400842 throw new WindowManager.InvalidDisplayException("Unable to add window "
843 + mWindow + " -- the specified display can not be found");
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800844 case WindowManagerGlobal.ADD_INVALID_TYPE:
Alan Viverette73f6d602015-09-14 16:01:19 -0400845 throw new WindowManager.InvalidDisplayException("Unable to add window "
846 + mWindow + " -- the specified window type "
847 + mWindowAttributes.type + " is not valid");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 }
849 throw new RuntimeException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800850 "Unable to add window -- unknown error code " + res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800851 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700852
Jeff Brown00fa7bd2010-07-02 15:37:36 -0700853 if (view instanceof RootViewSurfaceTaker) {
854 mInputQueueCallback =
855 ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
856 }
Jeff Browncc4f7db2011-08-30 20:34:48 -0700857 if (mInputChannel != null) {
858 if (mInputQueueCallback != null) {
Michael Wrighta44dd262013-04-10 21:12:00 -0700859 mInputQueue = new InputQueue();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700860 mInputQueueCallback.onInputQueueCreated(mInputQueue);
Jeff Browncc4f7db2011-08-30 20:34:48 -0700861 }
Michael Wrighta44dd262013-04-10 21:12:00 -0700862 mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
863 Looper.myLooper());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700864 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700865
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 view.assignParent(this);
Jeff Brown98365d72012-08-19 20:30:52 -0700867 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
868 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700869
870 if (mAccessibilityManager.isEnabled()) {
871 mAccessibilityInteractionConnectionManager.ensureConnection();
872 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700873
874 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
875 view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
876 }
Michael Wright95ae9422013-03-14 10:58:50 -0700877
Jeff Brownf9e989d2013-04-04 23:04:03 -0700878 // Set up the input pipeline.
879 CharSequence counterSuffix = attrs.getTitle();
Michael Wright899d7052014-04-23 17:23:39 -0700880 mSyntheticInputStage = new SyntheticInputStage();
881 InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
Jeff Brownf9e989d2013-04-04 23:04:03 -0700882 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
883 "aq:native-post-ime:" + counterSuffix);
884 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
885 InputStage imeStage = new ImeInputStage(earlyPostImeStage,
886 "aq:ime:" + counterSuffix);
887 InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
888 InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
889 "aq:native-pre-ime:" + counterSuffix);
890
891 mFirstInputStage = nativePreImeStage;
892 mFirstPostImeInputStage = earlyPostImeStage;
893 mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800894 }
895 }
896 }
897
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800898 private void setTag() {
899 final String[] split = mWindowAttributes.getTitle().toString().split("\\.");
900 if (split.length > 0) {
901 mTag = TAG + "[" + split[split.length - 1] + "]";
902 }
903 }
904
keunyoung30f420f2013-08-02 14:23:10 -0700905 /** Whether the window is in local focus mode or not */
906 private boolean isInLocalFocusMode() {
907 return (mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0;
908 }
909
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100910 @UnsupportedAppUsage
Dianne Hackborn49b043f2015-05-07 14:21:38 -0700911 public int getWindowFlags() {
912 return mWindowAttributes.flags;
913 }
914
Dianne Hackbornece0f4f2015-06-11 13:29:01 -0700915 public int getDisplayId() {
916 return mDisplay.getDisplayId();
917 }
918
Dianne Hackborna7bb6fb2015-02-03 18:13:40 -0800919 public CharSequence getTitle() {
920 return mWindowAttributes.getTitle();
921 }
922
Mihai Popa3589c2c2018-01-25 19:26:30 +0000923 /**
924 * @return the width of the root view. Note that this will return {@code -1} until the first
925 * layout traversal, when the width is set.
926 *
927 * @hide
928 */
929 public int getWidth() {
930 return mWidth;
931 }
932
933 /**
934 * @return the height of the root view. Note that this will return {@code -1} until the first
935 * layout traversal, when the height is set.
936 *
937 * @hide
938 */
939 public int getHeight() {
940 return mHeight;
941 }
942
Romain Guy8ff6b9e2011-11-09 20:10:18 -0800943 void destroyHardwareResources() {
Stan Iliev45faba52016-06-28 13:33:15 -0400944 if (mAttachInfo.mThreadedRenderer != null) {
945 mAttachInfo.mThreadedRenderer.destroyHardwareResources(mView);
946 mAttachInfo.mThreadedRenderer.destroy();
Romain Guy31f2c2e2011-11-21 10:55:41 -0800947 }
948 }
949
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100950 @UnsupportedAppUsage
Bo Liu845535a2014-03-21 12:06:23 -0700951 public void detachFunctor(long functor) {
Stan Iliev45faba52016-06-28 13:33:15 -0400952 if (mAttachInfo.mThreadedRenderer != null) {
John Reck44ac42a2014-05-16 14:46:07 -0700953 // Fence so that any pending invokeFunctor() messages will be processed
954 // before we return from detachFunctor.
Stan Iliev45faba52016-06-28 13:33:15 -0400955 mAttachInfo.mThreadedRenderer.stopDrawing();
John Reck44ac42a2014-05-16 14:46:07 -0700956 }
Romain Guyba6be8a2012-04-23 18:22:09 -0700957 }
958
John Reck3b202512014-06-23 13:13:08 -0700959 /**
960 * Schedules the functor for execution in either kModeProcess or
961 * kModeProcessNoContext, depending on whether or not there is an EGLContext.
962 *
963 * @param functor The native functor to invoke
964 * @param waitForCompletion If true, this will not return until the functor
965 * has invoked. If false, the functor may be invoked
966 * asynchronously.
967 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100968 @UnsupportedAppUsage
John Reck44b49f02016-03-25 14:29:48 -0700969 public static void invokeFunctor(long functor, boolean waitForCompletion) {
John Reck3b202512014-06-23 13:13:08 -0700970 ThreadedRenderer.invokeFunctor(functor, waitForCompletion);
Bo Liuae738a72014-04-27 16:22:04 -0700971 }
972
John Reck119907c2014-08-14 09:02:01 -0700973 public void registerAnimatingRenderNode(RenderNode animator) {
Stan Iliev45faba52016-06-28 13:33:15 -0400974 if (mAttachInfo.mThreadedRenderer != null) {
975 mAttachInfo.mThreadedRenderer.registerAnimatingRenderNode(animator);
John Reck119907c2014-08-14 09:02:01 -0700976 } else {
977 if (mAttachInfo.mPendingAnimatingRenderNodes == null) {
978 mAttachInfo.mPendingAnimatingRenderNodes = new ArrayList<RenderNode>();
979 }
980 mAttachInfo.mPendingAnimatingRenderNodes.add(animator);
981 }
982 }
983
Doris Liu718cd3e2016-05-17 16:50:31 -0700984 public void registerVectorDrawableAnimator(
985 AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) {
Stan Iliev45faba52016-06-28 13:33:15 -0400986 if (mAttachInfo.mThreadedRenderer != null) {
987 mAttachInfo.mThreadedRenderer.registerVectorDrawableAnimator(animator);
Doris Liu718cd3e2016-05-17 16:50:31 -0700988 }
989 }
990
Jorim Jaggi64be98d2018-04-26 23:23:29 +0200991 /**
992 * Registers a callback to be executed when the next frame is being drawn on RenderThread. This
993 * callback will be executed on a RenderThread worker thread, and only used for the next frame
994 * and thus it will only fire once.
995 *
996 * @param callback The callback to register.
997 */
998 public void registerRtFrameCallback(FrameDrawingCallback callback) {
999 mNextRtFrameCallback = callback;
1000 }
1001
Mathew Inwoode5ad5982018-08-17 15:07:52 +01001002 @UnsupportedAppUsage
Romain Guy3b748a42013-04-17 18:54:38 -07001003 private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
Dianne Hackborn7eec10e2010-11-12 18:03:47 -08001004 mAttachInfo.mHardwareAccelerated = false;
1005 mAttachInfo.mHardwareAccelerationRequested = false;
Romain Guy4f6aff32011-01-12 16:21:41 -08001006
Romain Guy856d4e12011-10-14 15:47:55 -07001007 // Don't enable hardware acceleration when the application is in compatibility mode
John Reckdd58e792014-04-02 16:54:28 +00001008 if (mTranslator != null) return;
Romain Guy856d4e12011-10-14 15:47:55 -07001009
Dianne Hackborn7eec10e2010-11-12 18:03:47 -08001010 // Try to enable hardware acceleration if requested
Igor Murashkina86ab6402013-08-30 12:58:36 -07001011 final boolean hardwareAccelerated =
Jim Miller1b365922011-03-09 19:38:07 -08001012 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
1013
John Reckdd58e792014-04-02 16:54:28 +00001014 if (hardwareAccelerated) {
John Reck51aaf902015-12-02 15:08:07 -08001015 if (!ThreadedRenderer.isAvailable()) {
Romain Guy1af23a32011-03-24 16:03:55 -07001016 return;
1017 }
1018
Dianne Hackborn5d927c22011-09-02 12:22:18 -07001019 // Persistent processes (including the system) should not do
1020 // accelerated rendering on low-end devices. In that case,
1021 // sRendererDisabled will be set. In addition, the system process
1022 // itself should never do accelerated rendering. In that case, both
1023 // sRendererDisabled and sSystemRendererDisabled are set. When
1024 // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
1025 // can be used by code on the system process to escape that and enable
1026 // HW accelerated drawing. (This is basically for the lock screen.)
Jim Miller1b365922011-03-09 19:38:07 -08001027
John Reck61375a82014-09-18 19:27:48 +00001028 final boolean fakeHwAccelerated = (attrs.privateFlags &
1029 WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
Dianne Hackborn5d927c22011-09-02 12:22:18 -07001030 final boolean forceHwAccelerated = (attrs.privateFlags &
1031 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
Jim Miller1b365922011-03-09 19:38:07 -08001032
John Reck61375a82014-09-18 19:27:48 +00001033 if (fakeHwAccelerated) {
1034 // This is exclusively for the preview windows the window manager
1035 // shows for launching applications, so they will look more like
1036 // the app being launched.
1037 mAttachInfo.mHardwareAccelerationRequested = true;
John Reck51aaf902015-12-02 15:08:07 -08001038 } else if (!ThreadedRenderer.sRendererDisabled
1039 || (ThreadedRenderer.sSystemRendererDisabled && forceHwAccelerated)) {
Stan Iliev45faba52016-06-28 13:33:15 -04001040 if (mAttachInfo.mThreadedRenderer != null) {
1041 mAttachInfo.mThreadedRenderer.destroy();
Romain Guy211370f2012-02-01 16:10:55 -08001042 }
1043
Alan Viverette2b12b582014-10-29 11:11:40 -07001044 final Rect insets = attrs.surfaceInsets;
Alan Viverette2cd23e62014-11-04 17:04:02 -08001045 final boolean hasSurfaceInsets = insets.left != 0 || insets.right != 0
1046 || insets.top != 0 || insets.bottom != 0;
Alan Viverette2b12b582014-10-29 11:11:40 -07001047 final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;
Romain Guy26a2b972017-04-17 09:39:51 -07001048 final boolean wideGamut =
Romain Guye89d0bb2017-06-20 12:23:42 -07001049 mContext.getResources().getConfiguration().isScreenWideColorGamut()
1050 && attrs.getColorMode() == ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT;
Romain Guy26a2b972017-04-17 09:39:51 -07001051
John Reckdf1742e2017-01-19 15:56:21 -08001052 mAttachInfo.mThreadedRenderer = ThreadedRenderer.create(mContext, translucent,
1053 attrs.getTitle().toString());
Romain Guy26a2b972017-04-17 09:39:51 -07001054 mAttachInfo.mThreadedRenderer.setWideGamut(wideGamut);
Stan Iliev45faba52016-06-28 13:33:15 -04001055 if (mAttachInfo.mThreadedRenderer != null) {
Romain Guye55945e2013-04-04 15:26:04 -07001056 mAttachInfo.mHardwareAccelerated =
1057 mAttachInfo.mHardwareAccelerationRequested = true;
1058 }
Romain Guye4d01122010-06-16 18:44:05 -07001059 }
1060 }
1061 }
1062
Mathew Inwoode5ad5982018-08-17 15:07:52 +01001063 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 public View getView() {
1065 return mView;
1066 }
1067
1068 final WindowLeaked getLocation() {
1069 return mLocation;
1070 }
1071
1072 void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
1073 synchronized (this) {
Alan Viverettedbed8932014-08-06 17:54:52 -07001074 final int oldInsetLeft = mWindowAttributes.surfaceInsets.left;
1075 final int oldInsetTop = mWindowAttributes.surfaceInsets.top;
1076 final int oldInsetRight = mWindowAttributes.surfaceInsets.right;
1077 final int oldInsetBottom = mWindowAttributes.surfaceInsets.bottom;
1078 final int oldSoftInputMode = mWindowAttributes.softInputMode;
Alan Viverette5435a302015-01-29 10:25:34 -08001079 final boolean oldHasManualSurfaceInsets = mWindowAttributes.hasManualSurfaceInsets;
Chong Zhang44aabe42016-05-10 11:20:14 -07001080
1081 if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
1082 & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
Chong Zhang4ffc3182016-05-04 15:06:02 -07001083 && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) {
Chong Zhang44aabe42016-05-10 11:20:14 -07001084 Slog.d(mTag, "setLayoutParams: FLAG_KEEP_SCREEN_ON from true to false!");
Chong Zhang4ffc3182016-05-04 15:06:02 -07001085 }
Alan Viverettedbed8932014-08-06 17:54:52 -07001086
Dianne Hackborn9d090892012-06-11 18:35:41 -07001087 // Keep track of the actual window flags supplied by the client.
1088 mClientWindowLayoutFlags = attrs.flags;
Alan Viverettedbed8932014-08-06 17:54:52 -07001089
1090 // Preserve compatible window flag if exists.
1091 final int compatibleWindowFlag = mWindowAttributes.privateFlags
Adam Lesinski95c42972013-10-02 10:13:27 -07001092 & WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Alan Viverettedbed8932014-08-06 17:54:52 -07001093
1094 // Transfer over system UI visibility values as they carry current state.
Craig Mautner3fe38c02012-05-03 17:28:09 -07001095 attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
1096 attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
Alan Viverettedbed8932014-08-06 17:54:52 -07001097
Romain Guyf21c9b02011-09-06 16:56:54 -07001098 mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
John Spurlockbd957402013-10-03 11:38:39 -04001099 if ((mWindowAttributesChangesFlag
1100 & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) {
1101 // Recompute system ui visibility.
1102 mAttachInfo.mRecomputeGlobalAttributes = true;
1103 }
Teng-Hui Zhu27571282016-05-12 15:53:53 -07001104 if ((mWindowAttributesChangesFlag
1105 & WindowManager.LayoutParams.LAYOUT_CHANGED) != 0) {
1106 // Request to update light center.
1107 mAttachInfo.mNeedsUpdateLightCenter = true;
1108 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001109 if (mWindowAttributes.packageName == null) {
1110 mWindowAttributes.packageName = mBasePackageName;
1111 }
Adam Lesinski95c42972013-10-02 10:13:27 -07001112 mWindowAttributes.privateFlags |= compatibleWindowFlag;
Dianne Hackborn9d090892012-06-11 18:35:41 -07001113
Wale Ogunwale246c2092016-04-07 14:12:44 -07001114 if (mWindowAttributes.preservePreviousSurfaceInsets) {
1115 // Restore old surface insets.
1116 mWindowAttributes.surfaceInsets.set(
1117 oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
1118 mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
Robert Carr1bccabf2016-04-28 13:27:08 -07001119 } else if (mWindowAttributes.surfaceInsets.left != oldInsetLeft
1120 || mWindowAttributes.surfaceInsets.top != oldInsetTop
1121 || mWindowAttributes.surfaceInsets.right != oldInsetRight
1122 || mWindowAttributes.surfaceInsets.bottom != oldInsetBottom) {
Stan Iliev45faba52016-06-28 13:33:15 -04001123 mNeedsRendererSetup = true;
Wale Ogunwale246c2092016-04-07 14:12:44 -07001124 }
Alan Viverettedbed8932014-08-06 17:54:52 -07001125
Dianne Hackborn9d090892012-06-11 18:35:41 -07001126 applyKeepScreenOnFlag(mWindowAttributes);
1127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 if (newView) {
1129 mSoftInputMode = attrs.softInputMode;
1130 requestLayout();
1131 }
Alan Viverettedbed8932014-08-06 17:54:52 -07001132
The Android Open Source Project10592532009-03-18 17:39:46 -07001133 // Don't lose the mode we last auto-computed.
Alan Viverettedbed8932014-08-06 17:54:52 -07001134 if ((attrs.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
The Android Open Source Project10592532009-03-18 17:39:46 -07001135 == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
1136 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
1137 & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
Alan Viverettedbed8932014-08-06 17:54:52 -07001138 | (oldSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
The Android Open Source Project10592532009-03-18 17:39:46 -07001139 }
Alan Viverettedbed8932014-08-06 17:54:52 -07001140
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 mWindowAttributesChanged = true;
1142 scheduleTraversals();
1143 }
1144 }
1145
1146 void handleAppVisibility(boolean visible) {
1147 if (mAppVisible != visible) {
1148 mAppVisible = visible;
Andrii Kulian74b561a2017-08-11 09:06:46 -07001149 mAppVisibilityChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 scheduleTraversals();
John Reck73840ea2014-09-22 07:39:18 -07001151 if (!mAppVisible) {
1152 WindowManagerGlobal.trimForeground();
1153 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001154 }
1155 }
1156
1157 void handleGetNewSurface() {
1158 mNewSurfaceNeeded = true;
1159 mFullRedrawNeeded = true;
1160 scheduleTraversals();
1161 }
1162
Jeff Brownd912e1f2014-04-11 18:46:22 -07001163 private final DisplayListener mDisplayListener = new DisplayListener() {
1164 @Override
1165 public void onDisplayChanged(int displayId) {
1166 if (mView != null && mDisplay.getDisplayId() == displayId) {
1167 final int oldDisplayState = mAttachInfo.mDisplayState;
1168 final int newDisplayState = mDisplay.getState();
1169 if (oldDisplayState != newDisplayState) {
1170 mAttachInfo.mDisplayState = newDisplayState;
Jeff Brownc2932a12014-11-20 18:04:05 -08001171 pokeDrawLockIfNeeded();
Jeff Brownd912e1f2014-04-11 18:46:22 -07001172 if (oldDisplayState != Display.STATE_UNKNOWN) {
1173 final int oldScreenState = toViewScreenState(oldDisplayState);
1174 final int newScreenState = toViewScreenState(newDisplayState);
1175 if (oldScreenState != newScreenState) {
1176 mView.dispatchScreenStateChanged(newScreenState);
1177 }
1178 if (oldDisplayState == Display.STATE_OFF) {
1179 // Draw was suppressed so we need to for it to happen here.
1180 mFullRedrawNeeded = true;
1181 scheduleTraversals();
1182 }
1183 }
1184 }
Romain Guy7e4e5612012-03-05 14:37:29 -08001185 }
1186 }
Jeff Brownd912e1f2014-04-11 18:46:22 -07001187
1188 @Override
1189 public void onDisplayRemoved(int displayId) {
1190 }
1191
1192 @Override
1193 public void onDisplayAdded(int displayId) {
1194 }
1195
1196 private int toViewScreenState(int displayState) {
1197 return displayState == Display.STATE_OFF ?
1198 View.SCREEN_STATE_OFF : View.SCREEN_STATE_ON;
1199 }
1200 };
Romain Guy7e4e5612012-03-05 14:37:29 -08001201
Andrii Kulianb047b8b2017-02-08 18:38:26 -08001202 /**
1203 * Notify about move to a different display.
1204 * @param displayId The id of the display where this view root is moved to.
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07001205 * @param config Configuration of the resources on new display after move.
Andrii Kulianb047b8b2017-02-08 18:38:26 -08001206 *
1207 * @hide
1208 */
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07001209 public void onMovedToDisplay(int displayId, Configuration config) {
Andrii Kulianb047b8b2017-02-08 18:38:26 -08001210 if (mDisplay.getDisplayId() == displayId) {
1211 return;
1212 }
1213
1214 // Get new instance of display based on current display adjustments. It may be updated later
1215 // if moving between the displays also involved a configuration change.
Bryce Lee609bf652017-02-09 16:50:13 -08001216 mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(displayId,
1217 mView.getResources());
Andrii Kulianb047b8b2017-02-08 18:38:26 -08001218 mAttachInfo.mDisplayState = mDisplay.getState();
1219 // Internal state updated, now notify the view hierarchy.
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07001220 mView.dispatchMovedToDisplay(mDisplay, config);
Andrii Kulianb047b8b2017-02-08 18:38:26 -08001221 }
1222
Jeff Brownc2932a12014-11-20 18:04:05 -08001223 void pokeDrawLockIfNeeded() {
1224 final int displayState = mAttachInfo.mDisplayState;
1225 if (mView != null && mAdded && mTraversalScheduled
1226 && (displayState == Display.STATE_DOZE
1227 || displayState == Display.STATE_DOZE_SUSPEND)) {
1228 try {
1229 mWindowSession.pokeDrawLock(mWindow);
1230 } catch (RemoteException ex) {
1231 // System server died, oh well.
1232 }
1233 }
1234 }
1235
Craig Mautner6018aee2012-10-23 14:27:49 -07001236 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001237 public void requestFitSystemWindows() {
1238 checkThread();
Adrian Roosfa104232014-06-20 16:10:14 -07001239 mApplyInsetsRequested = true;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001240 scheduleTraversals();
1241 }
1242
Craig Mautner6018aee2012-10-23 14:27:49 -07001243 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001244 public void requestLayout() {
Chet Haase3efa7b52012-12-03 08:33:17 -08001245 if (!mHandlingLayoutInLayoutRequest) {
1246 checkThread();
1247 mLayoutRequested = true;
1248 scheduleTraversals();
1249 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001250 }
1251
Craig Mautner6018aee2012-10-23 14:27:49 -07001252 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001253 public boolean isLayoutRequested() {
1254 return mLayoutRequested;
1255 }
1256
Chris Craik9de95db2017-01-18 17:59:23 -08001257 @Override
1258 public void onDescendantInvalidated(@NonNull View child, @NonNull View descendant) {
1259 if ((descendant.mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) {
1260 mIsAnimating = true;
1261 }
1262 invalidate();
1263 }
1264
Mathew Inwoode5ad5982018-08-17 15:07:52 +01001265 @UnsupportedAppUsage
Romain Guycfef1232012-02-23 13:50:37 -08001266 void invalidate() {
1267 mDirty.set(0, 0, mWidth, mHeight);
John Recke4267ea2014-06-03 15:53:15 -07001268 if (!mWillDrawSoon) {
1269 scheduleTraversals();
1270 }
Romain Guycfef1232012-02-23 13:50:37 -08001271 }
1272
Dianne Hackborna53de062012-05-08 18:53:51 -07001273 void invalidateWorld(View view) {
1274 view.invalidate();
1275 if (view instanceof ViewGroup) {
Romain Guyf84208f2012-09-13 22:50:18 -07001276 ViewGroup parent = (ViewGroup) view;
1277 for (int i = 0; i < parent.getChildCount(); i++) {
Dianne Hackborna53de062012-05-08 18:53:51 -07001278 invalidateWorld(parent.getChildAt(i));
1279 }
1280 }
1281 }
1282
Craig Mautner6018aee2012-10-23 14:27:49 -07001283 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001284 public void invalidateChild(View child, Rect dirty) {
Romain Guycfef1232012-02-23 13:50:37 -08001285 invalidateChildInParent(null, dirty);
1286 }
1287
Craig Mautner8f303ad2013-06-14 11:32:22 -07001288 @Override
Romain Guycfef1232012-02-23 13:50:37 -08001289 public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001290 checkThread();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001291 if (DEBUG_DRAW) Log.v(mTag, "Invalidate child: " + dirty);
Romain Guycfef1232012-02-23 13:50:37 -08001292
Chet Haase70d4ba12010-10-06 09:46:45 -07001293 if (dirty == null) {
Chet Haase70d4ba12010-10-06 09:46:45 -07001294 invalidate();
Romain Guycfef1232012-02-23 13:50:37 -08001295 return null;
Chet Haase3561d062012-10-23 12:54:51 -07001296 } else if (dirty.isEmpty() && !mIsAnimating) {
Chet Haase05e91ed2012-07-03 14:17:57 -07001297 return null;
Chet Haase70d4ba12010-10-06 09:46:45 -07001298 }
Romain Guycfef1232012-02-23 13:50:37 -08001299
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001300 if (mCurScrollY != 0 || mTranslator != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001301 mTempRect.set(dirty);
Romain Guy1e095972009-07-07 11:22:45 -07001302 dirty = mTempRect;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001303 if (mCurScrollY != 0) {
Romain Guycfef1232012-02-23 13:50:37 -08001304 dirty.offset(0, -mCurScrollY);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001305 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001306 if (mTranslator != null) {
Romain Guy1e095972009-07-07 11:22:45 -07001307 mTranslator.translateRectInAppWindowToScreen(dirty);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001308 }
Romain Guy1e095972009-07-07 11:22:45 -07001309 if (mAttachInfo.mScalingRequired) {
1310 dirty.inset(-1, -1);
1311 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312 }
Romain Guycfef1232012-02-23 13:50:37 -08001313
Alan Viverettea7ea65e2015-05-15 11:30:21 -07001314 invalidateRectOnScreen(dirty);
1315
1316 return null;
1317 }
1318
1319 private void invalidateRectOnScreen(Rect dirty) {
Romain Guycfef1232012-02-23 13:50:37 -08001320 final Rect localDirty = mDirty;
1321 if (!localDirty.isEmpty() && !localDirty.contains(dirty)) {
Romain Guy02ccac62011-06-24 13:20:23 -07001322 mAttachInfo.mSetIgnoreDirtyState = true;
Romain Guy7d695942010-12-01 17:22:29 -08001323 mAttachInfo.mIgnoreDirtyState = true;
1324 }
Romain Guycfef1232012-02-23 13:50:37 -08001325
1326 // Add the new dirty rect to the current one
1327 localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
1328 // Intersect with the bounds of the window to skip
1329 // updates that lie outside of the visible region
Romain Guy7b2f8b82012-03-19 17:18:54 -07001330 final float appScale = mAttachInfo.mApplicationScale;
Chet Haase3561d062012-10-23 12:54:51 -07001331 final boolean intersected = localDirty.intersect(0, 0,
1332 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
1333 if (!intersected) {
Chet Haaseb78ee0e2012-10-17 11:32:01 -07001334 localDirty.setEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001335 }
Chet Haase3561d062012-10-23 12:54:51 -07001336 if (!mWillDrawSoon && (intersected || mIsAnimating)) {
1337 scheduleTraversals();
1338 }
Romain Guy0d9275e2010-10-26 14:22:30 -07001339 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001340
Daniel Koulomzin087ae472015-12-16 17:52:25 -05001341 public void setIsAmbientMode(boolean ambient) {
1342 mIsAmbientMode = ambient;
1343 }
1344
Robert Carr414ebc62017-04-12 12:01:00 -07001345 interface WindowStoppedCallback {
1346 public void windowStopped(boolean stopped);
1347 }
1348 private final ArrayList<WindowStoppedCallback> mWindowStoppedCallbacks = new ArrayList<>();
1349
1350 void addWindowStoppedCallback(WindowStoppedCallback c) {
1351 mWindowStoppedCallbacks.add(c);
1352 }
1353
1354 void removeWindowStoppedCallback(WindowStoppedCallback c) {
1355 mWindowStoppedCallbacks.remove(c);
1356 }
1357
George Mount41725de2015-04-09 08:23:05 -07001358 void setWindowStopped(boolean stopped) {
Dianne Hackbornce418e62011-03-01 14:31:38 -08001359 if (mStopped != stopped) {
1360 mStopped = stopped;
Stan Iliev45faba52016-06-28 13:33:15 -04001361 final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer;
John Reck8afcc762016-04-13 10:24:06 -07001362 if (renderer != null) {
1363 if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped);
1364 renderer.setStopped(mStopped);
1365 }
George Mount41725de2015-04-09 08:23:05 -07001366 if (!mStopped) {
Dianne Hackbornce418e62011-03-01 14:31:38 -08001367 scheduleTraversals();
John Reckd9b16072016-02-23 10:35:19 -08001368 } else {
John Reck8afcc762016-04-13 10:24:06 -07001369 if (renderer != null) {
1370 renderer.destroyHardwareResources(mView);
John Reckf4db3d22016-02-26 12:58:17 -08001371 }
Dianne Hackbornce418e62011-03-01 14:31:38 -08001372 }
Robert Carr414ebc62017-04-12 12:01:00 -07001373
1374 for (int i = 0; i < mWindowStoppedCallbacks.size(); i++) {
1375 mWindowStoppedCallbacks.get(i).windowStopped(stopped);
1376 }
Robert Carr6858bb92018-04-16 11:09:49 -07001377
1378 if (mStopped) {
Vishnu Nair47d2d1e2019-01-24 13:01:24 -08001379 if (mSurfaceHolder != null) {
1380 notifySurfaceDestroyed();
1381 }
Robert Carr6858bb92018-04-16 11:09:49 -07001382 mSurface.release();
1383 }
Dianne Hackbornce418e62011-03-01 14:31:38 -08001384 }
1385 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001386
George Mount41725de2015-04-09 08:23:05 -07001387 /**
1388 * Block the input events during an Activity Transition. The KEYCODE_BACK event is allowed
1389 * through to allow quick reversal of the Activity Transition.
1390 *
1391 * @param paused true to pause, false to resume.
1392 */
1393 public void setPausedForTransition(boolean paused) {
1394 mPausedForTransition = paused;
1395 }
1396
Craig Mautner8f303ad2013-06-14 11:32:22 -07001397 @Override
Romain Guycfef1232012-02-23 13:50:37 -08001398 public ViewParent getParent() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001399 return null;
1400 }
1401
Craig Mautner8f303ad2013-06-14 11:32:22 -07001402 @Override
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001403 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404 if (child != mView) {
1405 throw new RuntimeException("child is not mine, honest!");
1406 }
1407 // Note: don't apply scroll offset, because we want to know its
1408 // visibility in the virtual canvas being given to the view hierarchy.
1409 return r.intersect(0, 0, mWidth, mHeight);
1410 }
1411
Igor Murashkina86ab6402013-08-30 12:58:36 -07001412 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001413 public void bringChildToFront(View child) {
1414 }
1415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001416 int getHostVisibility() {
Bryce Lee16e50892017-04-11 01:59:37 +00001417 return (mAppVisible || mForceDecorViewVisibility) ? mView.getVisibility() : View.GONE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001418 }
Romain Guy8506ab42009-06-11 17:35:47 -07001419
Chet Haasecca2c982011-05-20 14:34:18 -07001420 /**
1421 * Add LayoutTransition to the list of transitions to be started in the next traversal.
1422 * This list will be cleared after the transitions on the list are start()'ed. These
1423 * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
1424 * happens during the layout phase of traversal, which we want to complete before any of the
1425 * animations are started (because those animations may side-effect properties that layout
1426 * depends upon, like the bounding rectangles of the affected views). So we add the transition
1427 * to the list and it is started just prior to starting the drawing phase of traversal.
1428 *
1429 * @param transition The LayoutTransition to be started on the next traversal.
1430 *
1431 * @hide
1432 */
1433 public void requestTransitionStart(LayoutTransition transition) {
1434 if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
1435 if (mPendingTransitions == null) {
1436 mPendingTransitions = new ArrayList<LayoutTransition>();
1437 }
1438 mPendingTransitions.add(transition);
1439 }
1440 }
1441
John Recka5dda642014-05-22 15:43:54 -07001442 /**
1443 * Notifies the HardwareRenderer that a new frame will be coming soon.
1444 * Currently only {@link ThreadedRenderer} cares about this, and uses
1445 * this knowledge to adjust the scheduling of off-thread animations
1446 */
1447 void notifyRendererOfFramePending() {
Stan Iliev45faba52016-06-28 13:33:15 -04001448 if (mAttachInfo.mThreadedRenderer != null) {
1449 mAttachInfo.mThreadedRenderer.notifyFramePending();
John Recka5dda642014-05-22 15:43:54 -07001450 }
1451 }
1452
Mathew Inwoode5ad5982018-08-17 15:07:52 +01001453 @UnsupportedAppUsage
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001454 void scheduleTraversals() {
1455 if (!mTraversalScheduled) {
1456 mTraversalScheduled = true;
Jeff Brown3d4e7efe2015-02-26 15:34:16 -08001457 mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001458 mChoreographer.postCallback(
1459 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
Michael Wright9d744c72014-02-18 21:27:42 -08001460 if (!mUnbufferedInputDispatch) {
1461 scheduleConsumeBatchedInput();
1462 }
John Recka5dda642014-05-22 15:43:54 -07001463 notifyRendererOfFramePending();
Jeff Brownc2932a12014-11-20 18:04:05 -08001464 pokeDrawLockIfNeeded();
Jeff Brown96e942d2011-11-30 19:55:01 -08001465 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001466 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001467
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001468 void unscheduleTraversals() {
1469 if (mTraversalScheduled) {
1470 mTraversalScheduled = false;
Jeff Brown3d4e7efe2015-02-26 15:34:16 -08001471 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001472 mChoreographer.removeCallbacks(
1473 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
1474 }
1475 }
1476
1477 void doTraversal() {
1478 if (mTraversalScheduled) {
1479 mTraversalScheduled = false;
Jeff Brown3d4e7efe2015-02-26 15:34:16 -08001480 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001481
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001482 if (mProfile) {
1483 Debug.startMethodTracing("ViewAncestor");
Jeff Brown96e942d2011-11-30 19:55:01 -08001484 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001485
Chris Craike22c59b2015-05-21 18:33:37 -07001486 performTraversals();
Jeff Brown96e942d2011-11-30 19:55:01 -08001487
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001488 if (mProfile) {
1489 Debug.stopMethodTracing();
1490 mProfile = false;
1491 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001492 }
1493 }
1494
Dianne Hackborn9d090892012-06-11 18:35:41 -07001495 private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) {
1496 // Update window's global keep screen on flag: if a view has requested
1497 // that the screen be kept on, then it is always set; otherwise, it is
1498 // set to whatever the client last requested for the global state.
1499 if (mAttachInfo.mKeepScreenOn) {
1500 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
1501 } else {
1502 params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
1503 | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1504 }
1505 }
1506
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001507 private boolean collectViewAttributes() {
Chris Craikd36a81f2014-07-17 10:16:51 -07001508 if (mAttachInfo.mRecomputeGlobalAttributes) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001509 //Log.i(mTag, "Computing view hierarchy attributes!");
Chris Craikd36a81f2014-07-17 10:16:51 -07001510 mAttachInfo.mRecomputeGlobalAttributes = false;
1511 boolean oldScreenOn = mAttachInfo.mKeepScreenOn;
1512 mAttachInfo.mKeepScreenOn = false;
1513 mAttachInfo.mSystemUiVisibility = 0;
1514 mAttachInfo.mHasSystemUiListeners = false;
1515 mView.dispatchCollectViewAttributes(mAttachInfo, 0);
1516 mAttachInfo.mSystemUiVisibility &= ~mAttachInfo.mDisabledSystemUiVisibility;
Craig Mautner7eac0f52012-09-13 13:14:14 -07001517 WindowManager.LayoutParams params = mWindowAttributes;
Chris Craikd36a81f2014-07-17 10:16:51 -07001518 mAttachInfo.mSystemUiVisibility |= getImpliedSystemUiVisibility(params);
1519 if (mAttachInfo.mKeepScreenOn != oldScreenOn
1520 || mAttachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
1521 || mAttachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
Dianne Hackborn9d090892012-06-11 18:35:41 -07001522 applyKeepScreenOnFlag(params);
Chris Craikd36a81f2014-07-17 10:16:51 -07001523 params.subtreeSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
1524 params.hasSystemUiListeners = mAttachInfo.mHasSystemUiListeners;
1525 mView.dispatchWindowSystemUiVisiblityChanged(mAttachInfo.mSystemUiVisibility);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001526 return true;
1527 }
1528 }
1529 return false;
1530 }
1531
John Spurlockbd957402013-10-03 11:38:39 -04001532 private int getImpliedSystemUiVisibility(WindowManager.LayoutParams params) {
1533 int vis = 0;
1534 // Translucent decor window flags imply stable system ui visibility.
1535 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) != 0) {
1536 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
1537 }
1538 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) != 0) {
1539 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
1540 }
1541 return vis;
1542 }
1543
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001544 private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
1545 final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
1546 int childWidthMeasureSpec;
1547 int childHeightMeasureSpec;
1548 boolean windowSizeMayChange = false;
1549
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001550 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(mTag,
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001551 "Measuring " + host + " in display " + desiredWindowWidth
1552 + "x" + desiredWindowHeight + "...");
1553
1554 boolean goodMeasure = false;
1555 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
1556 // On large screens, we don't want to allow dialogs to just
1557 // stretch to fill the entire width of the screen to display
1558 // one line of text. First try doing the layout at a smaller
1559 // size to see if it will fit.
1560 final DisplayMetrics packageMetrics = res.getDisplayMetrics();
1561 res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
1562 int baseSize = 0;
1563 if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
1564 baseSize = (int)mTmpValue.getDimension(packageMetrics);
1565 }
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08001566 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": baseSize=" + baseSize
1567 + ", desiredWindowWidth=" + desiredWindowWidth);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001568 if (baseSize != 0 && desiredWindowWidth > baseSize) {
1569 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
1570 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001571 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001572 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08001573 + host.getMeasuredWidth() + "," + host.getMeasuredHeight()
1574 + ") from width spec: " + MeasureSpec.toString(childWidthMeasureSpec)
1575 + " and height spec: " + MeasureSpec.toString(childHeightMeasureSpec));
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001576 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1577 goodMeasure = true;
1578 } else {
1579 // Didn't fit in that size... try expanding a bit.
1580 baseSize = (baseSize+desiredWindowWidth)/2;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001581 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": next baseSize="
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001582 + baseSize);
1583 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001584 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001585 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001586 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1587 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001588 if (DEBUG_DIALOG) Log.v(mTag, "Good!");
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001589 goodMeasure = true;
1590 }
1591 }
1592 }
1593 }
1594
1595 if (!goodMeasure) {
1596 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
1597 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001598 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001599 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
1600 windowSizeMayChange = true;
1601 }
1602 }
1603
1604 if (DBG) {
1605 System.out.println("======================================");
1606 System.out.println("performTraversals -- after measure");
1607 host.debug();
1608 }
1609
1610 return windowSizeMayChange;
1611 }
1612
Alan Viverettefed3f722013-11-14 14:48:20 -08001613 /**
1614 * Modifies the input matrix such that it maps view-local coordinates to
1615 * on-screen coordinates.
1616 *
1617 * @param m input matrix to modify
1618 */
1619 void transformMatrixToGlobal(Matrix m) {
Dake Gu7bf379c2014-07-15 16:29:38 -07001620 m.preTranslate(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
Alan Viverettefed3f722013-11-14 14:48:20 -08001621 }
1622
1623 /**
1624 * Modifies the input matrix such that it maps on-screen coordinates to
1625 * view-local coordinates.
1626 *
1627 * @param m input matrix to modify
1628 */
1629 void transformMatrixToLocal(Matrix m) {
Dake Gu7bf379c2014-07-15 16:29:38 -07001630 m.postTranslate(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
Alan Viverettefed3f722013-11-14 14:48:20 -08001631 }
1632
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001633 /* package */ WindowInsets getWindowInsets(boolean forceConstruct) {
1634 if (mLastWindowInsets == null || forceConstruct) {
1635 mDispatchContentInsets.set(mAttachInfo.mContentInsets);
1636 mDispatchStableInsets.set(mAttachInfo.mStableInsets);
Adrian Roos5c6b6222017-11-07 17:36:10 +01001637 mDispatchDisplayCutout = mAttachInfo.mDisplayCutout.get();
1638
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001639 Rect contentInsets = mDispatchContentInsets;
1640 Rect stableInsets = mDispatchStableInsets;
Adrian Roos5c6b6222017-11-07 17:36:10 +01001641 DisplayCutout displayCutout = mDispatchDisplayCutout;
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001642 // For dispatch we preserve old logic, but for direct requests from Views we allow to
1643 // immediately use pending insets.
1644 if (!forceConstruct
1645 && (!mPendingContentInsets.equals(contentInsets) ||
Adrian Roos5c6b6222017-11-07 17:36:10 +01001646 !mPendingStableInsets.equals(stableInsets) ||
1647 !mPendingDisplayCutout.get().equals(displayCutout))) {
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001648 contentInsets = mPendingContentInsets;
1649 stableInsets = mPendingStableInsets;
Adrian Roos5c6b6222017-11-07 17:36:10 +01001650 displayCutout = mPendingDisplayCutout.get();
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001651 }
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001652 Rect outsets = mAttachInfo.mOutsets;
1653 if (outsets.left > 0 || outsets.top > 0 || outsets.right > 0 || outsets.bottom > 0) {
1654 contentInsets = new Rect(contentInsets.left + outsets.left,
1655 contentInsets.top + outsets.top, contentInsets.right + outsets.right,
1656 contentInsets.bottom + outsets.bottom);
1657 }
Adrian Roos7419a172018-05-24 18:20:51 +02001658 contentInsets = ensureInsetsNonNegative(contentInsets, "content");
1659 stableInsets = ensureInsetsNonNegative(stableInsets, "stable");
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001660 mLastWindowInsets = new WindowInsets(contentInsets,
Adam Powell01f280d2015-05-18 16:07:42 -07001661 null /* windowDecorInsets */, stableInsets,
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08001662 mContext.getResources().getConfiguration().isScreenRound(),
Adrian Roos5c6b6222017-11-07 17:36:10 +01001663 mAttachInfo.mAlwaysConsumeNavBar, displayCutout);
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001664 }
1665 return mLastWindowInsets;
1666 }
1667
Adrian Roos7419a172018-05-24 18:20:51 +02001668 private Rect ensureInsetsNonNegative(Rect insets, String kind) {
1669 if (insets.left < 0 || insets.top < 0 || insets.right < 0 || insets.bottom < 0) {
Adrian Roos7419a172018-05-24 18:20:51 +02001670 return new Rect(Math.max(0, insets.left),
1671 Math.max(0, insets.top),
1672 Math.max(0, insets.right),
1673 Math.max(0, insets.bottom));
1674 }
1675 return insets;
1676 }
1677
Adam Powell2accbf92014-04-16 23:14:57 +00001678 void dispatchApplyInsets(View host) {
Adrian Roos2b0dcb32017-12-12 16:07:55 +01001679 WindowInsets insets = getWindowInsets(true /* forceConstruct */);
Adrian Roosfa02da62018-01-15 16:01:18 +01001680 final boolean dispatchCutout = (mWindowAttributes.layoutInDisplayCutoutMode
1681 == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS);
1682 if (!dispatchCutout) {
Adrian Roos2b0dcb32017-12-12 16:07:55 +01001683 // Window is either not laid out in cutout or the status bar inset takes care of
1684 // clearing the cutout, so we don't need to dispatch the cutout to the hierarchy.
Adrian Roosd07bafd2017-12-11 17:30:56 +01001685 insets = insets.consumeDisplayCutout();
Adrian Roos2b0dcb32017-12-12 16:07:55 +01001686 }
1687 host.dispatchApplyWindowInsets(insets);
Adam Powell2accbf92014-04-16 23:14:57 +00001688 }
1689
Chong Zhangf6525ce2016-01-14 17:09:56 -08001690 private static boolean shouldUseDisplaySize(final WindowManager.LayoutParams lp) {
1691 return lp.type == TYPE_STATUS_BAR_PANEL
1692 || lp.type == TYPE_INPUT_METHOD
1693 || lp.type == TYPE_VOLUME_OVERLAY;
1694 }
1695
1696 private int dipToPx(int dip) {
1697 final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
1698 return (int) (displayMetrics.density * dip + 0.5f);
1699 }
1700
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701 private void performTraversals() {
1702 // cache mView since it is used so much below...
1703 final View host = mView;
1704
1705 if (DBG) {
1706 System.out.println("======================================");
1707 System.out.println("performTraversals");
1708 host.debug();
1709 }
1710
1711 if (host == null || !mAdded)
1712 return;
1713
Craig Mautnerdf2390a2012-08-29 20:59:22 -07001714 mIsInTraversal = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001715 mWillDrawSoon = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001716 boolean windowSizeMayChange = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 boolean newSurface = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001718 boolean surfaceChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719 WindowManager.LayoutParams lp = mWindowAttributes;
1720
1721 int desiredWindowWidth;
1722 int desiredWindowHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001724 final int viewVisibility = getHostVisibility();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001725 final boolean viewVisibilityChanged = !mFirst
Andrii Kulian74b561a2017-08-11 09:06:46 -07001726 && (mViewVisibility != viewVisibility || mNewSurfaceNeeded
1727 // Also check for possible double visibility update, which will make current
1728 // viewVisibility value equal to mViewVisibility and we may miss it.
1729 || mAppVisibilityChanged);
1730 mAppVisibilityChanged = false;
Adam Powell06f9eb82016-08-24 17:09:01 -07001731 final boolean viewUserVisibilityChanged = !mFirst &&
1732 ((mViewVisibility == View.VISIBLE) != (viewVisibility == View.VISIBLE));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001733
1734 WindowManager.LayoutParams params = null;
1735 if (mWindowAttributesChanged) {
1736 mWindowAttributesChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001737 surfaceChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001738 params = lp;
1739 }
Adam Lesinski4ece3d62016-06-16 18:05:41 -07001740 CompatibilityInfo compatibilityInfo =
1741 mDisplay.getDisplayAdjustments().getCompatibilityInfo();
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001742 if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
1743 params = lp;
Jeff Brown96e942d2011-11-30 19:55:01 -08001744 mFullRedrawNeeded = true;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001745 mLayoutRequested = true;
1746 if (mLastInCompatMode) {
Adam Lesinski95c42972013-10-02 10:13:27 -07001747 params.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001748 mLastInCompatMode = false;
1749 } else {
Adam Lesinski95c42972013-10-02 10:13:27 -07001750 params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001751 mLastInCompatMode = true;
1752 }
1753 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001754
Romain Guyf21c9b02011-09-06 16:56:54 -07001755 mWindowAttributesChangesFlag = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -07001756
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001757 Rect frame = mWinFrame;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001758 if (mFirst) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001759 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001760 mLayoutRequested = true;
1761
Andrii Kulian44607962017-03-16 11:06:24 -07001762 final Configuration config = mContext.getResources().getConfiguration();
Chong Zhangf6525ce2016-01-14 17:09:56 -08001763 if (shouldUseDisplaySize(lp)) {
Dianne Hackborna239c842011-06-01 12:28:20 -07001764 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001765 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001766 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001767 desiredWindowWidth = size.x;
1768 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001769 } else {
Adrian Roos9e370f22018-03-06 18:19:45 +01001770 desiredWindowWidth = mWinFrame.width();
1771 desiredWindowHeight = mWinFrame.height();
Dianne Hackborna239c842011-06-01 12:28:20 -07001772 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001773
Romain Guyc5d55862011-01-21 19:01:46 -08001774 // We used to use the following condition to choose 32 bits drawing caches:
1775 // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
1776 // However, windows are now always 32 bits by default, so choose 32 bits
Chris Craikd36a81f2014-07-17 10:16:51 -07001777 mAttachInfo.mUse32BitDrawingCache = true;
1778 mAttachInfo.mHasWindowFocus = false;
1779 mAttachInfo.mWindowVisibility = viewVisibility;
1780 mAttachInfo.mRecomputeGlobalAttributes = false;
Andrii Kulian44607962017-03-16 11:06:24 -07001781 mLastConfigurationFromResources.setTo(config);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001782 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Fabrice Di Megliob003e282012-10-17 17:20:19 -07001783 // Set the layout direction if it has not been set before (inherit is the default)
1784 if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
Andrii Kulian44607962017-03-16 11:06:24 -07001785 host.setLayoutDirection(config.getLayoutDirection());
Fabrice Di Megliob003e282012-10-17 17:20:19 -07001786 }
Chris Craikd36a81f2014-07-17 10:16:51 -07001787 host.dispatchAttachedToWindow(mAttachInfo, 0);
1788 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
Adam Powell2accbf92014-04-16 23:14:57 +00001789 dispatchApplyInsets(host);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001790 } else {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001791 desiredWindowWidth = frame.width();
1792 desiredWindowHeight = frame.height();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001793 if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001794 if (DEBUG_ORIENTATION) Log.v(mTag, "View " + host + " resized to: " + frame);
Jeff Brown96e942d2011-11-30 19:55:01 -08001795 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001796 mLayoutRequested = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001797 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001798 }
1799 }
1800
1801 if (viewVisibilityChanged) {
Bryce Lee16e50892017-04-11 01:59:37 +00001802 mAttachInfo.mWindowVisibility = viewVisibility;
1803 host.dispatchWindowVisibilityChanged(viewVisibility);
Adam Powell06f9eb82016-08-24 17:09:01 -07001804 if (viewUserVisibilityChanged) {
Adam Powell64e1ba42016-08-22 09:09:44 -07001805 host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE);
1806 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001807 if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
Skuhneb8160872015-09-22 09:51:39 -07001808 endDragResizing();
Romain Guy65b345f2011-07-27 18:51:50 -07001809 destroyHardwareResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001810 }
1811 if (viewVisibility == View.GONE) {
1812 // After making a window gone, we will count it as being
1813 // shown for the first time the next time it gets focus.
1814 mHasHadWindowFocus = false;
1815 }
1816 }
1817
Alan Viverette7dbc3bf2015-01-28 16:14:36 -08001818 // Non-visible windows can't hold accessibility focus.
1819 if (mAttachInfo.mWindowVisibility != View.VISIBLE) {
1820 host.clearAccessibilityFocus();
1821 }
1822
Chet Haaseb78c2842012-04-19 13:39:50 -07001823 // Execute enqueued actions on every traversal in case a detached view enqueued an action
Chris Craikd36a81f2014-07-17 10:16:51 -07001824 getRunQueue().executeActions(mAttachInfo.mHandler);
Chet Haaseb78c2842012-04-19 13:39:50 -07001825
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001826 boolean insetsChanged = false;
Romain Guy8506ab42009-06-11 17:35:47 -07001827
Craig Mautner72d6f212015-02-19 16:33:09 -08001828 boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001829 if (layoutRequested) {
Romain Guy15df6702009-08-17 20:17:30 -07001830
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001831 final Resources res = mView.getContext().getResources();
1832
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001833 if (mFirst) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001834 // make sure touch mode code executes by setting cached value
1835 // to opposite of the added touch mode.
1836 mAttachInfo.mInTouchMode = !mAddedTouchMode;
Romain Guy2d4cff62010-04-09 15:39:00 -07001837 ensureTouchModeLocally(mAddedTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001838 } else {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001839 if (!mPendingOverscanInsets.equals(mAttachInfo.mOverscanInsets)) {
1840 insetsChanged = true;
1841 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001842 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001843 insetsChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001844 }
Adrian Roosfa104232014-06-20 16:10:14 -07001845 if (!mPendingStableInsets.equals(mAttachInfo.mStableInsets)) {
1846 insetsChanged = true;
1847 }
Adrian Roos5c6b6222017-11-07 17:36:10 +01001848 if (!mPendingDisplayCutout.equals(mAttachInfo.mDisplayCutout)) {
1849 insetsChanged = true;
1850 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001851 if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001852 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001853 if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001854 + mAttachInfo.mVisibleInsets);
1855 }
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001856 if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) {
1857 insetsChanged = true;
1858 }
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08001859 if (mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar) {
1860 insetsChanged = true;
1861 }
Chong Zhangf6525ce2016-01-14 17:09:56 -08001862 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
1863 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001864 windowSizeMayChange = true;
Chong Zhangf6525ce2016-01-14 17:09:56 -08001865
1866 if (shouldUseDisplaySize(lp)) {
1867 // NOTE -- system code, won't try to do compat mode.
1868 Point size = new Point();
1869 mDisplay.getRealSize(size);
1870 desiredWindowWidth = size.x;
1871 desiredWindowHeight = size.y;
1872 } else {
1873 Configuration config = res.getConfiguration();
1874 desiredWindowWidth = dipToPx(config.screenWidthDp);
1875 desiredWindowHeight = dipToPx(config.screenHeightDp);
1876 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001877 }
1878 }
1879
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001880 // Ask host how big it wants to be
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001881 windowSizeMayChange |= measureHierarchy(host, lp, res,
1882 desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001883 }
1884
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001885 if (collectViewAttributes()) {
1886 params = lp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001887 }
Chris Craikd36a81f2014-07-17 10:16:51 -07001888 if (mAttachInfo.mForceReportNewAttributes) {
1889 mAttachInfo.mForceReportNewAttributes = false;
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001890 params = lp;
1891 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001892
Chris Craikd36a81f2014-07-17 10:16:51 -07001893 if (mFirst || mAttachInfo.mViewVisibilityChanged) {
1894 mAttachInfo.mViewVisibilityChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001895 int resizeMode = mSoftInputMode &
1896 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
1897 // If we are in auto resize mode, then we need to determine
1898 // what mode to use now.
1899 if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001900 final int N = mAttachInfo.mScrollContainers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001901 for (int i=0; i<N; i++) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001902 if (mAttachInfo.mScrollContainers.get(i).isShown()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001903 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
1904 }
1905 }
1906 if (resizeMode == 0) {
1907 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
1908 }
1909 if ((lp.softInputMode &
1910 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
1911 lp.softInputMode = (lp.softInputMode &
1912 ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
1913 resizeMode;
1914 params = lp;
1915 }
1916 }
1917 }
Romain Guy8506ab42009-06-11 17:35:47 -07001918
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001919 if (params != null) {
1920 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
1921 if (!PixelFormat.formatHasAlpha(params.format)) {
1922 params.format = PixelFormat.TRANSLUCENT;
1923 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001924 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001925 mAttachInfo.mOverscanRequested = (params.flags
1926 & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001927 }
1928
Adrian Roosfa104232014-06-20 16:10:14 -07001929 if (mApplyInsetsRequested) {
1930 mApplyInsetsRequested = false;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001931 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Adam Powell2accbf92014-04-16 23:14:57 +00001932 dispatchApplyInsets(host);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001933 if (mLayoutRequested) {
1934 // Short-circuit catching a new layout request here, so
1935 // we don't need to go through two layout passes when things
1936 // change due to fitting system windows, which can happen a lot.
1937 windowSizeMayChange |= measureHierarchy(host, lp,
1938 mView.getContext().getResources(),
1939 desiredWindowWidth, desiredWindowHeight);
1940 }
1941 }
1942
1943 if (layoutRequested) {
1944 // Clear this now, so that if anything requests a layout in the
1945 // rest of this function we will catch it and re-run a full
1946 // layout pass.
1947 mLayoutRequested = false;
1948 }
1949
1950 boolean windowShouldResize = layoutRequested && windowSizeMayChange
Dianne Hackborn189ee182010-12-02 21:48:53 -08001951 && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
Romain Guy2e4f4262010-04-06 11:07:52 -07001952 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
1953 frame.width() < desiredWindowWidth && frame.width() != mWidth)
1954 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
1955 frame.height() < desiredWindowHeight && frame.height() != mHeight));
Jorim Jaggi4846ee32016-01-07 17:39:12 +01001956 windowShouldResize |= mDragResizing && mResizeMode == RESIZE_MODE_FREEFORM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001957
Jorim Jaggi4846ee32016-01-07 17:39:12 +01001958 // If the activity was just relaunched, it might have unfrozen the task bounds (while
1959 // relaunching), so we need to force a call into window manager to pick up the latest
1960 // bounds.
1961 windowShouldResize |= mActivityRelaunched;
1962
Jeff Brown2e05ec32013-09-30 15:57:43 -07001963 // Determine whether to compute insets.
1964 // If there are no inset listeners remaining then we may still need to compute
1965 // insets in case the old insets were non-empty and must be reset.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001966 final boolean computesInternalInsets =
Chris Craikd36a81f2014-07-17 10:16:51 -07001967 mAttachInfo.mTreeObserver.hasComputeInternalInsetsListeners()
1968 || mAttachInfo.mHasNonEmptyGivenInternalInsets;
Romain Guy812ccbe2010-06-01 14:07:24 -07001969
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001970 boolean insetsPending = false;
1971 int relayoutResult = 0;
Chet Haased86fb2c2016-05-04 07:26:02 -07001972 boolean updatedConfiguration = false;
Romain Guy812ccbe2010-06-01 14:07:24 -07001973
Robert Carrb2594852016-04-25 16:21:13 -07001974 final int surfaceGenerationId = mSurface.getGenerationId();
1975
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08001976 final boolean isViewVisible = viewVisibility == View.VISIBLE;
Andrii Kulianb2e37802017-01-11 00:36:44 -08001977 final boolean windowRelayoutWasForced = mForceNextWindowRelayout;
Bryce Lee46b01652017-06-07 23:01:56 +00001978 if (mFirst || windowShouldResize || insetsChanged ||
1979 viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
Jorim Jaggia4a58ef2016-01-27 02:10:08 -08001980 mForceNextWindowRelayout = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001981
Alan Viverette64bf97a2015-09-18 16:42:00 -04001982 if (isViewVisible) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001983 // If this window is giving internal insets to the window
1984 // manager, and it is being added or changing its visibility,
1985 // then we want to first give the window manager "fake"
1986 // insets to cause it to effectively ignore the content of
1987 // the window during layout. This avoids it briefly causing
1988 // other windows to resize/move based on the raw frame of the
1989 // window, waiting until we can finish laying out this window
1990 // and get back to the window manager with the ultimately
1991 // computed insets.
Romain Guy812ccbe2010-06-01 14:07:24 -07001992 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001993 }
1994
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001995 if (mSurfaceHolder != null) {
1996 mSurfaceHolder.mSurfaceLock.lock();
1997 mDrawingAllowed = true;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001998 }
Romain Guy812ccbe2010-06-01 14:07:24 -07001999
Romain Guyc361da82010-10-25 15:29:10 -07002000 boolean hwInitialized = false;
Chong Zhang75eccbd2016-07-12 19:25:08 -07002001 boolean contentInsetsChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002002 boolean hadSurface = mSurface.isValid();
Romain Guy812ccbe2010-06-01 14:07:24 -07002003
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002004 try {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07002005 if (DEBUG_LAYOUT) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002006 Log.i(mTag, "host=w:" + host.getMeasuredWidth() + ", h:" +
Dianne Hackborn189ee182010-12-02 21:48:53 -08002007 host.getMeasuredHeight() + ", params=" + params);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07002008 }
Romain Guy2a83f002011-01-18 18:28:21 -08002009
Stan Iliev45faba52016-06-28 13:33:15 -04002010 if (mAttachInfo.mThreadedRenderer != null) {
John Reckf7d9c1d2014-04-09 10:01:03 -07002011 // relayoutWindow may decide to destroy mSurface. As that decision
2012 // happens in WindowManager service, we need to be defensive here
2013 // and stop using the surface in case it gets destroyed.
Stan Iliev45faba52016-06-28 13:33:15 -04002014 if (mAttachInfo.mThreadedRenderer.pauseSurface(mSurface)) {
John Reck01a5ea32014-12-03 13:01:07 -08002015 // Animations were running so we need to push a frame
2016 // to resume them
2017 mDirty.set(0, 0, mWidth, mHeight);
2018 }
John Reckba6adf62015-02-19 14:36:50 -08002019 mChoreographer.mFrameInfo.addFlags(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED);
John Reckf7d9c1d2014-04-09 10:01:03 -07002020 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07002021 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
2022
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002023 if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
Dianne Hackbornc4aad012013-02-22 15:05:25 -08002024 + " overscan=" + mPendingOverscanInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002025 + " content=" + mPendingContentInsets.toShortString()
2026 + " visible=" + mPendingVisibleInsets.toShortString()
Adrian Roos5c6b6222017-11-07 17:36:10 +01002027 + " stable=" + mPendingStableInsets.toShortString()
2028 + " cutout=" + mPendingDisplayCutout.get().toString()
Filip Gruszczynski0ec13282015-06-25 11:26:01 -07002029 + " outsets=" + mPendingOutsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002030 + " surface=" + mSurface);
Romain Guy8506ab42009-06-11 17:35:47 -07002031
Bryce Leef858b572017-06-29 14:03:33 -07002032 // If the pending {@link MergedConfiguration} handed back from
2033 // {@link #relayoutWindow} does not match the one last reported,
2034 // WindowManagerService has reported back a frame from a configuration not yet
2035 // handled by the client. In this case, we need to accept the configuration so we
2036 // do not lay out and draw with the wrong configuration.
2037 if (!mPendingMergedConfiguration.equals(mLastReportedMergedConfiguration)) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002038 if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: "
Bryce Leef858b572017-06-29 14:03:33 -07002039 + mPendingMergedConfiguration.getMergedConfiguration());
Andrii Kulian44607962017-03-16 11:06:24 -07002040 performConfigurationChange(mPendingMergedConfiguration, !mFirst,
2041 INVALID_DISPLAY /* same display */);
Chet Haased86fb2c2016-05-04 07:26:02 -07002042 updatedConfiguration = true;
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002043 }
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07002044
Dianne Hackbornc4aad012013-02-22 15:05:25 -08002045 final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
2046 mAttachInfo.mOverscanInsets);
Chong Zhang75eccbd2016-07-12 19:25:08 -07002047 contentInsetsChanged = !mPendingContentInsets.equals(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002048 mAttachInfo.mContentInsets);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08002049 final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002050 mAttachInfo.mVisibleInsets);
Adrian Roosfa104232014-06-20 16:10:14 -07002051 final boolean stableInsetsChanged = !mPendingStableInsets.equals(
2052 mAttachInfo.mStableInsets);
Adrian Roos5c6b6222017-11-07 17:36:10 +01002053 final boolean cutoutChanged = !mPendingDisplayCutout.equals(
2054 mAttachInfo.mDisplayCutout);
Filip Gruszczynski2217f612015-05-26 11:32:08 -07002055 final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets);
Chong Zhangf4abc2b2015-11-12 23:40:58 -08002056 final boolean surfaceSizeChanged = (relayoutResult
2057 & WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
Adrian Roosdcf50a4f2018-01-29 18:31:34 +01002058 surfaceChanged |= surfaceSizeChanged;
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08002059 final boolean alwaysConsumeNavBarChanged =
2060 mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002061 if (contentInsetsChanged) {
2062 mAttachInfo.mContentInsets.set(mPendingContentInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002063 if (DEBUG_LAYOUT) Log.v(mTag, "Content insets changing to: "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002064 + mAttachInfo.mContentInsets);
2065 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08002066 if (overscanInsetsChanged) {
2067 mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002068 if (DEBUG_LAYOUT) Log.v(mTag, "Overscan insets changing to: "
Dianne Hackbornc4aad012013-02-22 15:05:25 -08002069 + mAttachInfo.mOverscanInsets);
2070 // Need to relayout with content insets.
2071 contentInsetsChanged = true;
2072 }
Adrian Roosfa104232014-06-20 16:10:14 -07002073 if (stableInsetsChanged) {
2074 mAttachInfo.mStableInsets.set(mPendingStableInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002075 if (DEBUG_LAYOUT) Log.v(mTag, "Decor insets changing to: "
Adrian Roosfa104232014-06-20 16:10:14 -07002076 + mAttachInfo.mStableInsets);
2077 // Need to relayout with content insets.
2078 contentInsetsChanged = true;
2079 }
Adrian Roos5c6b6222017-11-07 17:36:10 +01002080 if (cutoutChanged) {
2081 mAttachInfo.mDisplayCutout.set(mPendingDisplayCutout);
2082 if (DEBUG_LAYOUT) {
2083 Log.v(mTag, "DisplayCutout changing to: " + mAttachInfo.mDisplayCutout);
2084 }
2085 // Need to relayout with content insets.
2086 contentInsetsChanged = true;
2087 }
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08002088 if (alwaysConsumeNavBarChanged) {
2089 mAttachInfo.mAlwaysConsumeNavBar = mPendingAlwaysConsumeNavBar;
2090 contentInsetsChanged = true;
2091 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002092 if (contentInsetsChanged || mLastSystemUiVisibility !=
Adrian Roosfa104232014-06-20 16:10:14 -07002093 mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested
Filip Gruszczynski2217f612015-05-26 11:32:08 -07002094 || mLastOverscanRequested != mAttachInfo.mOverscanRequested
2095 || outsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002096 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08002097 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Filip Gruszczynski2217f612015-05-26 11:32:08 -07002098 mAttachInfo.mOutsets.set(mPendingOutsets);
Adrian Roosfa104232014-06-20 16:10:14 -07002099 mApplyInsetsRequested = false;
Adam Powell2accbf92014-04-16 23:14:57 +00002100 dispatchApplyInsets(host);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002101 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002102 if (visibleInsetsChanged) {
2103 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002104 if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002105 + mAttachInfo.mVisibleInsets);
2106 }
2107
2108 if (!hadSurface) {
2109 if (mSurface.isValid()) {
2110 // If we are creating a new surface, then we need to
2111 // completely redraw it. Also, when we get to the
2112 // point of drawing it we will hold off and schedule
2113 // a new traversal instead. This is so we can tell the
2114 // window manager about all of the windows being displayed
2115 // before actually drawing them, so it can display then
2116 // all at once.
2117 newSurface = true;
Jeff Brown96e942d2011-11-30 19:55:01 -08002118 mFullRedrawNeeded = true;
Jack Palevich61a6e682009-10-09 17:37:50 -07002119 mPreviousTransparentRegion.setEmpty();
Romain Guy8506ab42009-06-11 17:35:47 -07002120
John Reck63005e62015-05-19 15:00:13 -07002121 // Only initialize up-front if transparent regions are not
2122 // requested, otherwise defer to see if the entire window
2123 // will be transparent
Stan Iliev45faba52016-06-28 13:33:15 -04002124 if (mAttachInfo.mThreadedRenderer != null) {
Dianne Hackborn64825172011-03-02 21:32:58 -08002125 try {
Stan Iliev45faba52016-06-28 13:33:15 -04002126 hwInitialized = mAttachInfo.mThreadedRenderer.initialize(
John Reck79d81e62013-11-05 13:26:57 -08002127 mSurface);
John Reck63005e62015-05-19 15:00:13 -07002128 if (hwInitialized && (host.mPrivateFlags
2129 & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
2130 // Don't pre-allocate if transparent regions
2131 // are requested as they may not be needed
Jorim Jaggi7823ee72018-07-17 15:24:16 +02002132 mAttachInfo.mThreadedRenderer.allocateBuffers(mSurface);
John Reck63005e62015-05-19 15:00:13 -07002133 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07002134 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002135 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08002136 return;
2137 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002138 }
2139 }
2140 } else if (!mSurface.isValid()) {
2141 // If the surface has been removed, then reset the scroll
2142 // positions.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002143 if (mLastScrolledFocus != null) {
2144 mLastScrolledFocus.clear();
2145 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002146 mScrollY = mCurScrollY = 0;
Adrian Roos0e7ae4e2014-10-01 15:33:22 +02002147 if (mView instanceof RootViewSurfaceTaker) {
2148 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
2149 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002150 if (mScroller != null) {
2151 mScroller.abortAnimation();
2152 }
Romain Guy1d0c7082011-08-03 16:22:24 -07002153 // Our surface is gone
Stan Iliev45faba52016-06-28 13:33:15 -04002154 if (mAttachInfo.mThreadedRenderer != null &&
2155 mAttachInfo.mThreadedRenderer.isEnabled()) {
2156 mAttachInfo.mThreadedRenderer.destroy();
Romain Guy1d0c7082011-08-03 16:22:24 -07002157 }
Chong Zhangf4abc2b2015-11-12 23:40:58 -08002158 } else if ((surfaceGenerationId != mSurface.getGenerationId()
Andrii Kulianb2e37802017-01-11 00:36:44 -08002159 || surfaceSizeChanged || windowRelayoutWasForced)
Chong Zhangf4abc2b2015-11-12 23:40:58 -08002160 && mSurfaceHolder == null
Stan Iliev45faba52016-06-28 13:33:15 -04002161 && mAttachInfo.mThreadedRenderer != null) {
Jeff Brown96e942d2011-11-30 19:55:01 -08002162 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08002163 try {
Chong Zhangf4abc2b2015-11-12 23:40:58 -08002164 // Need to do updateSurface (which leads to CanvasContext::setSurface and
2165 // re-create the EGLSurface) if either the Surface changed (as indicated by
2166 // generation id), or WindowManager changed the surface size. The latter is
2167 // because on some chips, changing the consumer side's BufferQueue size may
2168 // not take effect immediately unless we create a new EGLSurface.
2169 // Note that frame size change doesn't always imply surface size change (eg.
2170 // drag resizing uses fullscreen surface), need to check surfaceSizeChanged
2171 // flag from WindowManager.
Stan Iliev45faba52016-06-28 13:33:15 -04002172 mAttachInfo.mThreadedRenderer.updateSurface(mSurface);
Igor Murashkina86ab6402013-08-30 12:58:36 -07002173 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002174 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08002175 return;
2176 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002177 }
Chong Zhang0275e392015-09-17 10:41:44 -07002178
Jorim Jaggi4846ee32016-01-07 17:39:12 +01002179 final boolean freeformResizing = (relayoutResult
2180 & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFORM) != 0;
2181 final boolean dockedResizing = (relayoutResult
2182 & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_DOCKED) != 0;
2183 final boolean dragResizing = freeformResizing || dockedResizing;
Chong Zhang0275e392015-09-17 10:41:44 -07002184 if (mDragResizing != dragResizing) {
Skuhneb8160872015-09-22 09:51:39 -07002185 if (dragResizing) {
Jorim Jaggi4846ee32016-01-07 17:39:12 +01002186 mResizeMode = freeformResizing
2187 ? RESIZE_MODE_FREEFORM
2188 : RESIZE_MODE_DOCKED_DIVIDER;
Adrian Roos5c6b6222017-11-07 17:36:10 +01002189 // TODO: Need cutout?
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002190 startDragResizing(mPendingBackDropFrame,
2191 mWinFrame.equals(mPendingBackDropFrame), mPendingVisibleInsets,
2192 mPendingStableInsets, mResizeMode);
Skuhneb8160872015-09-22 09:51:39 -07002193 } else {
2194 // We shouldn't come here, but if we come we should end the resize.
2195 endDragResizing();
2196 }
Chong Zhang0275e392015-09-17 10:41:44 -07002197 }
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09002198 if (!mUseMTRenderer) {
Skuhneb8160872015-09-22 09:51:39 -07002199 if (dragResizing) {
2200 mCanvasOffsetX = mWinFrame.left;
2201 mCanvasOffsetY = mWinFrame.top;
2202 } else {
2203 mCanvasOffsetX = mCanvasOffsetY = 0;
2204 }
Chong Zhang0275e392015-09-17 10:41:44 -07002205 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002206 } catch (RemoteException e) {
2207 }
Romain Guy1d0c7082011-08-03 16:22:24 -07002208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002209 if (DEBUG_ORIENTATION) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07002210 TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002211
Chris Craikd36a81f2014-07-17 10:16:51 -07002212 mAttachInfo.mWindowLeft = frame.left;
2213 mAttachInfo.mWindowTop = frame.top;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002214
2215 // !!FIXME!! This next section handles the case where we did not get the
2216 // window size we asked for. We should avoid this by getting a maximum size from
2217 // the window session beforehand.
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07002218 if (mWidth != frame.width() || mHeight != frame.height()) {
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07002219 mWidth = frame.width();
2220 mHeight = frame.height();
2221 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002222
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002223 if (mSurfaceHolder != null) {
2224 // The app owns the surface; tell it about what is going on.
2225 if (mSurface.isValid()) {
2226 // XXX .copyFrom() doesn't work!
2227 //mSurfaceHolder.mSurface.copyFrom(mSurface);
2228 mSurfaceHolder.mSurface = mSurface;
2229 }
Jeff Brown30bc34f2011-01-25 12:56:56 -08002230 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002231 mSurfaceHolder.mSurfaceLock.unlock();
2232 if (mSurface.isValid()) {
John Reck208c47c2016-06-09 16:26:21 -07002233 if (!hadSurface) {
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002234 mSurfaceHolder.ungetCallbacks();
2235
2236 mIsCreating = true;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002237 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
2238 if (callbacks != null) {
2239 for (SurfaceHolder.Callback c : callbacks) {
2240 c.surfaceCreated(mSurfaceHolder);
2241 }
2242 }
2243 surfaceChanged = true;
2244 }
John Reck208c47c2016-06-09 16:26:21 -07002245 if (surfaceChanged || surfaceGenerationId != mSurface.getGenerationId()) {
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002246 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
2247 if (callbacks != null) {
2248 for (SurfaceHolder.Callback c : callbacks) {
2249 c.surfaceChanged(mSurfaceHolder, lp.format,
2250 mWidth, mHeight);
2251 }
2252 }
2253 }
2254 mIsCreating = false;
2255 } else if (hadSurface) {
Vishnu Nair47d2d1e2019-01-24 13:01:24 -08002256 notifySurfaceDestroyed();
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002257 mSurfaceHolder.mSurfaceLock.lock();
Jozef BABJAK93c5b6a2011-02-22 09:33:19 +01002258 try {
2259 mSurfaceHolder.mSurface = new Surface();
2260 } finally {
2261 mSurfaceHolder.mSurfaceLock.unlock();
2262 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002263 }
2264 }
Romain Guy53389bd2010-09-07 17:16:32 -07002265
Stan Iliev45faba52016-06-28 13:33:15 -04002266 final ThreadedRenderer threadedRenderer = mAttachInfo.mThreadedRenderer;
2267 if (threadedRenderer != null && threadedRenderer.isEnabled()) {
Alan Viverette50210d92015-05-14 18:05:36 -07002268 if (hwInitialized
Stan Iliev45faba52016-06-28 13:33:15 -04002269 || mWidth != threadedRenderer.getWidth()
2270 || mHeight != threadedRenderer.getHeight()
2271 || mNeedsRendererSetup) {
2272 threadedRenderer.setup(mWidth, mHeight, mAttachInfo,
Alan Viverette50210d92015-05-14 18:05:36 -07002273 mWindowAttributes.surfaceInsets);
Stan Iliev45faba52016-06-28 13:33:15 -04002274 mNeedsRendererSetup = false;
Romain Guy03985752011-07-11 15:33:51 -07002275 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002276 }
2277
Craig Mautner72d6f212015-02-19 16:33:09 -08002278 if (!mStopped || mReportNextDraw) {
Dianne Hackbornce418e62011-03-01 14:31:38 -08002279 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
Jeff Brown98365d72012-08-19 20:30:52 -07002280 (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
Dianne Hackbornce418e62011-03-01 14:31:38 -08002281 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
Chong Zhang75eccbd2016-07-12 19:25:08 -07002282 || mHeight != host.getMeasuredHeight() || contentInsetsChanged ||
Chet Haased86fb2c2016-05-04 07:26:02 -07002283 updatedConfiguration) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002284 int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
2285 int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
Igor Murashkina86ab6402013-08-30 12:58:36 -07002286
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002287 if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed! mWidth="
Dianne Hackbornce418e62011-03-01 14:31:38 -08002288 + mWidth + " measuredWidth=" + host.getMeasuredWidth()
2289 + " mHeight=" + mHeight
2290 + " measuredHeight=" + host.getMeasuredHeight()
Chong Zhang75eccbd2016-07-12 19:25:08 -07002291 + " coveredInsetsChanged=" + contentInsetsChanged);
Igor Murashkina86ab6402013-08-30 12:58:36 -07002292
Dianne Hackbornce418e62011-03-01 14:31:38 -08002293 // Ask host how big it wants to be
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002294 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Igor Murashkina86ab6402013-08-30 12:58:36 -07002295
Dianne Hackbornce418e62011-03-01 14:31:38 -08002296 // Implementation of weights from WindowManager.LayoutParams
2297 // We just grow the dimensions as needed and re-measure if
2298 // needs be
2299 int width = host.getMeasuredWidth();
2300 int height = host.getMeasuredHeight();
2301 boolean measureAgain = false;
Igor Murashkina86ab6402013-08-30 12:58:36 -07002302
Dianne Hackbornce418e62011-03-01 14:31:38 -08002303 if (lp.horizontalWeight > 0.0f) {
2304 width += (int) ((mWidth - width) * lp.horizontalWeight);
2305 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
2306 MeasureSpec.EXACTLY);
2307 measureAgain = true;
2308 }
2309 if (lp.verticalWeight > 0.0f) {
2310 height += (int) ((mHeight - height) * lp.verticalWeight);
2311 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
2312 MeasureSpec.EXACTLY);
2313 measureAgain = true;
2314 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07002315
Dianne Hackbornce418e62011-03-01 14:31:38 -08002316 if (measureAgain) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002317 if (DEBUG_LAYOUT) Log.v(mTag,
Dianne Hackbornce418e62011-03-01 14:31:38 -08002318 "And hey let's measure once more: width=" + width
2319 + " height=" + height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002320 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackbornce418e62011-03-01 14:31:38 -08002321 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07002322
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002323 layoutRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002324 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002325 }
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07002326 } else {
2327 // Not the first pass and no window/insets/visibility change but the window
2328 // may have moved and we need check that and if so to update the left and right
2329 // in the attach info. We translate only the window frame since on window move
2330 // the window manager tells us only for the new frame but the insets are the
2331 // same and we do not want to translate them more than once.
Jorim Jaggi2e95a482016-01-14 17:36:55 -08002332 maybeHandleWindowMove(frame);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002333 }
2334
Craig Mautner72d6f212015-02-19 16:33:09 -08002335 final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002336 boolean triggerGlobalLayoutListener = didLayout
Chris Craikd36a81f2014-07-17 10:16:51 -07002337 || mAttachInfo.mRecomputeGlobalAttributes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002338 if (didLayout) {
Jorim Jaggi26d02d22016-02-24 18:37:51 -05002339 performLayout(lp, mWidth, mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002340
Mathias Agopian54e3d3842013-04-12 15:13:12 -07002341 // By this point all views have been sized and positioned
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002342 // We can compute the transparent area
2343
Dianne Hackborn4702a852012-08-17 15:18:29 -07002344 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002345 // start out transparent
2346 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
2347 host.getLocationInWindow(mTmpLocation);
2348 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
2349 mTmpLocation[0] + host.mRight - host.mLeft,
2350 mTmpLocation[1] + host.mBottom - host.mTop);
2351
2352 host.gatherTransparentRegion(mTransparentRegion);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07002353 if (mTranslator != null) {
2354 mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
2355 }
2356
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002357 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
2358 mPreviousTransparentRegion.set(mTransparentRegion);
Mathias Agopian54e3d3842013-04-12 15:13:12 -07002359 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002360 // reconfigure window manager
2361 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002362 mWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002363 } catch (RemoteException e) {
2364 }
2365 }
2366 }
2367
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002368 if (DBG) {
2369 System.out.println("======================================");
Chet Haase4610eef2015-12-03 07:38:11 -08002370 System.out.println("performTraversals -- after setFrame");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002371 host.debug();
2372 }
2373 }
2374
2375 if (triggerGlobalLayoutListener) {
Chris Craikd36a81f2014-07-17 10:16:51 -07002376 mAttachInfo.mRecomputeGlobalAttributes = false;
2377 mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002378 }
2379
2380 if (computesInternalInsets) {
Jeff Brownfbf09772011-01-16 14:06:57 -08002381 // Clear the original insets.
Chris Craikd36a81f2014-07-17 10:16:51 -07002382 final ViewTreeObserver.InternalInsetsInfo insets = mAttachInfo.mGivenInternalInsets;
Jeff Brownfbf09772011-01-16 14:06:57 -08002383 insets.reset();
2384
2385 // Compute new insets in place.
Chris Craikd36a81f2014-07-17 10:16:51 -07002386 mAttachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
2387 mAttachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty();
Jeff Brownfbf09772011-01-16 14:06:57 -08002388
2389 // Tell the window manager.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002390 if (insetsPending || !mLastGivenInsets.equals(insets)) {
2391 mLastGivenInsets.set(insets);
Jeff Brownfbf09772011-01-16 14:06:57 -08002392
2393 // Translate insets to screen coordinates if needed.
2394 final Rect contentInsets;
2395 final Rect visibleInsets;
2396 final Region touchableRegion;
2397 if (mTranslator != null) {
2398 contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
2399 visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
2400 touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
2401 } else {
2402 contentInsets = insets.contentInsets;
2403 visibleInsets = insets.visibleInsets;
2404 touchableRegion = insets.touchableRegion;
2405 }
2406
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002407 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002408 mWindowSession.setInsets(mWindow, insets.mTouchableInsets,
Jeff Brownfbf09772011-01-16 14:06:57 -08002409 contentInsets, visibleInsets, touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002410 } catch (RemoteException e) {
2411 }
2412 }
2413 }
Romain Guy8506ab42009-06-11 17:35:47 -07002414
Evan Roskyadf5bec2017-10-19 10:24:07 -07002415 if (mFirst) {
Evan Roskybdc66cb2017-09-08 14:27:24 -07002416 if (sAlwaysAssignFocus || !isInTouchMode()) {
Evan Roskyadf5bec2017-10-19 10:24:07 -07002417 // handle first focus request
2418 if (DEBUG_INPUT_RESIZE) {
2419 Log.v(mTag, "First: mView.hasFocus()=" + mView.hasFocus());
2420 }
2421 if (mView != null) {
2422 if (!mView.hasFocus()) {
2423 mView.restoreDefaultFocus();
2424 if (DEBUG_INPUT_RESIZE) {
2425 Log.v(mTag, "First: requested focused view=" + mView.findFocus());
2426 }
2427 } else {
2428 if (DEBUG_INPUT_RESIZE) {
2429 Log.v(mTag, "First: existing focused view=" + mView.findFocus());
2430 }
2431 }
2432 }
2433 } else {
2434 // Some views (like ScrollView) won't hand focus to descendants that aren't within
2435 // their viewport. Before layout, there's a good change these views are size 0
2436 // which means no children can get focus. After layout, this view now has size, but
2437 // is not guaranteed to hand-off focus to a focusable child (specifically, the edge-
2438 // case where the child has a size prior to layout and thus won't trigger
2439 // focusableViewAvailable).
2440 View focused = mView.findFocus();
2441 if (focused instanceof ViewGroup
2442 && ((ViewGroup) focused).getDescendantFocusability()
2443 == ViewGroup.FOCUS_AFTER_DESCENDANTS) {
2444 focused.restoreDefaultFocus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002445 }
2446 }
2447 }
2448
Alan Viverette64bf97a2015-09-18 16:42:00 -04002449 final boolean changedVisibility = (viewVisibilityChanged || mFirst) && isViewVisible;
2450 final boolean hasWindowFocus = mAttachInfo.mHasWindowFocus && isViewVisible;
2451 final boolean regainedFocus = hasWindowFocus && mLostWindowFocus;
2452 if (regainedFocus) {
2453 mLostWindowFocus = false;
2454 } else if (!hasWindowFocus && mHadWindowFocus) {
2455 mLostWindowFocus = true;
2456 }
2457
2458 if (changedVisibility || regainedFocus) {
Phil Weaver532c7992016-08-29 15:59:03 -07002459 // Toasts are presented as notifications - don't present them as windows as well
2460 boolean isToast = (mWindowAttributes == null) ? false
2461 : (mWindowAttributes.type == WindowManager.LayoutParams.TYPE_TOAST);
2462 if (!isToast) {
2463 host.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
2464 }
Alan Viverette64bf97a2015-09-18 16:42:00 -04002465 }
2466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002467 mFirst = false;
2468 mWillDrawSoon = false;
2469 mNewSurfaceNeeded = false;
Jorim Jaggi4846ee32016-01-07 17:39:12 +01002470 mActivityRelaunched = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002471 mViewVisibility = viewVisibility;
Alan Viverette64bf97a2015-09-18 16:42:00 -04002472 mHadWindowFocus = hasWindowFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002473
Alan Viverette64bf97a2015-09-18 16:42:00 -04002474 if (hasWindowFocus && !isInLocalFocusMode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002475 final boolean imTarget = WindowManager.LayoutParams
2476 .mayUseInputMethod(mWindowAttributes.flags);
2477 if (imTarget != mLastWasImTarget) {
2478 mLastWasImTarget = imTarget;
2479 InputMethodManager imm = InputMethodManager.peekInstance();
2480 if (imm != null && imTarget) {
Alan Viverette64bf97a2015-09-18 16:42:00 -04002481 imm.onPreWindowFocus(mView, hasWindowFocus);
Yohei Yukawa5f059652015-05-14 22:16:41 -07002482 imm.onPostWindowFocus(mView, mView.findFocus(),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002483 mWindowAttributes.softInputMode,
2484 !mHasHadWindowFocus, mWindowAttributes.flags);
2485 }
2486 }
2487 }
Romain Guy8506ab42009-06-11 17:35:47 -07002488
Jeff Brown96e942d2011-11-30 19:55:01 -08002489 // Remember if we must report the next draw.
Jeff Brown98365d72012-08-19 20:30:52 -07002490 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
Robert Carr49cd9f82017-05-25 18:24:42 -07002491 reportNextDraw();
Jeff Brown96e942d2011-11-30 19:55:01 -08002492 }
2493
Alan Viverette64bf97a2015-09-18 16:42:00 -04002494 boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002495
Jorim Jaggi75c21ca2016-03-28 19:26:09 -04002496 if (!cancelDraw && !newSurface) {
Chet Haase9c450412015-10-01 13:25:58 -07002497 if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
2498 for (int i = 0; i < mPendingTransitions.size(); ++i) {
2499 mPendingTransitions.get(i).startChangingAnimations();
Chet Haased56c6952011-09-07 08:46:23 -07002500 }
Chet Haase9c450412015-10-01 13:25:58 -07002501 mPendingTransitions.clear();
Chet Haased56c6952011-09-07 08:46:23 -07002502 }
Chet Haase9c450412015-10-01 13:25:58 -07002503
2504 performDraw();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002505 } else {
Alan Viverette64bf97a2015-09-18 16:42:00 -04002506 if (isViewVisible) {
Chris Wren78cb7cf2012-05-15 12:36:44 -04002507 // Try again
2508 scheduleTraversals();
2509 } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
Chet Haased56c6952011-09-07 08:46:23 -07002510 for (int i = 0; i < mPendingTransitions.size(); ++i) {
2511 mPendingTransitions.get(i).endChangingAnimations();
2512 }
2513 mPendingTransitions.clear();
2514 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002515 }
Craig Mautnerdf2390a2012-08-29 20:59:22 -07002516
2517 mIsInTraversal = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002518 }
2519
Vishnu Nair47d2d1e2019-01-24 13:01:24 -08002520 private void notifySurfaceDestroyed() {
2521 mSurfaceHolder.ungetCallbacks();
2522 SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks();
2523 if (callbacks != null) {
2524 for (SurfaceHolder.Callback c : callbacks) {
2525 c.surfaceDestroyed(mSurfaceHolder);
2526 }
2527 }
2528 }
2529
Jorim Jaggi2e95a482016-01-14 17:36:55 -08002530 private void maybeHandleWindowMove(Rect frame) {
2531
2532 // TODO: Well, we are checking whether the frame has changed similarly
2533 // to how this is done for the insets. This is however incorrect since
2534 // the insets and the frame are translated. For example, the old frame
2535 // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new
2536 // reported frame is (2, 2 - 2, 2) which implies no change but this is not
2537 // true since we are comparing a not translated value to a translated one.
2538 // This scenario is rare but we may want to fix that.
2539
2540 final boolean windowMoved = mAttachInfo.mWindowLeft != frame.left
2541 || mAttachInfo.mWindowTop != frame.top;
2542 if (windowMoved) {
2543 if (mTranslator != null) {
2544 mTranslator.translateRectInScreenToAppWinFrame(frame);
2545 }
2546 mAttachInfo.mWindowLeft = frame.left;
2547 mAttachInfo.mWindowTop = frame.top;
Teng-Hui Zhu27571282016-05-12 15:53:53 -07002548 }
2549 if (windowMoved || mAttachInfo.mNeedsUpdateLightCenter) {
2550 // Update the light position for the new offsets.
Stan Iliev45faba52016-06-28 13:33:15 -04002551 if (mAttachInfo.mThreadedRenderer != null) {
2552 mAttachInfo.mThreadedRenderer.setLightCenter(mAttachInfo);
Jorim Jaggi2e95a482016-01-14 17:36:55 -08002553 }
Teng-Hui Zhu27571282016-05-12 15:53:53 -07002554 mAttachInfo.mNeedsUpdateLightCenter = false;
Jorim Jaggi2e95a482016-01-14 17:36:55 -08002555 }
2556 }
Teng-Hui Zhu27571282016-05-12 15:53:53 -07002557
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08002558 private void handleWindowFocusChanged() {
2559 final boolean hasWindowFocus;
2560 final boolean inTouchMode;
2561 synchronized (this) {
Dianne Hackborn011944c2017-12-15 15:44:55 -08002562 if (!mWindowFocusChanged) {
2563 return;
2564 }
2565 mWindowFocusChanged = false;
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08002566 hasWindowFocus = mUpcomingWindowFocus;
2567 inTouchMode = mUpcomingInTouchMode;
2568 }
2569
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08002570 if (mAdded) {
2571 profileRendering(hasWindowFocus);
2572
2573 if (hasWindowFocus) {
2574 ensureTouchModeLocally(inTouchMode);
2575 if (mAttachInfo.mThreadedRenderer != null && mSurface.isValid()) {
2576 mFullRedrawNeeded = true;
2577 try {
2578 final WindowManager.LayoutParams lp = mWindowAttributes;
2579 final Rect surfaceInsets = lp != null ? lp.surfaceInsets : null;
2580 mAttachInfo.mThreadedRenderer.initializeIfNeeded(
2581 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
2582 } catch (OutOfResourcesException e) {
2583 Log.e(mTag, "OutOfResourcesException locking surface", e);
2584 try {
2585 if (!mWindowSession.outOfMemory(mWindow)) {
2586 Slog.w(mTag, "No processes killed for memory;"
2587 + " killing self");
2588 Process.killProcess(Process.myPid());
2589 }
2590 } catch (RemoteException ex) {
2591 }
2592 // Retry in a bit.
2593 mHandler.sendMessageDelayed(mHandler.obtainMessage(
2594 MSG_WINDOW_FOCUS_CHANGED), 500);
2595 return;
2596 }
2597 }
2598 }
2599
2600 mAttachInfo.mHasWindowFocus = hasWindowFocus;
2601
2602 mLastWasImTarget = WindowManager.LayoutParams
2603 .mayUseInputMethod(mWindowAttributes.flags);
2604
2605 InputMethodManager imm = InputMethodManager.peekInstance();
2606 if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
2607 imm.onPreWindowFocus(mView, hasWindowFocus);
2608 }
2609 if (mView != null) {
2610 mAttachInfo.mKeyDispatchState.reset();
2611 mView.dispatchWindowFocusChanged(hasWindowFocus);
2612 mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
2613
2614 if (mAttachInfo.mTooltipHost != null) {
2615 mAttachInfo.mTooltipHost.hideTooltip();
2616 }
2617 }
2618
2619 // Note: must be done after the focus change callbacks,
2620 // so all of the view state is set up correctly.
2621 if (hasWindowFocus) {
2622 if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
2623 imm.onPostWindowFocus(mView, mView.findFocus(),
2624 mWindowAttributes.softInputMode,
2625 !mHasHadWindowFocus, mWindowAttributes.flags);
2626 }
2627 // Clear the forward bit. We can just do this directly, since
2628 // the window manager doesn't care about it.
2629 mWindowAttributes.softInputMode &=
2630 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
2631 ((WindowManager.LayoutParams) mView.getLayoutParams())
2632 .softInputMode &=
2633 ~WindowManager.LayoutParams
2634 .SOFT_INPUT_IS_FORWARD_NAVIGATION;
2635 mHasHadWindowFocus = true;
Svetoslav Ganov24c90452017-12-27 15:17:14 -08002636
2637 // Refocusing a window that has a focused view should fire a
2638 // focus event for the view since the global focused view changed.
2639 fireAccessibilityFocusEventIfHasFocusedNode();
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08002640 } else {
2641 if (mPointerCapture) {
2642 handlePointerCaptureChanged(false);
2643 }
2644 }
2645 }
2646 mFirstInputStage.onWindowFocusChanged(hasWindowFocus);
2647 }
2648
Svetoslav Ganov24c90452017-12-27 15:17:14 -08002649 private void fireAccessibilityFocusEventIfHasFocusedNode() {
2650 if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
2651 return;
2652 }
2653 final View focusedView = mView.findFocus();
2654 if (focusedView == null) {
2655 return;
2656 }
2657 final AccessibilityNodeProvider provider = focusedView.getAccessibilityNodeProvider();
2658 if (provider == null) {
2659 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
2660 } else {
2661 final AccessibilityNodeInfo focusedNode = findFocusedVirtualNode(provider);
2662 if (focusedNode != null) {
2663 final int virtualId = AccessibilityNodeInfo.getVirtualDescendantId(
2664 focusedNode.getSourceNodeId());
2665 // This is a best effort since clearing and setting the focus via the
2666 // provider APIs could have side effects. We don't have a provider API
2667 // similar to that on View to ask a given event to be fired.
2668 final AccessibilityEvent event = AccessibilityEvent.obtain(
2669 AccessibilityEvent.TYPE_VIEW_FOCUSED);
2670 event.setSource(focusedView, virtualId);
2671 event.setPackageName(focusedNode.getPackageName());
2672 event.setChecked(focusedNode.isChecked());
2673 event.setContentDescription(focusedNode.getContentDescription());
2674 event.setPassword(focusedNode.isPassword());
2675 event.getText().add(focusedNode.getText());
2676 event.setEnabled(focusedNode.isEnabled());
2677 focusedView.getParent().requestSendAccessibilityEvent(focusedView, event);
2678 focusedNode.recycle();
2679 }
2680 }
2681 }
2682
2683 private AccessibilityNodeInfo findFocusedVirtualNode(AccessibilityNodeProvider provider) {
2684 AccessibilityNodeInfo focusedNode = provider.findFocus(
2685 AccessibilityNodeInfo.FOCUS_INPUT);
2686 if (focusedNode != null) {
2687 return focusedNode;
2688 }
2689
2690 if (!mContext.isAutofillCompatibilityEnabled()) {
2691 return null;
2692 }
2693
2694 // Unfortunately some provider implementations don't properly
2695 // implement AccessibilityNodeProvider#findFocus
2696 AccessibilityNodeInfo current = provider.createAccessibilityNodeInfo(
2697 AccessibilityNodeProvider.HOST_VIEW_ID);
2698 if (current.isFocused()) {
2699 return current;
2700 }
2701
2702 final Queue<AccessibilityNodeInfo> fringe = new LinkedList<>();
2703 fringe.offer(current);
2704
2705 while (!fringe.isEmpty()) {
2706 current = fringe.poll();
2707 final LongArray childNodeIds = current.getChildNodeIds();
2708 if (childNodeIds== null || childNodeIds.size() <= 0) {
2709 continue;
2710 }
2711 final int childCount = childNodeIds.size();
2712 for (int i = 0; i < childCount; i++) {
2713 final int virtualId = AccessibilityNodeInfo.getVirtualDescendantId(
2714 childNodeIds.get(i));
2715 final AccessibilityNodeInfo child = provider.createAccessibilityNodeInfo(virtualId);
2716 if (child != null) {
2717 if (child.isFocused()) {
2718 return child;
2719 }
2720 fringe.offer(child);
2721 }
2722 }
2723 current.recycle();
2724 }
2725
2726 return null;
2727 }
2728
Romain Guy3696779b2013-01-28 14:04:07 -08002729 private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002730 Log.e(mTag, "OutOfResourcesException initializing HW surface", e);
Romain Guy3696779b2013-01-28 14:04:07 -08002731 try {
2732 if (!mWindowSession.outOfMemory(mWindow) &&
2733 Process.myUid() != Process.SYSTEM_UID) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002734 Slog.w(mTag, "No processes killed for memory; killing self");
Romain Guy3696779b2013-01-28 14:04:07 -08002735 Process.killProcess(Process.myPid());
2736 }
2737 } catch (RemoteException ex) {
2738 }
2739 mLayoutRequested = true; // ask wm for a new surface next time.
2740 }
2741
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002742 private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
Robert Carr001e55a2017-05-15 17:21:38 -07002743 if (mView == null) {
2744 return;
2745 }
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002746 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
2747 try {
2748 mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
2749 } finally {
2750 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2751 }
2752 }
2753
Chet Haase97140572012-09-13 14:56:47 -07002754 /**
2755 * Called by {@link android.view.View#isInLayout()} to determine whether the view hierarchy
2756 * is currently undergoing a layout pass.
2757 *
2758 * @return whether the view hierarchy is currently undergoing a layout pass
2759 */
2760 boolean isInLayout() {
2761 return mInLayout;
2762 }
2763
2764 /**
Chet Haasecc699b42012-12-13 09:06:55 -08002765 * Called by {@link android.view.View#requestLayout()} if the view hierarchy is currently
2766 * undergoing a layout pass. requestLayout() should not generally be called during layout,
2767 * unless the container hierarchy knows what it is doing (i.e., it is fine as long as
2768 * all children in that container hierarchy are measured and laid out at the end of the layout
2769 * pass for that container). If requestLayout() is called anyway, we handle it correctly
2770 * by registering all requesters during a frame as it proceeds. At the end of the frame,
2771 * we check all of those views to see if any still have pending layout requests, which
2772 * indicates that they were not correctly handled by their container hierarchy. If that is
2773 * the case, we clear all such flags in the tree, to remove the buggy flag state that leads
2774 * to blank containers, and force a second request/measure/layout pass in this frame. If
Chet Haase97140572012-09-13 14:56:47 -07002775 * more requestLayout() calls are received during that second layout pass, we post those
Chet Haasecc699b42012-12-13 09:06:55 -08002776 * requests to the next frame to avoid possible infinite loops.
2777 *
2778 * <p>The return value from this method indicates whether the request should proceed
2779 * (if it is a request during the first layout pass) or should be skipped and posted to the
2780 * next frame (if it is a request during the second layout pass).</p>
Chet Haase97140572012-09-13 14:56:47 -07002781 *
2782 * @param view the view that requested the layout.
Chet Haasecc699b42012-12-13 09:06:55 -08002783 *
2784 * @return true if request should proceed, false otherwise.
Chet Haase97140572012-09-13 14:56:47 -07002785 */
Chet Haasecc699b42012-12-13 09:06:55 -08002786 boolean requestLayoutDuringLayout(final View view) {
2787 if (view.mParent == null || view.mAttachInfo == null) {
2788 // Would not normally trigger another layout, so just let it pass through as usual
2789 return true;
2790 }
Chet Haase107a4822013-03-13 06:46:50 -07002791 if (!mLayoutRequesters.contains(view)) {
2792 mLayoutRequesters.add(view);
2793 }
Chet Haase97140572012-09-13 14:56:47 -07002794 if (!mHandlingLayoutInLayoutRequest) {
Chet Haase107a4822013-03-13 06:46:50 -07002795 // Let the request proceed normally; it will be processed in a second layout pass
2796 // if necessary
Chet Haasecc699b42012-12-13 09:06:55 -08002797 return true;
Chet Haase97140572012-09-13 14:56:47 -07002798 } else {
Chet Haase107a4822013-03-13 06:46:50 -07002799 // Don't let the request proceed during the second layout pass.
2800 // It will post to the next frame instead.
Chet Haasecc699b42012-12-13 09:06:55 -08002801 return false;
Chet Haase97140572012-09-13 14:56:47 -07002802 }
2803 }
2804
Chet Haase3efa7b52012-12-03 08:33:17 -08002805 private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
2806 int desiredWindowHeight) {
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002807 mLayoutRequested = false;
2808 mScrollMayChange = true;
Chet Haase97140572012-09-13 14:56:47 -07002809 mInLayout = true;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002810
2811 final View host = mView;
Robert Carr32f37ab2017-06-15 12:39:34 -07002812 if (host == null) {
2813 return;
2814 }
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002815 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002816 Log.v(mTag, "Laying out " + host + " to (" +
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002817 host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
2818 }
2819
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002820 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
2821 try {
2822 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haasecc699b42012-12-13 09:06:55 -08002823
Chet Haased5a83522012-11-21 16:24:44 -08002824 mInLayout = false;
Chet Haase97140572012-09-13 14:56:47 -07002825 int numViewsRequestingLayout = mLayoutRequesters.size();
2826 if (numViewsRequestingLayout > 0) {
Chet Haasecc699b42012-12-13 09:06:55 -08002827 // requestLayout() was called during layout.
2828 // If no layout-request flags are set on the requesting views, there is no problem.
2829 // If some requests are still pending, then we need to clear those flags and do
2830 // a full request/measure/layout pass to handle this situation.
Chet Haase107a4822013-03-13 06:46:50 -07002831 ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
2832 false);
2833 if (validLayoutRequesters != null) {
2834 // Set this flag to indicate that any further requests are happening during
2835 // the second pass, which may result in posting those requests to the next
2836 // frame instead
Chet Haasecc699b42012-12-13 09:06:55 -08002837 mHandlingLayoutInLayoutRequest = true;
Chet Haase107a4822013-03-13 06:46:50 -07002838
2839 // Process fresh layout requests, then measure and layout
2840 int numValidRequests = validLayoutRequesters.size();
Chet Haasecc699b42012-12-13 09:06:55 -08002841 for (int i = 0; i < numValidRequests; ++i) {
Chet Haase107a4822013-03-13 06:46:50 -07002842 final View view = validLayoutRequesters.get(i);
2843 Log.w("View", "requestLayout() improperly called by " + view +
2844 " during layout: running second layout pass");
2845 view.requestLayout();
Chet Haasecc699b42012-12-13 09:06:55 -08002846 }
2847 measureHierarchy(host, lp, mView.getContext().getResources(),
2848 desiredWindowWidth, desiredWindowHeight);
2849 mInLayout = true;
2850 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haase107a4822013-03-13 06:46:50 -07002851
Chet Haasecc699b42012-12-13 09:06:55 -08002852 mHandlingLayoutInLayoutRequest = false;
Chet Haase107a4822013-03-13 06:46:50 -07002853
2854 // Check the valid requests again, this time without checking/clearing the
2855 // layout flags, since requests happening during the second pass get noop'd
2856 validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);
2857 if (validLayoutRequesters != null) {
2858 final ArrayList<View> finalRequesters = validLayoutRequesters;
2859 // Post second-pass requests to the next frame
2860 getRunQueue().post(new Runnable() {
2861 @Override
2862 public void run() {
2863 int numValidRequests = finalRequesters.size();
2864 for (int i = 0; i < numValidRequests; ++i) {
2865 final View view = finalRequesters.get(i);
2866 Log.w("View", "requestLayout() improperly called by " + view +
2867 " during second layout pass: posting in next frame");
2868 view.requestLayout();
2869 }
2870 }
2871 });
2872 }
Chet Haasecc699b42012-12-13 09:06:55 -08002873 }
Chet Haase107a4822013-03-13 06:46:50 -07002874
Chet Haase97140572012-09-13 14:56:47 -07002875 }
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002876 } finally {
2877 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2878 }
Chet Haase97140572012-09-13 14:56:47 -07002879 mInLayout = false;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002880 }
2881
Chet Haase107a4822013-03-13 06:46:50 -07002882 /**
2883 * This method is called during layout when there have been calls to requestLayout() during
2884 * layout. It walks through the list of views that requested layout to determine which ones
2885 * still need it, based on visibility in the hierarchy and whether they have already been
2886 * handled (as is usually the case with ListView children).
2887 *
2888 * @param layoutRequesters The list of views that requested layout during layout
2889 * @param secondLayoutRequests Whether the requests were issued during the second layout pass.
2890 * If so, the FORCE_LAYOUT flag was not set on requesters.
2891 * @return A list of the actual views that still need to be laid out.
2892 */
2893 private ArrayList<View> getValidLayoutRequesters(ArrayList<View> layoutRequesters,
2894 boolean secondLayoutRequests) {
2895
2896 int numViewsRequestingLayout = layoutRequesters.size();
2897 ArrayList<View> validLayoutRequesters = null;
2898 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2899 View view = layoutRequesters.get(i);
2900 if (view != null && view.mAttachInfo != null && view.mParent != null &&
2901 (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) ==
2902 View.PFLAG_FORCE_LAYOUT)) {
2903 boolean gone = false;
2904 View parent = view;
2905 // Only trigger new requests for views in a non-GONE hierarchy
2906 while (parent != null) {
2907 if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) {
2908 gone = true;
2909 break;
2910 }
2911 if (parent.mParent instanceof View) {
2912 parent = (View) parent.mParent;
2913 } else {
2914 parent = null;
2915 }
2916 }
2917 if (!gone) {
2918 if (validLayoutRequesters == null) {
2919 validLayoutRequesters = new ArrayList<View>();
2920 }
2921 validLayoutRequesters.add(view);
2922 }
2923 }
2924 }
2925 if (!secondLayoutRequests) {
2926 // If we're checking the layout flags, then we need to clean them up also
2927 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2928 View view = layoutRequesters.get(i);
2929 while (view != null &&
2930 (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
2931 view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
2932 if (view.mParent instanceof View) {
2933 view = (View) view.mParent;
2934 } else {
2935 view = null;
2936 }
2937 }
2938 }
2939 }
2940 layoutRequesters.clear();
2941 return validLayoutRequesters;
2942 }
2943
Igor Murashkina86ab6402013-08-30 12:58:36 -07002944 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002945 public void requestTransparentRegion(View child) {
2946 // the test below should not fail unless someone is messing with us
2947 checkThread();
2948 if (mView == child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002949 mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002950 // Need to make sure we re-evaluate the window attributes next
2951 // time around, to ensure the window has the correct format.
2952 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -07002953 mWindowAttributesChangesFlag = 0;
Mathias Agopian1bd80ad2010-11-04 17:13:39 -07002954 requestLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002955 }
2956 }
2957
2958 /**
2959 * Figures out the measure spec for the root view in a window based on it's
2960 * layout params.
2961 *
2962 * @param windowSize
2963 * The available width or height of the window
2964 *
2965 * @param rootDimension
2966 * The layout params for one dimension (width or height) of the
2967 * window.
2968 *
2969 * @return The measure spec to use to measure the root view.
2970 */
Romain Guya998dff2012-03-23 18:58:36 -07002971 private static int getRootMeasureSpec(int windowSize, int rootDimension) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002972 int measureSpec;
2973 switch (rootDimension) {
2974
Romain Guy980a9382010-01-08 15:06:28 -08002975 case ViewGroup.LayoutParams.MATCH_PARENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002976 // Window can't resize. Force root view to be windowSize.
2977 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
2978 break;
2979 case ViewGroup.LayoutParams.WRAP_CONTENT:
2980 // Window can resize. Set max size for root view.
2981 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
2982 break;
2983 default:
2984 // Window wants to be an exact size. Force root view to be that size.
2985 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
2986 break;
2987 }
2988 return measureSpec;
2989 }
2990
Alan Viveretteccb11e12014-07-08 16:04:02 -07002991 int mHardwareXOffset;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002992 int mHardwareYOffset;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002993
Igor Murashkina86ab6402013-08-30 12:58:36 -07002994 @Override
Stan Iliev45faba52016-06-28 13:33:15 -04002995 public void onPreDraw(DisplayListCanvas canvas) {
John Reck3e04f092017-06-02 15:50:09 -07002996 // If mCurScrollY is not 0 then this influences the hardwareYOffset. The end result is we
2997 // can apply offsets that are not handled by anything else, resulting in underdraw as
2998 // the View is shifted (thus shifting the window background) exposing unpainted
2999 // content. To handle this with minimal glitches we just clear to BLACK if the window
3000 // is opaque. If it's not opaque then HWUI already internally does a glClear to
3001 // transparent, so there's no risk of underdraw on non-opaque surfaces.
3002 if (mCurScrollY != 0 && mHardwareYOffset != 0 && mAttachInfo.mThreadedRenderer.isOpaque()) {
3003 canvas.drawColor(Color.BLACK);
3004 }
Alan Viveretteccb11e12014-07-08 16:04:02 -07003005 canvas.translate(-mHardwareXOffset, -mHardwareYOffset);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08003006 }
3007
Igor Murashkina86ab6402013-08-30 12:58:36 -07003008 @Override
Stan Iliev45faba52016-06-28 13:33:15 -04003009 public void onPostDraw(DisplayListCanvas canvas) {
Alan Viverette632af842014-10-28 13:45:11 -07003010 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09003011 if (mUseMTRenderer) {
3012 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
3013 mWindowCallbacks.get(i).onPostDraw(canvas);
3014 }
Jorim Jaggic39c7b02016-03-24 10:47:07 -07003015 }
Dianne Hackborn0f761d62010-11-30 22:06:10 -08003016 }
3017
Chet Haaseed30fd82011-04-22 16:18:45 -07003018 /**
3019 * @hide
3020 */
3021 void outputDisplayList(View view) {
Chris Craik356b5fe2015-07-07 10:39:36 -07003022 view.mRenderNode.output();
Stan Iliev45faba52016-06-28 13:33:15 -04003023 if (mAttachInfo.mThreadedRenderer != null) {
John Reck3e04f092017-06-02 15:50:09 -07003024 mAttachInfo.mThreadedRenderer.serializeDisplayListTree();
John Recke248bd12015-08-05 13:53:53 -07003025 }
Romain Guy59a12ca2011-06-09 17:48:21 -07003026 }
3027
3028 /**
3029 * @see #PROPERTY_PROFILE_RENDERING
3030 */
3031 private void profileRendering(boolean enabled) {
3032 if (mProfileRendering) {
3033 mRenderProfilingEnabled = enabled;
Chris Craikae4f32042013-02-07 12:57:10 -08003034
3035 if (mRenderProfiler != null) {
3036 mChoreographer.removeFrameCallback(mRenderProfiler);
3037 }
3038 if (mRenderProfilingEnabled) {
3039 if (mRenderProfiler == null) {
3040 mRenderProfiler = new Choreographer.FrameCallback() {
3041 @Override
3042 public void doFrame(long frameTimeNanos) {
3043 mDirty.set(0, 0, mWidth, mHeight);
3044 scheduleTraversals();
3045 if (mRenderProfilingEnabled) {
3046 mChoreographer.postFrameCallback(mRenderProfiler);
3047 }
Romain Guy59a12ca2011-06-09 17:48:21 -07003048 }
Chris Craikae4f32042013-02-07 12:57:10 -08003049 };
3050 }
Romain Guy5bb3c732012-11-29 17:52:58 -08003051 mChoreographer.postFrameCallback(mRenderProfiler);
Romain Guy59a12ca2011-06-09 17:48:21 -07003052 } else {
Romain Guy59a12ca2011-06-09 17:48:21 -07003053 mRenderProfiler = null;
Chet Haaseed30fd82011-04-22 16:18:45 -07003054 }
3055 }
3056 }
3057
Chet Haase2f2022a2011-10-11 06:41:59 -07003058 /**
3059 * Called from draw() when DEBUG_FPS is enabled
3060 */
3061 private void trackFPS() {
3062 // Tracks frames per second drawn. First value in a series of draws may be bogus
3063 // because it down not account for the intervening idle time
3064 long nowTime = System.currentTimeMillis();
3065 if (mFpsStartTime < 0) {
3066 mFpsStartTime = mFpsPrevTime = nowTime;
3067 mFpsNumFrames = 0;
3068 } else {
3069 ++mFpsNumFrames;
3070 String thisHash = Integer.toHexString(System.identityHashCode(this));
3071 long frameTime = nowTime - mFpsPrevTime;
3072 long totalTime = nowTime - mFpsStartTime;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003073 Log.v(mTag, "0x" + thisHash + "\tFrame time:\t" + frameTime);
Chet Haase2f2022a2011-10-11 06:41:59 -07003074 mFpsPrevTime = nowTime;
3075 if (totalTime > 1000) {
3076 float fps = (float) mFpsNumFrames * 1000 / totalTime;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003077 Log.v(mTag, "0x" + thisHash + "\tFPS:\t" + fps);
Chet Haase2f2022a2011-10-11 06:41:59 -07003078 mFpsStartTime = nowTime;
3079 mFpsNumFrames = 0;
3080 }
3081 }
3082 }
3083
Robert Carr8508bb22017-03-27 15:46:27 -07003084 /**
3085 * A count of the number of calls to pendingDrawFinished we
3086 * require to notify the WM drawing is complete.
Robert Carr8508bb22017-03-27 15:46:27 -07003087 */
Robert Carr49cd9f82017-05-25 18:24:42 -07003088 int mDrawsNeededToReport = 0;
Robert Carr8508bb22017-03-27 15:46:27 -07003089
3090 /**
3091 * Delay notifying WM of draw finished until
3092 * a balanced call to pendingDrawFinished.
3093 */
3094 void drawPending() {
3095 mDrawsNeededToReport++;
3096 }
3097
3098 void pendingDrawFinished() {
3099 if (mDrawsNeededToReport == 0) {
3100 throw new RuntimeException("Unbalanced drawPending/pendingDrawFinished calls");
3101 }
3102 mDrawsNeededToReport--;
3103 if (mDrawsNeededToReport == 0) {
3104 reportDrawFinished();
3105 }
3106 }
3107
3108 private void postDrawFinished() {
3109 mHandler.sendEmptyMessage(MSG_DRAW_FINISHED);
3110 }
3111
3112 private void reportDrawFinished() {
Robert Carrd5c7dd62017-03-08 10:39:30 -08003113 try {
Robert Carr49cd9f82017-05-25 18:24:42 -07003114 mDrawsNeededToReport = 0;
Robert Carrd5c7dd62017-03-08 10:39:30 -08003115 mWindowSession.finishDrawing(mWindow);
3116 } catch (RemoteException e) {
3117 // Have fun!
3118 }
3119 }
3120
Jeff Brown96e942d2011-11-30 19:55:01 -08003121 private void performDraw() {
Jeff Brownd912e1f2014-04-11 18:46:22 -07003122 if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
Craig Mautner006f0e42012-03-21 11:00:32 -07003123 return;
Robert Carr32f37ab2017-06-15 12:39:34 -07003124 } else if (mView == null) {
3125 return;
Craig Mautner006f0e42012-03-21 11:00:32 -07003126 }
Romain Guy7e4e5612012-03-05 14:37:29 -08003127
John Reck5b02c622018-05-17 10:44:00 -07003128 final boolean fullRedrawNeeded = mFullRedrawNeeded || mReportNextDraw;
Jeff Brown96e942d2011-11-30 19:55:01 -08003129 mFullRedrawNeeded = false;
Jeff Brown481c1572012-03-09 14:41:15 -08003130
Romain Guy1f59e5c2012-05-06 14:11:16 -07003131 mIsDrawing = true;
Jeff Brown481c1572012-03-09 14:41:15 -08003132 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
John Reck5b02c622018-05-17 10:44:00 -07003133
3134 boolean usingAsyncReport = false;
3135 if (mReportNextDraw && mAttachInfo.mThreadedRenderer != null
3136 && mAttachInfo.mThreadedRenderer.isEnabled()) {
3137 usingAsyncReport = true;
3138 mAttachInfo.mThreadedRenderer.setFrameCompleteCallback((long frameNr) -> {
3139 // TODO: Use the frame number
3140 pendingDrawFinished();
3141 });
3142 }
3143
Jeff Brown481c1572012-03-09 14:41:15 -08003144 try {
John Reck5b02c622018-05-17 10:44:00 -07003145 boolean canUseAsync = draw(fullRedrawNeeded);
3146 if (usingAsyncReport && !canUseAsync) {
3147 mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(null);
3148 usingAsyncReport = false;
3149 }
Jeff Brown481c1572012-03-09 14:41:15 -08003150 } finally {
Romain Guy1f59e5c2012-05-06 14:11:16 -07003151 mIsDrawing = false;
Jeff Brown481c1572012-03-09 14:41:15 -08003152 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
3153 }
Jeff Brown96e942d2011-11-30 19:55:01 -08003154
John Reck119907c2014-08-14 09:02:01 -07003155 // For whatever reason we didn't create a HardwareRenderer, end any
3156 // hardware animations that are now dangling
3157 if (mAttachInfo.mPendingAnimatingRenderNodes != null) {
3158 final int count = mAttachInfo.mPendingAnimatingRenderNodes.size();
3159 for (int i = 0; i < count; i++) {
3160 mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators();
3161 }
3162 mAttachInfo.mPendingAnimatingRenderNodes.clear();
3163 }
3164
Jeff Brown96e942d2011-11-30 19:55:01 -08003165 if (mReportNextDraw) {
3166 mReportNextDraw = false;
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07003167
3168 // if we're using multi-thread renderer, wait for the window frame draws
3169 if (mWindowDrawCountDown != null) {
3170 try {
3171 mWindowDrawCountDown.await();
3172 } catch (InterruptedException e) {
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07003173 Log.e(mTag, "Window redraw count down interrupted!");
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07003174 }
3175 mWindowDrawCountDown = null;
3176 }
3177
Stan Iliev45faba52016-06-28 13:33:15 -04003178 if (mAttachInfo.mThreadedRenderer != null) {
Stan Iliev45faba52016-06-28 13:33:15 -04003179 mAttachInfo.mThreadedRenderer.setStopped(mStopped);
John Reck28ad7b52014-04-07 16:59:25 -07003180 }
Jeff Brown96e942d2011-11-30 19:55:01 -08003181
3182 if (LOCAL_LOGV) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003183 Log.v(mTag, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
Jeff Brown96e942d2011-11-30 19:55:01 -08003184 }
Robert Carr25cfa132016-11-16 13:24:09 -08003185
Jeff Brown96e942d2011-11-30 19:55:01 -08003186 if (mSurfaceHolder != null && mSurface.isValid()) {
Robert Carr8508bb22017-03-27 15:46:27 -07003187 SurfaceCallbackHelper sch = new SurfaceCallbackHelper(this::postDrawFinished);
Jeff Brown96e942d2011-11-30 19:55:01 -08003188 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
Robert Carr25cfa132016-11-16 13:24:09 -08003189
3190 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
John Reck5b02c622018-05-17 10:44:00 -07003191 } else if (!usingAsyncReport) {
3192 if (mAttachInfo.mThreadedRenderer != null) {
3193 mAttachInfo.mThreadedRenderer.fence();
3194 }
Robert Carr8508bb22017-03-27 15:46:27 -07003195 pendingDrawFinished();
Jeff Brown96e942d2011-11-30 19:55:01 -08003196 }
Jeff Brown96e942d2011-11-30 19:55:01 -08003197 }
3198 }
3199
John Reck5b02c622018-05-17 10:44:00 -07003200 private boolean draw(boolean fullRedrawNeeded) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003201 Surface surface = mSurface;
Romain Guyfbb93fa2012-12-03 18:50:35 -08003202 if (!surface.isValid()) {
John Reck5b02c622018-05-17 10:44:00 -07003203 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003204 }
3205
Chet Haase2f2022a2011-10-11 06:41:59 -07003206 if (DEBUG_FPS) {
3207 trackFPS();
3208 }
3209
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08003210 if (!sFirstDrawComplete) {
3211 synchronized (sFirstDrawHandlers) {
3212 sFirstDrawComplete = true;
Romain Guy812ccbe2010-06-01 14:07:24 -07003213 final int count = sFirstDrawHandlers.size();
3214 for (int i = 0; i< count; i++) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003215 mHandler.post(sFirstDrawHandlers.get(i));
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08003216 }
3217 }
3218 }
Romain Guy59a12ca2011-06-09 17:48:21 -07003219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003220 scrollToRectOrFocus(null, false);
3221
Chris Craikd36a81f2014-07-17 10:16:51 -07003222 if (mAttachInfo.mViewScrollChanged) {
3223 mAttachInfo.mViewScrollChanged = false;
3224 mAttachInfo.mTreeObserver.dispatchOnScrollChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003225 }
Romain Guy8506ab42009-06-11 17:35:47 -07003226
Dianne Hackborn0f761d62010-11-30 22:06:10 -08003227 boolean animating = mScroller != null && mScroller.computeScrollOffset();
Alan Viveretteccb11e12014-07-08 16:04:02 -07003228 final int curScrollY;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08003229 if (animating) {
Alan Viveretteccb11e12014-07-08 16:04:02 -07003230 curScrollY = mScroller.getCurrY();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003231 } else {
Alan Viveretteccb11e12014-07-08 16:04:02 -07003232 curScrollY = mScrollY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003233 }
Alan Viveretteccb11e12014-07-08 16:04:02 -07003234 if (mCurScrollY != curScrollY) {
3235 mCurScrollY = curScrollY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003236 fullRedrawNeeded = true;
Adrian Roos0e7ae4e2014-10-01 15:33:22 +02003237 if (mView instanceof RootViewSurfaceTaker) {
3238 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
3239 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003240 }
Jeff Brown96e942d2011-11-30 19:55:01 -08003241
Chris Craikd36a81f2014-07-17 10:16:51 -07003242 final float appScale = mAttachInfo.mApplicationScale;
3243 final boolean scalingRequired = mAttachInfo.mScalingRequired;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003244
Jeff Brown96e942d2011-11-30 19:55:01 -08003245 final Rect dirty = mDirty;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07003246 if (mSurfaceHolder != null) {
3247 // The app owns the surface, we won't draw.
3248 dirty.setEmpty();
Derek Sollenberger8d948352015-07-16 09:27:59 -04003249 if (animating && mScroller != null) {
3250 mScroller.abortAnimation();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08003251 }
John Reck5b02c622018-05-17 10:44:00 -07003252 return false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07003253 }
Romain Guy58ef7fb2010-09-13 12:52:37 -07003254
3255 if (fullRedrawNeeded) {
Chris Craikd36a81f2014-07-17 10:16:51 -07003256 mAttachInfo.mIgnoreDirtyState = true;
Romain Guyc3166e12011-08-08 15:00:03 -07003257 dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
Romain Guy58ef7fb2010-09-13 12:52:37 -07003258 }
Chet Haasead4f7032011-06-22 09:18:31 -07003259
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003260 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003261 Log.v(mTag, "Draw " + mView + "/"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003262 + mWindowAttributes.getTitle()
3263 + ": dirty={" + dirty.left + "," + dirty.top
3264 + "," + dirty.right + "," + dirty.bottom + "} surface="
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07003265 + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
3266 appScale + ", width=" + mWidth + ", height=" + mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003267 }
3268
Chris Craikd36a81f2014-07-17 10:16:51 -07003269 mAttachInfo.mTreeObserver.dispatchOnDraw();
Romain Guy25eba5c2012-04-04 17:29:03 -07003270
Chong Zhang0275e392015-09-17 10:41:44 -07003271 int xOffset = -mCanvasOffsetX;
3272 int yOffset = -mCanvasOffsetY + curScrollY;
Alan Viverettea51cab92014-07-16 15:15:49 -07003273 final WindowManager.LayoutParams params = mWindowAttributes;
3274 final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
3275 if (surfaceInsets != null) {
3276 xOffset -= surfaceInsets.left;
3277 yOffset -= surfaceInsets.top;
3278
3279 // Offset dirty rect for surface insets.
3280 dirty.offset(surfaceInsets.left, surfaceInsets.right);
3281 }
3282
Alan Viverette632af842014-10-28 13:45:11 -07003283 boolean accessibilityFocusDirty = false;
3284 final Drawable drawable = mAttachInfo.mAccessibilityFocusDrawable;
3285 if (drawable != null) {
3286 final Rect bounds = mAttachInfo.mTmpInvalRect;
3287 final boolean hasFocus = getAccessibilityFocusedRect(bounds);
3288 if (!hasFocus) {
3289 bounds.setEmpty();
3290 }
3291 if (!bounds.equals(drawable.getBounds())) {
3292 accessibilityFocusDirty = true;
3293 }
3294 }
3295
John Reckba6adf62015-02-19 14:36:50 -08003296 mAttachInfo.mDrawingTime =
3297 mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
3298
John Reck5b02c622018-05-17 10:44:00 -07003299 boolean useAsyncReport = false;
Alan Viverette632af842014-10-28 13:45:11 -07003300 if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
Stan Iliev45faba52016-06-28 13:33:15 -04003301 if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {
Alan Viverette632af842014-10-28 13:45:11 -07003302 // If accessibility focus moved, always invalidate the root.
Jorim Jaggic39c7b02016-03-24 10:47:07 -07003303 boolean invalidateRoot = accessibilityFocusDirty || mInvalidateRootRequested;
3304 mInvalidateRootRequested = false;
Alan Viverette632af842014-10-28 13:45:11 -07003305
Jeff Brown96e942d2011-11-30 19:55:01 -08003306 // Draw with hardware renderer.
3307 mIsAnimating = false;
Alan Viverette632af842014-10-28 13:45:11 -07003308
John Reck0a973302014-07-16 13:29:45 -07003309 if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
3310 mHardwareYOffset = yOffset;
3311 mHardwareXOffset = xOffset;
Alan Viverette632af842014-10-28 13:45:11 -07003312 invalidateRoot = true;
Alan Viverettef6cf1a02014-08-11 14:13:02 -07003313 }
3314
Alan Viverette632af842014-10-28 13:45:11 -07003315 if (invalidateRoot) {
Stan Iliev45faba52016-06-28 13:33:15 -04003316 mAttachInfo.mThreadedRenderer.invalidateRoot();
Alan Viverette632af842014-10-28 13:45:11 -07003317 }
3318
Jeff Brown96e942d2011-11-30 19:55:01 -08003319 dirty.setEmpty();
3320
Skuhne980ee472015-10-06 11:31:31 -07003321 // Stage the content drawn size now. It will be transferred to the renderer
3322 // shortly before the draw commands get send to the renderer.
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07003323 final boolean updated = updateContentDrawBounds();
3324
John Reck8afcc762016-04-13 10:24:06 -07003325 if (mReportNextDraw) {
3326 // report next draw overrides setStopped()
3327 // This value is re-sync'd to the value of mStopped
3328 // in the handling of mReportNextDraw post-draw.
Stan Iliev45faba52016-06-28 13:33:15 -04003329 mAttachInfo.mThreadedRenderer.setStopped(false);
John Reck8afcc762016-04-13 10:24:06 -07003330 }
3331
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07003332 if (updated) {
3333 requestDrawWindow();
3334 }
Jorim Jaggi0d6222d2016-04-18 20:42:10 -07003335
John Reck5b02c622018-05-17 10:44:00 -07003336 useAsyncReport = true;
Jorim Jaggie6a026b2018-06-06 18:42:16 +02003337
3338 // draw(...) might invoke post-draw, which might register the next callback already.
3339 final FrameDrawingCallback callback = mNextRtFrameCallback;
Jorim Jaggi64be98d2018-04-26 23:23:29 +02003340 mNextRtFrameCallback = null;
Jorim Jaggie6a026b2018-06-06 18:42:16 +02003341 mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this, callback);
Romain Guy3696779b2013-01-28 14:04:07 -08003342 } else {
3343 // If we get here with a disabled & requested hardware renderer, something went
3344 // wrong (an invalidate posted right before we destroyed the hardware surface
3345 // for instance) so we should just bail out. Locking the surface with software
3346 // rendering at this point would lock it forever and prevent hardware renderer
3347 // from doing its job when it comes back.
3348 // Before we request a new frame we must however attempt to reinitiliaze the
3349 // hardware renderer if it's in requested state. This would happen after an
3350 // eglTerminate() for instance.
Stan Iliev45faba52016-06-28 13:33:15 -04003351 if (mAttachInfo.mThreadedRenderer != null &&
3352 !mAttachInfo.mThreadedRenderer.isEnabled() &&
Robert Carr80923d52018-04-19 13:05:08 -07003353 mAttachInfo.mThreadedRenderer.isRequested() &&
3354 mSurface.isValid()) {
Romain Guy3696779b2013-01-28 14:04:07 -08003355
3356 try {
Stan Iliev45faba52016-06-28 13:33:15 -04003357 mAttachInfo.mThreadedRenderer.initializeIfNeeded(
Alan Viverette50210d92015-05-14 18:05:36 -07003358 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
Igor Murashkina86ab6402013-08-30 12:58:36 -07003359 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08003360 handleOutOfResourcesException(e);
John Reck5b02c622018-05-17 10:44:00 -07003361 return false;
Romain Guy3696779b2013-01-28 14:04:07 -08003362 }
3363
3364 mFullRedrawNeeded = true;
3365 scheduleTraversals();
John Reck5b02c622018-05-17 10:44:00 -07003366 return false;
Romain Guy3696779b2013-01-28 14:04:07 -08003367 }
3368
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09003369 if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
3370 scalingRequired, dirty, surfaceInsets)) {
John Reck5b02c622018-05-17 10:44:00 -07003371 return false;
Romain Guy3696779b2013-01-28 14:04:07 -08003372 }
Jeff Brown95db2b22011-11-30 19:54:41 -08003373 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003374 }
Romain Guy8506ab42009-06-11 17:35:47 -07003375
Dianne Hackborn0f761d62010-11-30 22:06:10 -08003376 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003377 mFullRedrawNeeded = true;
3378 scheduleTraversals();
3379 }
John Reck5b02c622018-05-17 10:44:00 -07003380 return useAsyncReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003381 }
3382
Romain Guy25eba5c2012-04-04 17:29:03 -07003383 /**
Alan Viveretteccb11e12014-07-08 16:04:02 -07003384 * @return true if drawing was successful, false if an error occurred
Romain Guy25eba5c2012-04-04 17:29:03 -07003385 */
Alan Viveretteccb11e12014-07-08 16:04:02 -07003386 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09003387 boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
Romain Guy25eba5c2012-04-04 17:29:03 -07003388
3389 // Draw with software renderer.
Alan Viverettea51cab92014-07-16 15:15:49 -07003390 final Canvas canvas;
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09003391
3392 // We already have the offset of surfaceInsets in xoff, yoff and dirty region,
3393 // therefore we need to add it back when moving the dirty region.
3394 int dirtyXOffset = xoff;
3395 int dirtyYOffset = yoff;
3396 if (surfaceInsets != null) {
3397 dirtyXOffset += surfaceInsets.left;
3398 dirtyYOffset += surfaceInsets.top;
3399 }
3400
Romain Guy25eba5c2012-04-04 17:29:03 -07003401 try {
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09003402 dirty.offset(-dirtyXOffset, -dirtyYOffset);
Alan Viverettea51cab92014-07-16 15:15:49 -07003403 final int left = dirty.left;
3404 final int top = dirty.top;
3405 final int right = dirty.right;
3406 final int bottom = dirty.bottom;
Romain Guy25eba5c2012-04-04 17:29:03 -07003407
Romain Guy25eba5c2012-04-04 17:29:03 -07003408 canvas = mSurface.lockCanvas(dirty);
3409
Romain Guye55945e2013-04-04 15:26:04 -07003410 // The dirty rectangle can be modified by Surface.lockCanvas()
3411 //noinspection ConstantConditions
Alan Viverettea51cab92014-07-16 15:15:49 -07003412 if (left != dirty.left || top != dirty.top || right != dirty.right
3413 || bottom != dirty.bottom) {
Romain Guy25eba5c2012-04-04 17:29:03 -07003414 attachInfo.mIgnoreDirtyState = true;
3415 }
3416
3417 // TODO: Do this in native
3418 canvas.setDensity(mDensity);
3419 } catch (Surface.OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08003420 handleOutOfResourcesException(e);
Romain Guy25eba5c2012-04-04 17:29:03 -07003421 return false;
3422 } catch (IllegalArgumentException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003423 Log.e(mTag, "Could not lock surface", e);
Romain Guy25eba5c2012-04-04 17:29:03 -07003424 // Don't assume this is due to out of memory, it could be
3425 // something else, and if it is something else then we could
3426 // kill stuff (or ourself) for no reason.
3427 mLayoutRequested = true; // ask wm for a new surface next time.
3428 return false;
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09003429 } finally {
3430 dirty.offset(dirtyXOffset, dirtyYOffset); // Reset to the original value.
Romain Guy25eba5c2012-04-04 17:29:03 -07003431 }
3432
3433 try {
3434 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003435 Log.v(mTag, "Surface " + surface + " drawing to bitmap w="
Romain Guy25eba5c2012-04-04 17:29:03 -07003436 + canvas.getWidth() + ", h=" + canvas.getHeight());
3437 //canvas.drawARGB(255, 255, 0, 0);
3438 }
3439
Romain Guy25eba5c2012-04-04 17:29:03 -07003440 // If this bitmap's format includes an alpha channel, we
3441 // need to clear it before drawing so that the child will
3442 // properly re-composite its drawing on a transparent
3443 // background. This automatically respects the clip/dirty region
3444 // or
3445 // If we are applying an offset, we need to clear the area
3446 // where the offset doesn't appear to avoid having garbage
3447 // left in the blank areas.
Alan Viveretteccb11e12014-07-08 16:04:02 -07003448 if (!canvas.isOpaque() || yoff != 0 || xoff != 0) {
Romain Guy25eba5c2012-04-04 17:29:03 -07003449 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
3450 }
3451
3452 dirty.setEmpty();
3453 mIsAnimating = false;
Dianne Hackborn4702a852012-08-17 15:18:29 -07003454 mView.mPrivateFlags |= View.PFLAG_DRAWN;
Romain Guy25eba5c2012-04-04 17:29:03 -07003455
3456 if (DEBUG_DRAW) {
3457 Context cxt = mView.getContext();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003458 Log.i(mTag, "Drawing: package:" + cxt.getPackageName() +
Romain Guy25eba5c2012-04-04 17:29:03 -07003459 ", metrics=" + cxt.getResources().getDisplayMetrics() +
3460 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
3461 }
3462 try {
Alan Viveretteccb11e12014-07-08 16:04:02 -07003463 canvas.translate(-xoff, -yoff);
Romain Guy25eba5c2012-04-04 17:29:03 -07003464 if (mTranslator != null) {
3465 mTranslator.translateCanvas(canvas);
3466 }
Dianne Hackborn908aecc2012-07-31 16:37:34 -07003467 canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
Romain Guy25eba5c2012-04-04 17:29:03 -07003468 attachInfo.mSetIgnoreDirtyState = false;
3469
Romain Guy25eba5c2012-04-04 17:29:03 -07003470 mView.draw(canvas);
Alan Viverette632af842014-10-28 13:45:11 -07003471
3472 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Romain Guy25eba5c2012-04-04 17:29:03 -07003473 } finally {
3474 if (!attachInfo.mSetIgnoreDirtyState) {
3475 // Only clear the flag if it was not set during the mView.draw() call
3476 attachInfo.mIgnoreDirtyState = false;
3477 }
3478 }
Romain Guy25eba5c2012-04-04 17:29:03 -07003479 } finally {
Romain Guydddcd222012-05-18 15:33:57 -07003480 try {
3481 surface.unlockCanvasAndPost(canvas);
3482 } catch (IllegalArgumentException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003483 Log.e(mTag, "Could not unlock surface", e);
Romain Guydddcd222012-05-18 15:33:57 -07003484 mLayoutRequested = true; // ask wm for a new surface next time.
3485 //noinspection ReturnInsideFinallyBlock
3486 return false;
3487 }
Romain Guy25eba5c2012-04-04 17:29:03 -07003488
Romain Guy25eba5c2012-04-04 17:29:03 -07003489 if (LOCAL_LOGV) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003490 Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost");
Romain Guy25eba5c2012-04-04 17:29:03 -07003491 }
3492 }
3493 return true;
3494 }
3495
Alan Viverette632af842014-10-28 13:45:11 -07003496 /**
3497 * We want to draw a highlight around the current accessibility focused.
3498 * Since adding a style for all possible view is not a viable option we
3499 * have this specialized drawing method.
3500 *
3501 * Note: We are doing this here to be able to draw the highlight for
3502 * virtual views in addition to real ones.
3503 *
3504 * @param canvas The canvas on which to draw.
3505 */
3506 private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
3507 final Rect bounds = mAttachInfo.mTmpInvalRect;
3508 if (getAccessibilityFocusedRect(bounds)) {
3509 final Drawable drawable = getAccessibilityFocusedDrawable();
3510 if (drawable != null) {
3511 drawable.setBounds(bounds);
3512 drawable.draw(canvas);
3513 }
3514 } else if (mAttachInfo.mAccessibilityFocusDrawable != null) {
3515 mAttachInfo.mAccessibilityFocusDrawable.setBounds(0, 0, 0, 0);
3516 }
3517 }
3518
3519 private boolean getAccessibilityFocusedRect(Rect bounds) {
3520 final AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
3521 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
3522 return false;
3523 }
3524
3525 final View host = mAccessibilityFocusedHost;
3526 if (host == null || host.mAttachInfo == null) {
3527 return false;
3528 }
3529
3530 final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
3531 if (provider == null) {
Svetoslavded133c2015-01-30 20:28:41 -08003532 host.getBoundsOnScreen(bounds, true);
Alan Viverette632af842014-10-28 13:45:11 -07003533 } else if (mAccessibilityFocusedVirtualView != null) {
3534 mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
3535 } else {
3536 return false;
3537 }
3538
Alan Viverette2232add2015-05-26 15:24:18 -07003539 // Transform the rect into window-relative coordinates.
Alan Viverette632af842014-10-28 13:45:11 -07003540 final AttachInfo attachInfo = mAttachInfo;
Alan Viverette2232add2015-05-26 15:24:18 -07003541 bounds.offset(0, attachInfo.mViewRootImpl.mScrollY);
Alan Viverette632af842014-10-28 13:45:11 -07003542 bounds.offset(-attachInfo.mWindowLeft, -attachInfo.mWindowTop);
Doris Liu9607fbe2015-05-28 17:17:28 -07003543 if (!bounds.intersect(0, 0, attachInfo.mViewRootImpl.mWidth,
3544 attachInfo.mViewRootImpl.mHeight)) {
3545 // If no intersection, set bounds to empty.
3546 bounds.setEmpty();
3547 }
Alan Viverette632af842014-10-28 13:45:11 -07003548 return !bounds.isEmpty();
3549 }
3550
3551 private Drawable getAccessibilityFocusedDrawable() {
Chris Craikd36a81f2014-07-17 10:16:51 -07003552 // Lazily load the accessibility focus drawable.
3553 if (mAttachInfo.mAccessibilityFocusDrawable == null) {
Alan Viverettef6cf1a02014-08-11 14:13:02 -07003554 final TypedValue value = new TypedValue();
Chris Craikd36a81f2014-07-17 10:16:51 -07003555 final boolean resolved = mView.mContext.getTheme().resolveAttribute(
3556 R.attr.accessibilityFocusedDrawable, value, true);
3557 if (resolved) {
3558 mAttachInfo.mAccessibilityFocusDrawable =
Alan Viverette8eea3ea2014-02-03 18:40:20 -08003559 mView.mContext.getDrawable(value.resourceId);
Svetoslav Ganov42138042012-03-20 11:51:39 -07003560 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07003561 }
Chris Craikd36a81f2014-07-17 10:16:51 -07003562 return mAttachInfo.mAccessibilityFocusDrawable;
Svetoslav Ganov42138042012-03-20 11:51:39 -07003563 }
3564
Jorim Jaggic39c7b02016-03-24 10:47:07 -07003565 /**
3566 * Requests that the root render node is invalidated next time we perform a draw, such that
3567 * {@link WindowCallbacks#onPostDraw} gets called.
3568 */
3569 public void requestInvalidateRootRenderNode() {
3570 mInvalidateRootRequested = true;
3571 }
3572
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003573 boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
Chris Craikd36a81f2014-07-17 10:16:51 -07003574 final Rect ci = mAttachInfo.mContentInsets;
3575 final Rect vi = mAttachInfo.mVisibleInsets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003576 int scrollY = 0;
3577 boolean handled = false;
Romain Guy8506ab42009-06-11 17:35:47 -07003578
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003579 if (vi.left > ci.left || vi.top > ci.top
3580 || vi.right > ci.right || vi.bottom > ci.bottom) {
3581 // We'll assume that we aren't going to change the scroll
3582 // offset, since we want to avoid that unless it is actually
3583 // going to make the focus visible... otherwise we scroll
3584 // all over the place.
3585 scrollY = mScrollY;
3586 // We can be called for two different situations: during a draw,
3587 // to update the scroll position if the focus has changed (in which
3588 // case 'rectangle' is null), or in response to a
3589 // requestChildRectangleOnScreen() call (in which case 'rectangle'
3590 // is non-null and we just want to scroll to whatever that
3591 // rectangle is).
Craig Mautner26a84df2013-04-11 19:09:05 -07003592 final View focus = mView.findFocus();
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003593 if (focus == null) {
Romain Guye8b16522009-07-14 13:06:42 -07003594 return false;
3595 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003596 View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null;
Craig Mautner26a84df2013-04-11 19:09:05 -07003597 if (focus != lastScrolledFocus) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003598 // If the focus has changed, then ignore any requests to scroll
3599 // to a rectangle; first we want to make sure the entire focus
3600 // view is visible.
3601 rectangle = null;
3602 }
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003603 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Eval scroll: focus=" + focus
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003604 + " rectangle=" + rectangle + " ci=" + ci
3605 + " vi=" + vi);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003606 if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003607 // Optimization: if the focus hasn't changed since last
3608 // time, and no layout has happened, then just leave things
3609 // as they are.
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003610 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Keeping scroll y="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003611 + mScrollY + " vi=" + vi.toShortString());
Craig Mautner26a84df2013-04-11 19:09:05 -07003612 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003613 // We need to determine if the currently focused view is
3614 // within the visible part of the window and, if not, apply
3615 // a pan so it can be seen.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003616 mLastScrolledFocus = new WeakReference<View>(focus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003617 mScrollMayChange = false;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003618 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Need to scroll?");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003619 // Try to find the rectangle from the focus view.
3620 if (focus.getGlobalVisibleRect(mVisRect, null)) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003621 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Root w="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003622 + mView.getWidth() + " h=" + mView.getHeight()
3623 + " ci=" + ci.toShortString()
3624 + " vi=" + vi.toShortString());
3625 if (rectangle == null) {
3626 focus.getFocusedRect(mTempRect);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003627 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Focus " + focus
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003628 + ": focusRect=" + mTempRect.toShortString());
Dianne Hackborn1c6a8942010-03-23 16:34:20 -07003629 if (mView instanceof ViewGroup) {
3630 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
3631 focus, mTempRect);
3632 }
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003633 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003634 "Focus in window: focusRect="
3635 + mTempRect.toShortString()
3636 + " visRect=" + mVisRect.toShortString());
3637 } else {
3638 mTempRect.set(rectangle);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003639 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003640 "Request scroll to rect: "
3641 + mTempRect.toShortString()
3642 + " visRect=" + mVisRect.toShortString());
3643 }
3644 if (mTempRect.intersect(mVisRect)) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003645 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003646 "Focus window visible rect: "
3647 + mTempRect.toShortString());
3648 if (mTempRect.height() >
3649 (mView.getHeight()-vi.top-vi.bottom)) {
3650 // If the focus simply is not going to fit, then
3651 // best is probably just to leave things as-is.
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003652 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003653 "Too tall; leaving scrollY=" + scrollY);
Chong Zhang67254722016-06-02 12:56:54 -07003654 }
3655 // Next, check whether top or bottom is covered based on the non-scrolled
3656 // position, and calculate new scrollY (or set it to 0).
3657 // We can't keep using mScrollY here. For example mScrollY is non-zero
3658 // due to IME, then IME goes away. The current value of mScrollY leaves top
3659 // and bottom both visible, but we still need to scroll it back to 0.
3660 else if (mTempRect.top < vi.top) {
3661 scrollY = mTempRect.top - vi.top;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003662 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003663 "Top covered; scrollY=" + scrollY);
Chong Zhang67254722016-06-02 12:56:54 -07003664 } else if (mTempRect.bottom > (mView.getHeight()-vi.bottom)) {
3665 scrollY = mTempRect.bottom - (mView.getHeight()-vi.bottom);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003666 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003667 "Bottom covered; scrollY=" + scrollY);
Chong Zhang67254722016-06-02 12:56:54 -07003668 } else {
3669 scrollY = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003670 }
3671 handled = true;
3672 }
3673 }
3674 }
3675 }
Romain Guy8506ab42009-06-11 17:35:47 -07003676
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003677 if (scrollY != mScrollY) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003678 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Pan scroll changed: old="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003679 + mScrollY + " , new=" + scrollY);
Derek Sollenberger8d948352015-07-16 09:27:59 -04003680 if (!immediate) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003681 if (mScroller == null) {
3682 mScroller = new Scroller(mView.getContext());
3683 }
3684 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
3685 } else if (mScroller != null) {
3686 mScroller.abortAnimation();
3687 }
3688 mScrollY = scrollY;
3689 }
Romain Guy8506ab42009-06-11 17:35:47 -07003690
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003691 return handled;
3692 }
Romain Guy8506ab42009-06-11 17:35:47 -07003693
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07003694 /**
3695 * @hide
3696 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +01003697 @UnsupportedAppUsage
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07003698 public View getAccessibilityFocusedHost() {
3699 return mAccessibilityFocusedHost;
3700 }
3701
3702 /**
3703 * @hide
3704 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +01003705 @UnsupportedAppUsage
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07003706 public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
3707 return mAccessibilityFocusedVirtualView;
3708 }
3709
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003710 void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003711 // If we have a virtual view with accessibility focus we need
3712 // to clear the focus and invalidate the virtual view bounds.
3713 if (mAccessibilityFocusedVirtualView != null) {
3714
3715 AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
3716 View focusHost = mAccessibilityFocusedHost;
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003717
3718 // Wipe the state of the current accessibility focus since
3719 // the call into the provider to clear accessibility focus
3720 // will fire an accessibility event which will end up calling
3721 // this method and we want to have clean state when this
3722 // invocation happens.
3723 mAccessibilityFocusedHost = null;
3724 mAccessibilityFocusedVirtualView = null;
3725
Alan Viverette239a0c02013-05-07 17:17:35 -07003726 // Clear accessibility focus on the host after clearing state since
3727 // this method may be reentrant.
Phil Weavere37cfab2016-04-07 21:01:57 -07003728 focusHost.clearAccessibilityFocusNoCallbacks(
3729 AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
Alan Viverette239a0c02013-05-07 17:17:35 -07003730
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003731 AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
3732 if (provider != null) {
3733 // Invalidate the area of the cleared accessibility focus.
3734 focusNode.getBoundsInParent(mTempRect);
3735 focusHost.invalidate(mTempRect);
3736 // Clear accessibility focus in the virtual node.
3737 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
3738 focusNode.getSourceNodeId());
3739 provider.performAction(virtualNodeId,
3740 AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
3741 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003742 focusNode.recycle();
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003743 }
Phil Weaverda469272016-06-24 18:17:21 -07003744 if ((mAccessibilityFocusedHost != null) && (mAccessibilityFocusedHost != view)) {
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003745 // Clear accessibility focus in the view.
Phil Weavere37cfab2016-04-07 21:01:57 -07003746 mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks(
3747 AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
Svetoslav Ganov42138042012-03-20 11:51:39 -07003748 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003749
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003750 // Set the new focus host and node.
3751 mAccessibilityFocusedHost = view;
3752 mAccessibilityFocusedVirtualView = node;
John Reck0a973302014-07-16 13:29:45 -07003753
Stan Iliev45faba52016-06-28 13:33:15 -04003754 if (mAttachInfo.mThreadedRenderer != null) {
3755 mAttachInfo.mThreadedRenderer.invalidateRoot();
John Reck0a973302014-07-16 13:29:45 -07003756 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07003757 }
3758
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08003759 boolean hasPointerCapture() {
3760 return mPointerCapture;
3761 }
3762
3763 void requestPointerCapture(boolean enabled) {
3764 if (mPointerCapture == enabled) {
3765 return;
3766 }
3767 InputManager.getInstance().requestPointerCapture(mAttachInfo.mWindowToken, enabled);
3768 }
3769
3770 private void handlePointerCaptureChanged(boolean hasCapture) {
3771 if (mPointerCapture == hasCapture) {
3772 return;
3773 }
3774 mPointerCapture = hasCapture;
3775 if (mView != null) {
3776 mView.dispatchPointerCaptureChanged(hasCapture);
3777 }
3778 }
3779
Igor Murashkina86ab6402013-08-30 12:58:36 -07003780 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003781 public void requestChildFocus(View child, View focused) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003782 if (DEBUG_INPUT_RESIZE) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003783 Log.v(mTag, "Request child focus: focus now " + focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003784 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003785 checkThread();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003786 scheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003787 }
3788
Igor Murashkina86ab6402013-08-30 12:58:36 -07003789 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003790 public void clearChildFocus(View child) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003791 if (DEBUG_INPUT_RESIZE) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003792 Log.v(mTag, "Clearing child focus");
Amith Yamasani73eb97f2012-02-14 15:45:15 -08003793 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003794 checkThread();
3795 scheduleTraversals();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003796 }
Amith Yamasani73eb97f2012-02-14 15:45:15 -08003797
Svetoslav Ganov42138042012-03-20 11:51:39 -07003798 @Override
3799 public ViewParent getParentForAccessibility() {
3800 return null;
3801 }
3802
Igor Murashkina86ab6402013-08-30 12:58:36 -07003803 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003804 public void focusableViewAvailable(View v) {
3805 checkThread();
Romain Guy1c90f032011-05-24 14:59:50 -07003806 if (mView != null) {
3807 if (!mView.hasFocus()) {
Evan Rosky28884042018-04-03 13:21:55 -07003808 if (sAlwaysAssignFocus || !mAttachInfo.mInTouchMode) {
Evan Rosky37df2db2017-01-24 16:35:52 -08003809 v.requestFocus();
3810 }
Romain Guy1c90f032011-05-24 14:59:50 -07003811 } else {
3812 // the one case where will transfer focus away from the current one
3813 // is if the current view is a view group that prefers to give focus
3814 // to its children first AND the view is a descendant of it.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003815 View focused = mView.findFocus();
3816 if (focused instanceof ViewGroup) {
3817 ViewGroup group = (ViewGroup) focused;
3818 if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
3819 && isViewDescendantOf(v, focused)) {
3820 v.requestFocus();
3821 }
Romain Guy1c90f032011-05-24 14:59:50 -07003822 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003823 }
3824 }
3825 }
3826
Igor Murashkina86ab6402013-08-30 12:58:36 -07003827 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003828 public void recomputeViewAttributes(View child) {
3829 checkThread();
3830 if (mView == child) {
3831 mAttachInfo.mRecomputeGlobalAttributes = true;
3832 if (!mWillDrawSoon) {
3833 scheduleTraversals();
3834 }
3835 }
3836 }
3837
3838 void dispatchDetachedFromWindow() {
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07003839 mFirstInputStage.onDetachedFromWindow();
Romain Guy90fc03b2011-01-16 13:07:15 -08003840 if (mView != null && mView.mAttachInfo != null) {
Dianne Hackborn961cae92013-03-20 14:59:43 -07003841 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003842 mView.dispatchDetachedFromWindow();
3843 }
3844
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003845 mAccessibilityInteractionConnectionManager.ensureNoConnection();
3846 mAccessibilityManager.removeAccessibilityStateChangeListener(
3847 mAccessibilityInteractionConnectionManager);
Chris Craikcce47eb2014-07-16 15:12:15 -07003848 mAccessibilityManager.removeHighTextContrastStateChangeListener(
3849 mHighContrastTextManager);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07003850 removeSendWindowContentChangedCallback();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003851
Romain Guya998dff2012-03-23 18:58:36 -07003852 destroyHardwareRenderer();
3853
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003854 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003855
Craig Mautner8f303ad2013-06-14 11:32:22 -07003856 mView.assignParent(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003857 mView = null;
3858 mAttachInfo.mRootView = null;
3859
Dianne Hackborn0586a1b2009-09-06 21:08:27 -07003860 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003861
Jeff Browncc4f7db2011-08-30 20:34:48 -07003862 if (mInputQueueCallback != null && mInputQueue != null) {
3863 mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
Michael Wrighta44dd262013-04-10 21:12:00 -07003864 mInputQueue.dispose();
Jeff Browncc4f7db2011-08-30 20:34:48 -07003865 mInputQueueCallback = null;
3866 mInputQueue = null;
Michael Wrighta44dd262013-04-10 21:12:00 -07003867 }
3868 if (mInputEventReceiver != null) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08003869 mInputEventReceiver.dispose();
3870 mInputEventReceiver = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -07003871 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003872 try {
Jeff Brown98365d72012-08-19 20:30:52 -07003873 mWindowSession.remove(mWindow);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003874 } catch (RemoteException e) {
3875 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003876
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003877 // Dispose the input channel after removing the window so the Window Manager
3878 // doesn't interpret the input channel being closed as an abnormal termination.
3879 if (mInputChannel != null) {
3880 mInputChannel.dispose();
3881 mInputChannel = null;
Jeff Brown349703e2010-06-22 01:27:15 -07003882 }
Jeff Brown96e942d2011-11-30 19:55:01 -08003883
Jeff Brownd912e1f2014-04-11 18:46:22 -07003884 mDisplayManager.unregisterDisplayListener(mDisplayListener);
3885
Jeff Brownebb2d8d2012-03-23 17:14:34 -07003886 unscheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003887 }
Romain Guy8506ab42009-06-11 17:35:47 -07003888
Andrii Kulian44607962017-03-16 11:06:24 -07003889 /**
3890 * Notifies all callbacks that configuration and/or display has changed and updates internal
3891 * state.
3892 * @param mergedConfiguration New global and override config in {@link MergedConfiguration}
3893 * container.
3894 * @param force Flag indicating if we should force apply the config.
3895 * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} if not
3896 * changed.
3897 */
3898 private void performConfigurationChange(MergedConfiguration mergedConfiguration, boolean force,
3899 int newDisplayId) {
3900 if (mergedConfiguration == null) {
3901 throw new IllegalArgumentException("No merged config provided.");
3902 }
Dianne Hackborn5fd21692011-06-07 14:09:47 -07003903
Andrii Kulian44607962017-03-16 11:06:24 -07003904 Configuration globalConfig = mergedConfiguration.getGlobalConfiguration();
3905 final Configuration overrideConfig = mergedConfiguration.getOverrideConfiguration();
3906 if (DEBUG_CONFIGURATION) Log.v(mTag,
3907 "Applying new config to window " + mWindowAttributes.getTitle()
3908 + ", globalConfig: " + globalConfig
3909 + ", overrideConfig: " + overrideConfig);
3910
3911 final CompatibilityInfo ci = mDisplay.getDisplayAdjustments().getCompatibilityInfo();
Craig Mautner48d0d182013-06-11 07:53:06 -07003912 if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
Andrii Kulian44607962017-03-16 11:06:24 -07003913 globalConfig = new Configuration(globalConfig);
3914 ci.applyToConfiguration(mNoncompatDensity, globalConfig);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07003915 }
3916
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003917 synchronized (sConfigCallbacks) {
3918 for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
Andrii Kulian44607962017-03-16 11:06:24 -07003919 sConfigCallbacks.get(i).onConfigurationChanged(globalConfig);
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003920 }
3921 }
Adam Lesinski4ece3d62016-06-16 18:05:41 -07003922
Andrii Kulian44607962017-03-16 11:06:24 -07003923 mLastReportedMergedConfiguration.setConfiguration(globalConfig, overrideConfig);
3924
3925 mForceNextConfigUpdate = force;
3926 if (mActivityConfigCallback != null) {
3927 // An activity callback is set - notify it about override configuration update.
3928 // This basically initiates a round trip to ActivityThread and back, which will ensure
3929 // that corresponding activity and resources are updated before updating inner state of
3930 // ViewRootImpl. Eventually it will call #updateConfiguration().
3931 mActivityConfigCallback.onConfigurationChanged(overrideConfig, newDisplayId);
3932 } else {
3933 // There is no activity callback - update the configuration right away.
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07003934 updateConfiguration(newDisplayId);
Andrii Kulian44607962017-03-16 11:06:24 -07003935 }
3936 mForceNextConfigUpdate = false;
3937 }
3938
3939 /**
3940 * Update display and views if last applied merged configuration changed.
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07003941 * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} otherwise.
Andrii Kulian44607962017-03-16 11:06:24 -07003942 */
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07003943 public void updateConfiguration(int newDisplayId) {
Andrii Kulian44607962017-03-16 11:06:24 -07003944 if (mView == null) {
3945 return;
3946 }
3947
3948 // At this point the resources have been updated to
3949 // have the most recent config, whatever that is. Use
3950 // the one in them which may be newer.
3951 final Resources localResources = mView.getResources();
3952 final Configuration config = localResources.getConfiguration();
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07003953
3954 // Handle move to display.
3955 if (newDisplayId != INVALID_DISPLAY) {
3956 onMovedToDisplay(newDisplayId, config);
3957 }
3958
3959 // Handle configuration change.
Andrii Kulian44607962017-03-16 11:06:24 -07003960 if (mForceNextConfigUpdate || mLastConfigurationFromResources.diff(config) != 0) {
3961 // Update the display with new DisplayAdjustments.
3962 mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(
3963 mDisplay.getDisplayId(), localResources);
3964
3965 final int lastLayoutDirection = mLastConfigurationFromResources.getLayoutDirection();
3966 final int currentLayoutDirection = config.getLayoutDirection();
3967 mLastConfigurationFromResources.setTo(config);
3968 if (lastLayoutDirection != currentLayoutDirection
3969 && mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
3970 mView.setLayoutDirection(currentLayoutDirection);
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003971 }
Andrii Kulian44607962017-03-16 11:06:24 -07003972 mView.dispatchConfigurationChanged(config);
Bryce Leef858b572017-06-29 14:03:33 -07003973
3974 // We could have gotten this {@link Configuration} update after we called
3975 // {@link #performTraversals} with an older {@link Configuration}. As a result, our
3976 // window frame may be stale. We must ensure the next pass of {@link #performTraversals}
3977 // catches this.
3978 mForceNextWindowRelayout = true;
3979 requestLayout();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003980 }
3981 }
John Reck05e85842014-04-23 14:48:28 -07003982
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003983 /**
3984 * Return true if child is an ancestor of parent, (or equal to the parent).
3985 */
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07003986 public static boolean isViewDescendantOf(View child, View parent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003987 if (child == parent) {
3988 return true;
3989 }
3990
3991 final ViewParent theParent = child.getParent();
3992 return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
3993 }
3994
Yohei Yukawad2e56472015-07-28 17:00:33 -07003995 private static void forceLayout(View view) {
3996 view.forceLayout();
3997 if (view instanceof ViewGroup) {
3998 ViewGroup group = (ViewGroup) view;
3999 final int count = group.getChildCount();
4000 for (int i = 0; i < count; i++) {
4001 forceLayout(group.getChildAt(i));
4002 }
4003 }
4004 }
4005
Jeff Browna175a5b2012-02-15 19:18:31 -08004006 private final static int MSG_INVALIDATE = 1;
4007 private final static int MSG_INVALIDATE_RECT = 2;
4008 private final static int MSG_DIE = 3;
4009 private final static int MSG_RESIZED = 4;
4010 private final static int MSG_RESIZED_REPORT = 5;
4011 private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
keunyoung30f420f2013-08-02 14:23:10 -07004012 private final static int MSG_DISPATCH_INPUT_EVENT = 7;
Jeff Browna175a5b2012-02-15 19:18:31 -08004013 private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
4014 private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
Jeff Browna175a5b2012-02-15 19:18:31 -08004015 private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
Dake Gu6a20a192018-02-08 12:09:30 -08004016 private final static int MSG_DISPATCH_KEY_FROM_AUTOFILL = 12;
Jeff Browna175a5b2012-02-15 19:18:31 -08004017 private final static int MSG_CHECK_FOCUS = 13;
4018 private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
4019 private final static int MSG_DISPATCH_DRAG_EVENT = 15;
4020 private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
4021 private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
4022 private final static int MSG_UPDATE_CONFIGURATION = 18;
Svetoslav Ganov42138042012-03-20 11:51:39 -07004023 private final static int MSG_PROCESS_INPUT_EVENTS = 19;
Romain Guyfbb93fa2012-12-03 18:50:35 -08004024 private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
Jorim Jaggi827e0fa2015-05-07 11:41:41 -07004025 private final static int MSG_INVALIDATE_WORLD = 22;
4026 private final static int MSG_WINDOW_MOVED = 23;
4027 private final static int MSG_SYNTHESIZE_INPUT_EVENT = 24;
4028 private final static int MSG_DISPATCH_WINDOW_SHOWN = 25;
Clara Bayarri75e09792015-07-29 16:20:40 +01004029 private final static int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26;
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08004030 private final static int MSG_UPDATE_POINTER_ICON = 27;
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08004031 private final static int MSG_POINTER_CAPTURE_CHANGED = 28;
Robert Carr8508bb22017-03-27 15:46:27 -07004032 private final static int MSG_DRAW_FINISHED = 29;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004033
Jeff Browna175a5b2012-02-15 19:18:31 -08004034 final class ViewRootHandler extends Handler {
4035 @Override
4036 public String getMessageName(Message message) {
4037 switch (message.what) {
4038 case MSG_INVALIDATE:
4039 return "MSG_INVALIDATE";
4040 case MSG_INVALIDATE_RECT:
4041 return "MSG_INVALIDATE_RECT";
4042 case MSG_DIE:
4043 return "MSG_DIE";
4044 case MSG_RESIZED:
4045 return "MSG_RESIZED";
4046 case MSG_RESIZED_REPORT:
4047 return "MSG_RESIZED_REPORT";
4048 case MSG_WINDOW_FOCUS_CHANGED:
4049 return "MSG_WINDOW_FOCUS_CHANGED";
keunyoung30f420f2013-08-02 14:23:10 -07004050 case MSG_DISPATCH_INPUT_EVENT:
4051 return "MSG_DISPATCH_INPUT_EVENT";
Jeff Browna175a5b2012-02-15 19:18:31 -08004052 case MSG_DISPATCH_APP_VISIBILITY:
4053 return "MSG_DISPATCH_APP_VISIBILITY";
4054 case MSG_DISPATCH_GET_NEW_SURFACE:
4055 return "MSG_DISPATCH_GET_NEW_SURFACE";
Jeff Browna175a5b2012-02-15 19:18:31 -08004056 case MSG_DISPATCH_KEY_FROM_IME:
4057 return "MSG_DISPATCH_KEY_FROM_IME";
Dake Gu6a20a192018-02-08 12:09:30 -08004058 case MSG_DISPATCH_KEY_FROM_AUTOFILL:
4059 return "MSG_DISPATCH_KEY_FROM_AUTOFILL";
Jeff Browna175a5b2012-02-15 19:18:31 -08004060 case MSG_CHECK_FOCUS:
4061 return "MSG_CHECK_FOCUS";
4062 case MSG_CLOSE_SYSTEM_DIALOGS:
4063 return "MSG_CLOSE_SYSTEM_DIALOGS";
4064 case MSG_DISPATCH_DRAG_EVENT:
4065 return "MSG_DISPATCH_DRAG_EVENT";
4066 case MSG_DISPATCH_DRAG_LOCATION_EVENT:
4067 return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
4068 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
4069 return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
4070 case MSG_UPDATE_CONFIGURATION:
4071 return "MSG_UPDATE_CONFIGURATION";
Jeff Browna175a5b2012-02-15 19:18:31 -08004072 case MSG_PROCESS_INPUT_EVENTS:
4073 return "MSG_PROCESS_INPUT_EVENTS";
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07004074 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
4075 return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
Craig Mautner5702d4d2012-06-30 14:10:16 -07004076 case MSG_WINDOW_MOVED:
4077 return "MSG_WINDOW_MOVED";
Michael Wright899d7052014-04-23 17:23:39 -07004078 case MSG_SYNTHESIZE_INPUT_EVENT:
4079 return "MSG_SYNTHESIZE_INPUT_EVENT";
Craig Mautner9c795042014-10-28 19:59:59 -07004080 case MSG_DISPATCH_WINDOW_SHOWN:
4081 return "MSG_DISPATCH_WINDOW_SHOWN";
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08004082 case MSG_UPDATE_POINTER_ICON:
4083 return "MSG_UPDATE_POINTER_ICON";
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08004084 case MSG_POINTER_CAPTURE_CHANGED:
4085 return "MSG_POINTER_CAPTURE_CHANGED";
Robert Carr8508bb22017-03-27 15:46:27 -07004086 case MSG_DRAW_FINISHED:
4087 return "MSG_DRAW_FINISHED";
Jeff Browna175a5b2012-02-15 19:18:31 -08004088 }
4089 return super.getMessageName(message);
Romain Guyf9284692011-07-13 18:46:21 -07004090 }
Romain Guyf9284692011-07-13 18:46:21 -07004091
Jeff Browna175a5b2012-02-15 19:18:31 -08004092 @Override
Michael Wright53b854a2016-04-12 19:22:41 -04004093 public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
4094 if (msg.what == MSG_REQUEST_KEYBOARD_SHORTCUTS && msg.obj == null) {
4095 // Debugging for b/27963013
4096 throw new NullPointerException(
4097 "Attempted to call MSG_REQUEST_KEYBOARD_SHORTCUTS with null receiver:");
4098 }
4099 return super.sendMessageAtTime(msg, uptimeMillis);
4100 }
4101
4102 @Override
Jeff Browna175a5b2012-02-15 19:18:31 -08004103 public void handleMessage(Message msg) {
4104 switch (msg.what) {
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004105 case MSG_INVALIDATE:
4106 ((View) msg.obj).invalidate();
Jeff Browna175a5b2012-02-15 19:18:31 -08004107 break;
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004108 case MSG_INVALIDATE_RECT:
4109 final View.AttachInfo.InvalidateInfo info =
4110 (View.AttachInfo.InvalidateInfo) msg.obj;
4111 info.target.invalidate(info.left, info.top, info.right, info.bottom);
4112 info.recycle();
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07004113 break;
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004114 case MSG_PROCESS_INPUT_EVENTS:
4115 mProcessInputEventsScheduled = false;
4116 doProcessInputEvents();
4117 break;
4118 case MSG_DISPATCH_APP_VISIBILITY:
4119 handleAppVisibility(msg.arg1 != 0);
4120 break;
4121 case MSG_DISPATCH_GET_NEW_SURFACE:
4122 handleGetNewSurface();
4123 break;
4124 case MSG_RESIZED: {
4125 // Recycled in the fall through...
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004126 SomeArgs args = (SomeArgs) msg.obj;
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004127 if (mWinFrame.equals(args.arg1)
4128 && mPendingOverscanInsets.equals(args.arg5)
4129 && mPendingContentInsets.equals(args.arg2)
4130 && mPendingStableInsets.equals(args.arg6)
Adrian Roos5c6b6222017-11-07 17:36:10 +01004131 && mPendingDisplayCutout.get().equals(args.arg9)
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004132 && mPendingVisibleInsets.equals(args.arg3)
4133 && mPendingOutsets.equals(args.arg7)
4134 && mPendingBackDropFrame.equals(args.arg8)
4135 && args.arg4 == null
4136 && args.argi1 == 0
4137 && mDisplay.getDisplayId() == args.argi3) {
4138 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08004139 }
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004140 } // fall through...
4141 case MSG_RESIZED_REPORT:
4142 if (mAdded) {
4143 SomeArgs args = (SomeArgs) msg.obj;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004144
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004145 final int displayId = args.argi3;
4146 MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg4;
4147 final boolean displayChanged = mDisplay.getDisplayId() != displayId;
Jorim Jaggi26952d72016-04-01 17:43:14 -07004148
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004149 if (!mLastReportedMergedConfiguration.equals(mergedConfiguration)) {
4150 // If configuration changed - notify about that and, maybe,
4151 // about move to display.
4152 performConfigurationChange(mergedConfiguration, false /* force */,
4153 displayChanged
4154 ? displayId : INVALID_DISPLAY /* same display */);
4155 } else if (displayChanged) {
4156 // Moved to display without config change - report last applied one.
4157 onMovedToDisplay(displayId, mLastConfigurationFromResources);
4158 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004159
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004160 final boolean framesChanged = !mWinFrame.equals(args.arg1)
4161 || !mPendingOverscanInsets.equals(args.arg5)
4162 || !mPendingContentInsets.equals(args.arg2)
4163 || !mPendingStableInsets.equals(args.arg6)
Adrian Roos5c6b6222017-11-07 17:36:10 +01004164 || !mPendingDisplayCutout.get().equals(args.arg9)
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004165 || !mPendingVisibleInsets.equals(args.arg3)
4166 || !mPendingOutsets.equals(args.arg7);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004167
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004168 mWinFrame.set((Rect) args.arg1);
4169 mPendingOverscanInsets.set((Rect) args.arg5);
4170 mPendingContentInsets.set((Rect) args.arg2);
4171 mPendingStableInsets.set((Rect) args.arg6);
Adrian Roos5c6b6222017-11-07 17:36:10 +01004172 mPendingDisplayCutout.set((DisplayCutout) args.arg9);
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004173 mPendingVisibleInsets.set((Rect) args.arg3);
4174 mPendingOutsets.set((Rect) args.arg7);
4175 mPendingBackDropFrame.set((Rect) args.arg8);
4176 mForceNextWindowRelayout = args.argi1 != 0;
4177 mPendingAlwaysConsumeNavBar = args.argi2 != 0;
4178
4179 args.recycle();
4180
4181 if (msg.what == MSG_RESIZED_REPORT) {
4182 reportNextDraw();
4183 }
4184
4185 if (mView != null && framesChanged) {
4186 forceLayout(mView);
4187 }
4188 requestLayout();
Jeff Browna175a5b2012-02-15 19:18:31 -08004189 }
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004190 break;
4191 case MSG_WINDOW_MOVED:
4192 if (mAdded) {
4193 final int w = mWinFrame.width();
4194 final int h = mWinFrame.height();
4195 final int l = msg.arg1;
4196 final int t = msg.arg2;
4197 mWinFrame.left = l;
4198 mWinFrame.right = l + w;
4199 mWinFrame.top = t;
4200 mWinFrame.bottom = t + h;
Romain Guy59a12ca2011-06-09 17:48:21 -07004201
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004202 mPendingBackDropFrame.set(mWinFrame);
4203 maybeHandleWindowMove(mWinFrame);
Yohei Yukawad2e56472015-07-28 17:00:33 -07004204 }
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004205 break;
4206 case MSG_WINDOW_FOCUS_CHANGED: {
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08004207 handleWindowFocusChanged();
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004208 } break;
4209 case MSG_DIE:
4210 doDie();
4211 break;
4212 case MSG_DISPATCH_INPUT_EVENT: {
4213 SomeArgs args = (SomeArgs) msg.obj;
4214 InputEvent event = (InputEvent) args.arg1;
4215 InputEventReceiver receiver = (InputEventReceiver) args.arg2;
4216 enqueueInputEvent(event, receiver, 0, true);
4217 args.recycle();
4218 } break;
4219 case MSG_SYNTHESIZE_INPUT_EVENT: {
4220 InputEvent event = (InputEvent) msg.obj;
4221 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_UNHANDLED, true);
4222 } break;
4223 case MSG_DISPATCH_KEY_FROM_IME: {
4224 if (LOCAL_LOGV) {
4225 Log.v(TAG, "Dispatching key " + msg.obj + " from IME to " + mView);
4226 }
4227 KeyEvent event = (KeyEvent) msg.obj;
4228 if ((event.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) != 0) {
4229 // The IME is trying to say this event is from the
4230 // system! Bad bad bad!
4231 //noinspection UnusedAssignment
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07004232 event = KeyEvent.changeFlags(event,
4233 event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004234 }
4235 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
4236 } break;
Dake Gu6a20a192018-02-08 12:09:30 -08004237 case MSG_DISPATCH_KEY_FROM_AUTOFILL: {
4238 if (LOCAL_LOGV) {
4239 Log.v(TAG, "Dispatching key " + msg.obj + " from Autofill to " + mView);
4240 }
4241 KeyEvent event = (KeyEvent) msg.obj;
Dake Gud9dbd272018-03-13 11:38:42 -07004242 enqueueInputEvent(event, null, 0, true);
Dake Gu6a20a192018-02-08 12:09:30 -08004243 } break;
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004244 case MSG_CHECK_FOCUS: {
Jeff Browna175a5b2012-02-15 19:18:31 -08004245 InputMethodManager imm = InputMethodManager.peekInstance();
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004246 if (imm != null) {
4247 imm.checkFocus();
Yohei Yukawa5f059652015-05-14 22:16:41 -07004248 }
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004249 } break;
4250 case MSG_CLOSE_SYSTEM_DIALOGS: {
Jeff Browna175a5b2012-02-15 19:18:31 -08004251 if (mView != null) {
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004252 mView.onCloseSystemDialogs((String) msg.obj);
4253 }
4254 } break;
4255 case MSG_DISPATCH_DRAG_EVENT: {
4256 } // fall through
4257 case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
4258 DragEvent event = (DragEvent) msg.obj;
4259 // only present when this app called startDrag()
4260 event.mLocalState = mLocalDragState;
4261 handleDragEvent(event);
4262 } break;
4263 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
4264 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj);
4265 } break;
4266 case MSG_UPDATE_CONFIGURATION: {
4267 Configuration config = (Configuration) msg.obj;
4268 if (config.isOtherSeqNewer(
4269 mLastReportedMergedConfiguration.getMergedConfiguration())) {
4270 // If we already have a newer merged config applied - use its global part.
4271 config = mLastReportedMergedConfiguration.getGlobalConfiguration();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004272 }
svetoslavganov75986cf2009-05-14 22:28:01 -07004273
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004274 // Use the newer global config and last reported override config.
4275 mPendingMergedConfiguration.setConfiguration(config,
4276 mLastReportedMergedConfiguration.getOverrideConfiguration());
4277
4278 performConfigurationChange(mPendingMergedConfiguration, false /* force */,
4279 INVALID_DISPLAY /* same display */);
4280 } break;
4281 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
4282 setAccessibilityFocus(null, null);
4283 } break;
4284 case MSG_INVALIDATE_WORLD: {
4285 if (mView != null) {
4286 invalidateWorld(mView);
Jeff Browna175a5b2012-02-15 19:18:31 -08004287 }
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004288 } break;
4289 case MSG_DISPATCH_WINDOW_SHOWN: {
4290 handleDispatchWindowShown();
4291 } break;
4292 case MSG_REQUEST_KEYBOARD_SHORTCUTS: {
4293 final IResultReceiver receiver = (IResultReceiver) msg.obj;
4294 final int deviceId = msg.arg1;
4295 handleRequestKeyboardShortcuts(receiver, deviceId);
4296 } break;
4297 case MSG_UPDATE_POINTER_ICON: {
4298 MotionEvent event = (MotionEvent) msg.obj;
4299 resetPointerIcon(event);
4300 } break;
4301 case MSG_POINTER_CAPTURE_CHANGED: {
4302 final boolean hasCapture = msg.arg1 != 0;
4303 handlePointerCaptureChanged(hasCapture);
4304 } break;
4305 case MSG_DRAW_FINISHED: {
4306 pendingDrawFinished();
4307 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004308 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004309 }
4310 }
Romain Guy51e4d4d2012-03-15 18:30:47 -07004311
Jeff Browna175a5b2012-02-15 19:18:31 -08004312 final ViewRootHandler mHandler = new ViewRootHandler();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004313
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004314 /**
4315 * Something in the current window tells us we need to change the touch mode. For
4316 * example, we are not in touch mode, and the user touches the screen.
4317 *
4318 * If the touch mode has changed, tell the window manager, and handle it locally.
4319 *
4320 * @param inTouchMode Whether we want to be in touch mode.
4321 * @return True if the touch mode changed and focus changed was changed as a result
4322 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +01004323 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004324 boolean ensureTouchMode(boolean inTouchMode) {
4325 if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
4326 + "touch mode is " + mAttachInfo.mInTouchMode);
4327 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
4328
4329 // tell the window manager
4330 try {
Matt Wud6bc96d2016-01-14 12:59:24 -08004331 mWindowSession.setInTouchMode(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004332 } catch (RemoteException e) {
4333 throw new RuntimeException(e);
4334 }
4335
4336 // handle the change
Romain Guy2d4cff62010-04-09 15:39:00 -07004337 return ensureTouchModeLocally(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004338 }
4339
4340 /**
4341 * Ensure that the touch mode for this window is set, and if it is changing,
4342 * take the appropriate action.
4343 * @param inTouchMode Whether we want to be in touch mode.
4344 * @return True if the touch mode changed and focus changed was changed as a result
4345 */
Romain Guy2d4cff62010-04-09 15:39:00 -07004346 private boolean ensureTouchModeLocally(boolean inTouchMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004347 if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
4348 + "touch mode is " + mAttachInfo.mInTouchMode);
4349
4350 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
4351
4352 mAttachInfo.mInTouchMode = inTouchMode;
4353 mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
4354
Romain Guy2d4cff62010-04-09 15:39:00 -07004355 return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004356 }
4357
4358 private boolean enterTouchMode() {
Alan Viveretteed7821a2013-07-24 15:49:23 -07004359 if (mView != null && mView.hasFocus()) {
4360 // note: not relying on mFocusedView here because this could
4361 // be when the window is first being added, and mFocused isn't
4362 // set yet.
4363 final View focused = mView.findFocus();
4364 if (focused != null && !focused.isFocusableInTouchMode()) {
4365 final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
4366 if (ancestorToTakeFocus != null) {
4367 // there is an ancestor that wants focus after its
4368 // descendants that is focusable in touch mode.. give it
4369 // focus
4370 return ancestorToTakeFocus.requestFocus();
4371 } else {
Alan Viverette973f3b42013-08-13 16:57:28 -07004372 // There's nothing to focus. Clear and propagate through the
4373 // hierarchy, but don't attempt to place new focus.
Alan Viverette223622a2013-12-17 13:29:02 -08004374 focused.clearFocusInternal(null, true, false);
Alan Viveretteed7821a2013-07-24 15:49:23 -07004375 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004376 }
4377 }
4378 }
4379 return false;
4380 }
4381
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004382 /**
4383 * Find an ancestor of focused that wants focus after its descendants and is
4384 * focusable in touch mode.
4385 * @param focused The currently focused view.
4386 * @return An appropriate view, or null if no such view exists.
4387 */
Romain Guya998dff2012-03-23 18:58:36 -07004388 private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004389 ViewParent parent = focused.getParent();
4390 while (parent instanceof ViewGroup) {
4391 final ViewGroup vgParent = (ViewGroup) parent;
4392 if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
4393 && vgParent.isFocusableInTouchMode()) {
4394 return vgParent;
4395 }
4396 if (vgParent.isRootNamespace()) {
4397 return null;
4398 } else {
4399 parent = vgParent.getParent();
4400 }
4401 }
4402 return null;
4403 }
4404
4405 private boolean leaveTouchMode() {
4406 if (mView != null) {
4407 if (mView.hasFocus()) {
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004408 View focusedView = mView.findFocus();
4409 if (!(focusedView instanceof ViewGroup)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004410 // some view has focus, let it keep it
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07004411 return false;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004412 } else if (((ViewGroup) focusedView).getDescendantFocusability() !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004413 ViewGroup.FOCUS_AFTER_DESCENDANTS) {
4414 // some view group has focus, and doesn't prefer its children
4415 // over itself for focus, so let them keep it.
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07004416 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004417 }
4418 }
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07004419
4420 // find the best view to give focus to in this brave new non-touch-mode
4421 // world
Evan Roskybdc66cb2017-09-08 14:27:24 -07004422 return mView.restoreDefaultFocus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004423 }
4424 return false;
4425 }
4426
Jeff Brownf9e989d2013-04-04 23:04:03 -07004427 /**
4428 * Base class for implementing a stage in the chain of responsibility
4429 * for processing input events.
4430 * <p>
4431 * Events are delivered to the stage by the {@link #deliver} method. The stage
4432 * then has the choice of finishing the event or forwarding it to the next stage.
4433 * </p>
4434 */
4435 abstract class InputStage {
4436 private final InputStage mNext;
4437
4438 protected static final int FORWARD = 0;
4439 protected static final int FINISH_HANDLED = 1;
4440 protected static final int FINISH_NOT_HANDLED = 2;
4441
4442 /**
4443 * Creates an input stage.
4444 * @param next The next stage to which events should be forwarded.
4445 */
4446 public InputStage(InputStage next) {
4447 mNext = next;
4448 }
4449
4450 /**
4451 * Delivers an event to be processed.
4452 */
4453 public final void deliver(QueuedInputEvent q) {
4454 if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
4455 forward(q);
Michael Wright17d28ca2013-10-31 17:47:45 -07004456 } else if (shouldDropInputEvent(q)) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004457 finish(q, false);
4458 } else {
4459 apply(q, onProcess(q));
4460 }
4461 }
4462
4463 /**
4464 * Marks the the input event as finished then forwards it to the next stage.
4465 */
4466 protected void finish(QueuedInputEvent q, boolean handled) {
4467 q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
4468 if (handled) {
4469 q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
4470 }
4471 forward(q);
4472 }
4473
4474 /**
4475 * Forwards the event to the next stage.
4476 */
4477 protected void forward(QueuedInputEvent q) {
4478 onDeliverToNext(q);
4479 }
4480
4481 /**
4482 * Applies a result code from {@link #onProcess} to the specified event.
4483 */
4484 protected void apply(QueuedInputEvent q, int result) {
4485 if (result == FORWARD) {
4486 forward(q);
4487 } else if (result == FINISH_HANDLED) {
4488 finish(q, true);
4489 } else if (result == FINISH_NOT_HANDLED) {
4490 finish(q, false);
4491 } else {
4492 throw new IllegalArgumentException("Invalid result: " + result);
4493 }
4494 }
4495
4496 /**
4497 * Called when an event is ready to be processed.
4498 * @return A result code indicating how the event was handled.
4499 */
4500 protected int onProcess(QueuedInputEvent q) {
4501 return FORWARD;
4502 }
4503
4504 /**
4505 * Called when an event is being delivered to the next stage.
4506 */
4507 protected void onDeliverToNext(QueuedInputEvent q) {
Michael Wright06a79252014-05-05 17:45:29 -07004508 if (DEBUG_INPUT_STAGES) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004509 Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);
Michael Wright06a79252014-05-05 17:45:29 -07004510 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004511 if (mNext != null) {
4512 mNext.deliver(q);
4513 } else {
4514 finishInputEvent(q);
4515 }
4516 }
Jeff Brown5182c782013-10-15 20:31:52 -07004517
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07004518 protected void onWindowFocusChanged(boolean hasWindowFocus) {
4519 if (mNext != null) {
4520 mNext.onWindowFocusChanged(hasWindowFocus);
4521 }
4522 }
4523
4524 protected void onDetachedFromWindow() {
4525 if (mNext != null) {
4526 mNext.onDetachedFromWindow();
4527 }
4528 }
4529
Michael Wright17d28ca2013-10-31 17:47:45 -07004530 protected boolean shouldDropInputEvent(QueuedInputEvent q) {
4531 if (mView == null || !mAdded) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004532 Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent);
Michael Wright17d28ca2013-10-31 17:47:45 -07004533 return true;
George Mount41725de2015-04-09 08:23:05 -07004534 } else if ((!mAttachInfo.mHasWindowFocus
Dake Gu6a20a192018-02-08 12:09:30 -08004535 && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
Dake Gud9dbd272018-03-13 11:38:42 -07004536 && !isAutofillUiShowing()) || mStopped
Joe LaPenna90776de2016-01-22 07:11:49 -08004537 || (mIsAmbientMode && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON))
4538 || (mPausedForTransition && !isBack(q.mEvent))) {
Wale Ogunwalec3672cd2014-11-05 15:17:35 -08004539 // This is a focus event and the window doesn't currently have input focus or
4540 // has stopped. This could be an event that came back from the previous stage
4541 // but the window has lost focus or stopped in the meantime.
4542 if (isTerminalInputEvent(q.mEvent)) {
4543 // Don't drop terminal input events, however mark them as canceled.
4544 q.mEvent.cancel();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004545 Slog.w(mTag, "Cancelling event due to no window focus: " + q.mEvent);
Wale Ogunwalec3672cd2014-11-05 15:17:35 -08004546 return false;
4547 }
4548
4549 // Drop non-terminal input events.
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004550 Slog.w(mTag, "Dropping event due to no window focus: " + q.mEvent);
Michael Wright17d28ca2013-10-31 17:47:45 -07004551 return true;
4552 }
4553 return false;
4554 }
4555
Jeff Brown5182c782013-10-15 20:31:52 -07004556 void dump(String prefix, PrintWriter writer) {
4557 if (mNext != null) {
4558 mNext.dump(prefix, writer);
4559 }
4560 }
George Mount41725de2015-04-09 08:23:05 -07004561
4562 private boolean isBack(InputEvent event) {
4563 if (event instanceof KeyEvent) {
4564 return ((KeyEvent) event).getKeyCode() == KeyEvent.KEYCODE_BACK;
4565 } else {
4566 return false;
4567 }
4568 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004569 }
4570
4571 /**
4572 * Base class for implementing an input pipeline stage that supports
4573 * asynchronous and out-of-order processing of input events.
4574 * <p>
4575 * In addition to what a normal input stage can do, an asynchronous
4576 * input stage may also defer an input event that has been delivered to it
4577 * and finish or forward it later.
4578 * </p>
4579 */
4580 abstract class AsyncInputStage extends InputStage {
4581 private final String mTraceCounter;
4582
4583 private QueuedInputEvent mQueueHead;
4584 private QueuedInputEvent mQueueTail;
4585 private int mQueueLength;
4586
4587 protected static final int DEFER = 3;
4588
4589 /**
4590 * Creates an asynchronous input stage.
4591 * @param next The next stage to which events should be forwarded.
4592 * @param traceCounter The name of a counter to record the size of
4593 * the queue of pending events.
4594 */
4595 public AsyncInputStage(InputStage next, String traceCounter) {
4596 super(next);
4597 mTraceCounter = traceCounter;
4598 }
4599
4600 /**
4601 * Marks the event as deferred, which is to say that it will be handled
4602 * asynchronously. The caller is responsible for calling {@link #forward}
4603 * or {@link #finish} later when it is done handling the event.
4604 */
4605 protected void defer(QueuedInputEvent q) {
4606 q.mFlags |= QueuedInputEvent.FLAG_DEFERRED;
4607 enqueue(q);
4608 }
4609
4610 @Override
4611 protected void forward(QueuedInputEvent q) {
4612 // Clear the deferred flag.
4613 q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED;
4614
4615 // Fast path if the queue is empty.
4616 QueuedInputEvent curr = mQueueHead;
4617 if (curr == null) {
4618 super.forward(q);
4619 return;
4620 }
4621
4622 // Determine whether the event must be serialized behind any others
4623 // before it can be delivered to the next stage. This is done because
4624 // deferred events might be handled out of order by the stage.
4625 final int deviceId = q.mEvent.getDeviceId();
4626 QueuedInputEvent prev = null;
4627 boolean blocked = false;
4628 while (curr != null && curr != q) {
4629 if (!blocked && deviceId == curr.mEvent.getDeviceId()) {
4630 blocked = true;
4631 }
4632 prev = curr;
4633 curr = curr.mNext;
4634 }
4635
4636 // If the event is blocked, then leave it in the queue to be delivered later.
4637 // Note that the event might not yet be in the queue if it was not previously
4638 // deferred so we will enqueue it if needed.
4639 if (blocked) {
4640 if (curr == null) {
4641 enqueue(q);
4642 }
4643 return;
4644 }
4645
4646 // The event is not blocked. Deliver it immediately.
4647 if (curr != null) {
4648 curr = curr.mNext;
4649 dequeue(q, prev);
4650 }
4651 super.forward(q);
4652
4653 // Dequeuing this event may have unblocked successors. Deliver them.
4654 while (curr != null) {
4655 if (deviceId == curr.mEvent.getDeviceId()) {
4656 if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) {
4657 break;
4658 }
4659 QueuedInputEvent next = curr.mNext;
4660 dequeue(curr, prev);
4661 super.forward(curr);
4662 curr = next;
4663 } else {
4664 prev = curr;
4665 curr = curr.mNext;
4666 }
4667 }
4668 }
4669
4670 @Override
4671 protected void apply(QueuedInputEvent q, int result) {
4672 if (result == DEFER) {
4673 defer(q);
4674 } else {
4675 super.apply(q, result);
4676 }
4677 }
4678
4679 private void enqueue(QueuedInputEvent q) {
4680 if (mQueueTail == null) {
4681 mQueueHead = q;
4682 mQueueTail = q;
4683 } else {
4684 mQueueTail.mNext = q;
4685 mQueueTail = q;
4686 }
4687
4688 mQueueLength += 1;
4689 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
4690 }
4691
4692 private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) {
4693 if (prev == null) {
4694 mQueueHead = q.mNext;
4695 } else {
4696 prev.mNext = q.mNext;
4697 }
4698 if (mQueueTail == q) {
4699 mQueueTail = prev;
4700 }
4701 q.mNext = null;
4702
4703 mQueueLength -= 1;
4704 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
4705 }
Jeff Brown5182c782013-10-15 20:31:52 -07004706
4707 @Override
4708 void dump(String prefix, PrintWriter writer) {
4709 writer.print(prefix);
4710 writer.print(getClass().getName());
4711 writer.print(": mQueueLength=");
4712 writer.println(mQueueLength);
4713
4714 super.dump(prefix, writer);
4715 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004716 }
4717
4718 /**
4719 * Delivers pre-ime input events to a native activity.
4720 * Does not support pointer events.
4721 */
Michael Wrighta44dd262013-04-10 21:12:00 -07004722 final class NativePreImeInputStage extends AsyncInputStage
4723 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004724 public NativePreImeInputStage(InputStage next, String traceCounter) {
4725 super(next, traceCounter);
4726 }
4727
4728 @Override
4729 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07004730 if (mInputQueue != null && q.mEvent instanceof KeyEvent) {
4731 mInputQueue.sendInputEvent(q.mEvent, q, true, this);
4732 return DEFER;
4733 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004734 return FORWARD;
4735 }
Michael Wrighta44dd262013-04-10 21:12:00 -07004736
4737 @Override
4738 public void onFinishedInputEvent(Object token, boolean handled) {
4739 QueuedInputEvent q = (QueuedInputEvent)token;
4740 if (handled) {
4741 finish(q, true);
4742 return;
4743 }
4744 forward(q);
4745 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004746 }
4747
4748 /**
4749 * Delivers pre-ime input events to the view hierarchy.
4750 * Does not support pointer events.
4751 */
4752 final class ViewPreImeInputStage extends InputStage {
4753 public ViewPreImeInputStage(InputStage next) {
4754 super(next);
4755 }
4756
4757 @Override
4758 protected int onProcess(QueuedInputEvent q) {
Jeff Brown481c1572012-03-09 14:41:15 -08004759 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004760 return processKeyEvent(q);
4761 }
4762 return FORWARD;
4763 }
4764
4765 private int processKeyEvent(QueuedInputEvent q) {
4766 final KeyEvent event = (KeyEvent)q.mEvent;
4767 if (mView.dispatchKeyEventPreIme(event)) {
4768 return FINISH_HANDLED;
4769 }
4770 return FORWARD;
4771 }
4772 }
4773
4774 /**
4775 * Delivers input events to the ime.
4776 * Does not support pointer events.
4777 */
4778 final class ImeInputStage extends AsyncInputStage
4779 implements InputMethodManager.FinishedInputEventCallback {
4780 public ImeInputStage(InputStage next, String traceCounter) {
4781 super(next, traceCounter);
4782 }
4783
4784 @Override
4785 protected int onProcess(QueuedInputEvent q) {
keunyoung30f420f2013-08-02 14:23:10 -07004786 if (mLastWasImTarget && !isInLocalFocusMode()) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004787 InputMethodManager imm = InputMethodManager.peekInstance();
4788 if (imm != null) {
4789 final InputEvent event = q.mEvent;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004790 if (DEBUG_IMF) Log.v(mTag, "Sending input event to IME: " + event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004791 int result = imm.dispatchInputEvent(event, q, this, mHandler);
4792 if (result == InputMethodManager.DISPATCH_HANDLED) {
4793 return FINISH_HANDLED;
4794 } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
Adam Lesinskic0f6eed2013-10-28 16:03:19 -07004795 // The IME could not handle it, so skip along to the next InputStage
4796 return FORWARD;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004797 } else {
4798 return DEFER; // callback will be invoked later
4799 }
4800 }
4801 }
4802 return FORWARD;
4803 }
4804
4805 @Override
4806 public void onFinishedInputEvent(Object token, boolean handled) {
4807 QueuedInputEvent q = (QueuedInputEvent)token;
4808 if (handled) {
4809 finish(q, true);
4810 return;
4811 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004812 forward(q);
4813 }
4814 }
4815
4816 /**
4817 * Performs early processing of post-ime input events.
4818 */
4819 final class EarlyPostImeInputStage extends InputStage {
4820 public EarlyPostImeInputStage(InputStage next) {
4821 super(next);
4822 }
4823
4824 @Override
4825 protected int onProcess(QueuedInputEvent q) {
4826 if (q.mEvent instanceof KeyEvent) {
4827 return processKeyEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08004828 } else {
Jeff Brown481c1572012-03-09 14:41:15 -08004829 final int source = q.mEvent.getSource();
4830 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004831 return processPointerEvent(q);
Jeff Brown481c1572012-03-09 14:41:15 -08004832 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08004833 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004834 return FORWARD;
4835 }
4836
4837 private int processKeyEvent(QueuedInputEvent q) {
4838 final KeyEvent event = (KeyEvent)q.mEvent;
4839
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08004840 if (mAttachInfo.mTooltipHost != null) {
4841 mAttachInfo.mTooltipHost.handleTooltipKey(event);
4842 }
4843
Jeff Brownf9e989d2013-04-04 23:04:03 -07004844 // If the key's purpose is to exit touch mode then we consume it
4845 // and consider it handled.
4846 if (checkForLeavingTouchModeAndConsume(event)) {
4847 return FINISH_HANDLED;
4848 }
4849
4850 // Make sure the fallback event policy sees all keys that will be
4851 // delivered to the view hierarchy.
4852 mFallbackEventHandler.preDispatchKeyEvent(event);
4853 return FORWARD;
4854 }
4855
4856 private int processPointerEvent(QueuedInputEvent q) {
4857 final MotionEvent event = (MotionEvent)q.mEvent;
4858
4859 // Translate the pointer event for compatibility, if needed.
4860 if (mTranslator != null) {
4861 mTranslator.translateEventInScreenToAppWindow(event);
4862 }
4863
Vladislav Kaznacheev7614cdf2017-02-21 11:57:59 -08004864 // Enter touch mode on down or scroll, if it is coming from a touch screen device,
4865 // exit otherwise.
Jeff Brownf9e989d2013-04-04 23:04:03 -07004866 final int action = event.getAction();
Vladislav Kaznacheev7614cdf2017-02-21 11:57:59 -08004867 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
4868 ensureTouchMode(event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN));
Jeff Brownf9e989d2013-04-04 23:04:03 -07004869 }
4870
Dake Gud9dbd272018-03-13 11:38:42 -07004871 if (action == MotionEvent.ACTION_DOWN) {
Dake Gub0fa3782018-02-26 12:25:14 -08004872 // Upon motion event within app window, close autofill ui.
Dake Gud9dbd272018-03-13 11:38:42 -07004873 AutofillManager afm = getAutofillManager();
4874 if (afm != null) {
4875 afm.requestHideFillUi();
Dake Gub0fa3782018-02-26 12:25:14 -08004876 }
4877 }
4878
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08004879 if (action == MotionEvent.ACTION_DOWN && mAttachInfo.mTooltipHost != null) {
4880 mAttachInfo.mTooltipHost.hideTooltip();
4881 }
4882
Jeff Brownf9e989d2013-04-04 23:04:03 -07004883 // Offset the scroll position.
4884 if (mCurScrollY != 0) {
4885 event.offsetLocation(0, mCurScrollY);
4886 }
4887
4888 // Remember the touch position for possible drag-initiation.
4889 if (event.isTouchEvent()) {
4890 mLastTouchPoint.x = event.getRawX();
4891 mLastTouchPoint.y = event.getRawY();
Vladislav Kaznacheevba761122016-01-22 12:09:45 -08004892 mLastTouchSource = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004893 }
4894 return FORWARD;
Jeff Brown4952dfd2011-11-30 19:23:22 -08004895 }
4896 }
4897
Jeff Brownf9e989d2013-04-04 23:04:03 -07004898 /**
4899 * Delivers post-ime input events to a native activity.
4900 */
Michael Wrighta44dd262013-04-10 21:12:00 -07004901 final class NativePostImeInputStage extends AsyncInputStage
4902 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004903 public NativePostImeInputStage(InputStage next, String traceCounter) {
4904 super(next, traceCounter);
4905 }
4906
4907 @Override
4908 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07004909 if (mInputQueue != null) {
4910 mInputQueue.sendInputEvent(q.mEvent, q, false, this);
4911 return DEFER;
4912 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004913 return FORWARD;
4914 }
Michael Wrighta44dd262013-04-10 21:12:00 -07004915
4916 @Override
4917 public void onFinishedInputEvent(Object token, boolean handled) {
4918 QueuedInputEvent q = (QueuedInputEvent)token;
4919 if (handled) {
4920 finish(q, true);
4921 return;
4922 }
4923 forward(q);
4924 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004925 }
4926
4927 /**
4928 * Delivers post-ime input events to the view hierarchy.
4929 */
4930 final class ViewPostImeInputStage extends InputStage {
4931 public ViewPostImeInputStage(InputStage next) {
4932 super(next);
4933 }
4934
4935 @Override
4936 protected int onProcess(QueuedInputEvent q) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08004937 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004938 return processKeyEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08004939 } else {
4940 final int source = q.mEvent.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004941 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
4942 return processPointerEvent(q);
4943 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
4944 return processTrackballEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08004945 } else {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004946 return processGenericMotionEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08004947 }
4948 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08004949 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08004950
Michael Wright9d744c72014-02-18 21:27:42 -08004951 @Override
4952 protected void onDeliverToNext(QueuedInputEvent q) {
4953 if (mUnbufferedInputDispatch
4954 && q.mEvent instanceof MotionEvent
4955 && ((MotionEvent)q.mEvent).isTouchEvent()
4956 && isTerminalInputEvent(q.mEvent)) {
4957 mUnbufferedInputDispatch = false;
4958 scheduleConsumeBatchedInput();
4959 }
4960 super.onDeliverToNext(q);
4961 }
4962
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08004963 private boolean performFocusNavigation(KeyEvent event) {
4964 int direction = 0;
4965 switch (event.getKeyCode()) {
4966 case KeyEvent.KEYCODE_DPAD_LEFT:
4967 if (event.hasNoModifiers()) {
4968 direction = View.FOCUS_LEFT;
4969 }
4970 break;
4971 case KeyEvent.KEYCODE_DPAD_RIGHT:
4972 if (event.hasNoModifiers()) {
4973 direction = View.FOCUS_RIGHT;
4974 }
4975 break;
4976 case KeyEvent.KEYCODE_DPAD_UP:
4977 if (event.hasNoModifiers()) {
4978 direction = View.FOCUS_UP;
4979 }
4980 break;
4981 case KeyEvent.KEYCODE_DPAD_DOWN:
4982 if (event.hasNoModifiers()) {
4983 direction = View.FOCUS_DOWN;
4984 }
4985 break;
4986 case KeyEvent.KEYCODE_TAB:
4987 if (event.hasNoModifiers()) {
4988 direction = View.FOCUS_FORWARD;
4989 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
4990 direction = View.FOCUS_BACKWARD;
4991 }
4992 break;
4993 }
4994 if (direction != 0) {
4995 View focused = mView.findFocus();
4996 if (focused != null) {
4997 View v = focused.focusSearch(direction);
4998 if (v != null && v != focused) {
4999 // do the math the get the interesting rect
5000 // of previous focused into the coord system of
5001 // newly focused view
5002 focused.getFocusedRect(mTempRect);
5003 if (mView instanceof ViewGroup) {
5004 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
5005 focused, mTempRect);
5006 ((ViewGroup) mView).offsetRectIntoDescendantCoords(
5007 v, mTempRect);
5008 }
5009 if (v.requestFocus(direction, mTempRect)) {
5010 playSoundEffect(SoundEffectConstants
5011 .getContantForFocusDirection(direction));
5012 return true;
5013 }
5014 }
5015
5016 // Give the focused view a last chance to handle the dpad key.
5017 if (mView.dispatchUnhandledMove(focused, direction)) {
5018 return true;
5019 }
5020 } else {
Evan Rosky37df2db2017-01-24 16:35:52 -08005021 if (mView.restoreDefaultFocus()) {
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08005022 return true;
5023 }
5024 }
5025 }
5026 return false;
5027 }
5028
Vadim Tryshevb5ced222017-01-17 19:31:35 -08005029 private boolean performKeyboardGroupNavigation(int direction) {
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08005030 final View focused = mView.findFocus();
Evan Rosky37df2db2017-01-24 16:35:52 -08005031 if (focused == null && mView.restoreDefaultFocus()) {
5032 return true;
5033 }
Evan Rosky5b860712017-04-17 16:40:16 -07005034 View cluster = focused == null ? keyboardNavigationClusterSearch(null, direction)
5035 : focused.keyboardNavigationClusterSearch(null, direction);
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08005036
Evan Rosky53fcf112017-01-26 14:37:55 -08005037 // Since requestFocus only takes "real" focus directions (and therefore also
5038 // restoreFocusInCluster), convert forward/backward focus into FOCUS_DOWN.
5039 int realDirection = direction;
5040 if (direction == View.FOCUS_FORWARD || direction == View.FOCUS_BACKWARD) {
5041 realDirection = View.FOCUS_DOWN;
5042 }
5043
Evan Rosky3ac64632017-02-13 18:04:43 -08005044 if (cluster != null && cluster.isRootNamespace()) {
5045 // the default cluster. Try to find a non-clustered view to focus.
5046 if (cluster.restoreFocusNotInCluster()) {
Evan Roskybd10c522017-03-27 15:50:38 -07005047 playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
Evan Rosky3ac64632017-02-13 18:04:43 -08005048 return true;
5049 }
5050 // otherwise skip to next actual cluster
5051 cluster = keyboardNavigationClusterSearch(null, direction);
5052 }
5053
Evan Rosky53fcf112017-01-26 14:37:55 -08005054 if (cluster != null && cluster.restoreFocusInCluster(realDirection)) {
Evan Roskybd10c522017-03-27 15:50:38 -07005055 playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08005056 return true;
5057 }
5058
5059 return false;
5060 }
5061
Jeff Brownf9e989d2013-04-04 23:04:03 -07005062 private int processKeyEvent(QueuedInputEvent q) {
5063 final KeyEvent event = (KeyEvent)q.mEvent;
5064
Evan Roskycd80e612018-05-17 17:46:09 -07005065 if (mUnhandledKeyManager.preViewDispatch(event)) {
Evan Rosky5e29c072017-06-02 17:31:22 -07005066 return FINISH_HANDLED;
5067 }
5068
Jeff Brownf9e989d2013-04-04 23:04:03 -07005069 // Deliver the key to the view hierarchy.
5070 if (mView.dispatchKeyEvent(event)) {
5071 return FINISH_HANDLED;
Jeff Brown21bc5c92011-02-28 18:27:14 -08005072 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005073
Michael Wright17d28ca2013-10-31 17:47:45 -07005074 if (shouldDropInputEvent(q)) {
5075 return FINISH_NOT_HANDLED;
5076 }
5077
Evan Roskycd80e612018-05-17 17:46:09 -07005078 // This dispatch is for windows that don't have a Window.Callback. Otherwise,
5079 // the Window.Callback usually will have already called this (see
5080 // DecorView.superDispatchKeyEvent) leaving this call a no-op.
5081 if (mUnhandledKeyManager.dispatch(mView, event)) {
Evan Rosky5e29c072017-06-02 17:31:22 -07005082 return FINISH_HANDLED;
5083 }
5084
Vadim Tryshev311a5b52017-01-05 18:54:11 -08005085 int groupNavigationDirection = 0;
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08005086
Evan Rosky516f9e62017-01-23 16:43:52 -08005087 if (event.getAction() == KeyEvent.ACTION_DOWN
5088 && event.getKeyCode() == KeyEvent.KEYCODE_TAB) {
5089 if (KeyEvent.metaStateHasModifiers(event.getMetaState(), KeyEvent.META_META_ON)) {
Vadim Tryshev311a5b52017-01-05 18:54:11 -08005090 groupNavigationDirection = View.FOCUS_FORWARD;
Evan Rosky516f9e62017-01-23 16:43:52 -08005091 } else if (KeyEvent.metaStateHasModifiers(event.getMetaState(),
5092 KeyEvent.META_META_ON | KeyEvent.META_SHIFT_ON)) {
Vadim Tryshev311a5b52017-01-05 18:54:11 -08005093 groupNavigationDirection = View.FOCUS_BACKWARD;
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08005094 }
5095 }
5096
Peeyush Agarwale631e322016-10-19 11:41:42 +01005097 // If a modifier is held, try to interpret the key as a shortcut.
Jeff Brownf9e989d2013-04-04 23:04:03 -07005098 if (event.getAction() == KeyEvent.ACTION_DOWN
Peeyush Agarwale631e322016-10-19 11:41:42 +01005099 && !KeyEvent.metaStateHasNoModifiers(event.getMetaState())
Jeff Brownf9e989d2013-04-04 23:04:03 -07005100 && event.getRepeatCount() == 0
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08005101 && !KeyEvent.isModifierKey(event.getKeyCode())
Vadim Tryshev311a5b52017-01-05 18:54:11 -08005102 && groupNavigationDirection == 0) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005103 if (mView.dispatchKeyShortcutEvent(event)) {
5104 return FINISH_HANDLED;
5105 }
Michael Wright17d28ca2013-10-31 17:47:45 -07005106 if (shouldDropInputEvent(q)) {
5107 return FINISH_NOT_HANDLED;
5108 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005109 }
5110
5111 // Apply the fallback event policy.
5112 if (mFallbackEventHandler.dispatchKeyEvent(event)) {
5113 return FINISH_HANDLED;
5114 }
Michael Wright17d28ca2013-10-31 17:47:45 -07005115 if (shouldDropInputEvent(q)) {
5116 return FINISH_NOT_HANDLED;
5117 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005118
5119 // Handle automatic focus changes.
5120 if (event.getAction() == KeyEvent.ACTION_DOWN) {
Vadim Tryshev311a5b52017-01-05 18:54:11 -08005121 if (groupNavigationDirection != 0) {
Vadim Tryshevb5ced222017-01-17 19:31:35 -08005122 if (performKeyboardGroupNavigation(groupNavigationDirection)) {
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08005123 return FINISH_HANDLED;
5124 }
5125 } else {
5126 if (performFocusNavigation(event)) {
5127 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005128 }
5129 }
5130 }
5131 return FORWARD;
Jeff Brown21bc5c92011-02-28 18:27:14 -08005132 }
5133
Jeff Brownf9e989d2013-04-04 23:04:03 -07005134 private int processPointerEvent(QueuedInputEvent q) {
5135 final MotionEvent event = (MotionEvent)q.mEvent;
5136
Vladislav Kaznacheev527905e2016-02-16 16:20:56 -08005137 mAttachInfo.mUnbufferedDispatchRequested = false;
Vladislav Kaznacheev527905e2016-02-16 16:20:56 -08005138 mAttachInfo.mHandlingPointerEvent = true;
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08005139 boolean handled = mView.dispatchPointerEvent(event);
Vladislav Kaznacheev527905e2016-02-16 16:20:56 -08005140 maybeUpdatePointerIcon(event);
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08005141 maybeUpdateTooltip(event);
Vladislav Kaznacheev527905e2016-02-16 16:20:56 -08005142 mAttachInfo.mHandlingPointerEvent = false;
5143 if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
5144 mUnbufferedInputDispatch = true;
5145 if (mConsumeBatchedInputScheduled) {
5146 scheduleConsumeBatchedInputImmediately();
5147 }
5148 }
5149 return handled ? FINISH_HANDLED : FORWARD;
5150 }
5151
5152 private void maybeUpdatePointerIcon(MotionEvent event) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005153 if (event.getPointerCount() == 1 && event.isFromSource(InputDevice.SOURCE_MOUSE)) {
Jun Mukai1db53972015-09-11 18:08:31 -07005154 if (event.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER
5155 || event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005156 // Other apps or the window manager may change the icon type outside of
5157 // this app, therefore the icon type has to be reset on enter/exit event.
5158 mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
Jun Mukai1db53972015-09-11 18:08:31 -07005159 }
5160
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005161 if (event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT) {
5162 if (!updatePointerIcon(event) &&
5163 event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005164 mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
Jun Mukai1db53972015-09-11 18:08:31 -07005165 }
5166 }
5167 }
Jeff Brown3915bb82010-11-05 15:02:16 -07005168 }
5169
Jeff Brownf9e989d2013-04-04 23:04:03 -07005170 private int processTrackballEvent(QueuedInputEvent q) {
5171 final MotionEvent event = (MotionEvent)q.mEvent;
5172
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08005173 if (event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) {
5174 if (!hasPointerCapture() || mView.dispatchCapturedPointerEvent(event)) {
5175 return FINISH_HANDLED;
5176 }
5177 }
5178
Jeff Brownf9e989d2013-04-04 23:04:03 -07005179 if (mView.dispatchTrackballEvent(event)) {
5180 return FINISH_HANDLED;
5181 }
5182 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005183 }
5184
Jeff Brownf9e989d2013-04-04 23:04:03 -07005185 private int processGenericMotionEvent(QueuedInputEvent q) {
5186 final MotionEvent event = (MotionEvent)q.mEvent;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07005187
Jeff Brownf9e989d2013-04-04 23:04:03 -07005188 // Deliver the event to the view.
5189 if (mView.dispatchGenericMotionEvent(event)) {
5190 return FINISH_HANDLED;
5191 }
5192 return FORWARD;
Jeff Brown3915bb82010-11-05 15:02:16 -07005193 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07005194 }
5195
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005196 private void resetPointerIcon(MotionEvent event) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005197 mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005198 updatePointerIcon(event);
5199 }
5200
5201 private boolean updatePointerIcon(MotionEvent event) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005202 final int pointerIndex = 0;
5203 final float x = event.getX(pointerIndex);
5204 final float y = event.getY(pointerIndex);
Andrii Kulian33c1bc52016-02-29 10:38:59 -08005205 if (mView == null) {
5206 // E.g. click outside a popup to dismiss it
5207 Slog.d(mTag, "updatePointerIcon called after view was removed");
5208 return false;
5209 }
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005210 if (x < 0 || x >= mView.getWidth() || y < 0 || y >= mView.getHeight()) {
Andrii Kulian33c1bc52016-02-29 10:38:59 -08005211 // E.g. when moving window divider with mouse
5212 Slog.d(mTag, "updatePointerIcon called with position out of bounds");
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005213 return false;
5214 }
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005215 final PointerIcon pointerIcon = mView.onResolvePointerIcon(event, pointerIndex);
5216 final int pointerType = (pointerIcon != null) ?
5217 pointerIcon.getType() : PointerIcon.TYPE_DEFAULT;
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005218
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005219 if (mPointerIconType != pointerType) {
5220 mPointerIconType = pointerType;
Vladislav Kaznacheeve40fb272017-01-03 16:45:42 -08005221 mCustomPointerIcon = null;
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005222 if (mPointerIconType != PointerIcon.TYPE_CUSTOM) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005223 InputManager.getInstance().setPointerIconType(pointerType);
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005224 return true;
5225 }
5226 }
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005227 if (mPointerIconType == PointerIcon.TYPE_CUSTOM &&
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005228 !pointerIcon.equals(mCustomPointerIcon)) {
5229 mCustomPointerIcon = pointerIcon;
5230 InputManager.getInstance().setCustomPointerIcon(mCustomPointerIcon);
5231 }
5232 return true;
5233 }
5234
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08005235 private void maybeUpdateTooltip(MotionEvent event) {
5236 if (event.getPointerCount() != 1) {
5237 return;
5238 }
5239 final int action = event.getActionMasked();
5240 if (action != MotionEvent.ACTION_HOVER_ENTER
5241 && action != MotionEvent.ACTION_HOVER_MOVE
5242 && action != MotionEvent.ACTION_HOVER_EXIT) {
5243 return;
5244 }
5245 AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
5246 if (manager.isEnabled() && manager.isTouchExplorationEnabled()) {
5247 return;
5248 }
5249 if (mView == null) {
5250 Slog.d(mTag, "maybeUpdateTooltip called after view was removed");
5251 return;
5252 }
5253 mView.dispatchTooltipHoverEvent(event);
5254 }
5255
Jeff Brownf9e989d2013-04-04 23:04:03 -07005256 /**
Jeff Brown678a1252013-04-09 17:46:25 -07005257 * Performs synthesis of new input events from unhandled input events.
Jeff Brownf9e989d2013-04-04 23:04:03 -07005258 */
5259 final class SyntheticInputStage extends InputStage {
Jeff Brown678a1252013-04-09 17:46:25 -07005260 private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler();
5261 private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
5262 private final SyntheticTouchNavigationHandler mTouchNavigation =
5263 new SyntheticTouchNavigationHandler();
Michael Wright899d7052014-04-23 17:23:39 -07005264 private final SyntheticKeyboardHandler mKeyboard = new SyntheticKeyboardHandler();
Jeff Brownf9e989d2013-04-04 23:04:03 -07005265
5266 public SyntheticInputStage() {
5267 super(null);
Jeff Brown21bc5c92011-02-28 18:27:14 -08005268 }
5269
Jeff Brownf9e989d2013-04-04 23:04:03 -07005270 @Override
5271 protected int onProcess(QueuedInputEvent q) {
5272 q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED;
5273 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07005274 final MotionEvent event = (MotionEvent)q.mEvent;
5275 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07005276 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07005277 mTrackball.process(event);
5278 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005279 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07005280 mJoystick.process(event);
5281 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005282 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
5283 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07005284 mTouchNavigation.process(event);
5285 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005286 }
Michael Wright899d7052014-04-23 17:23:39 -07005287 } else if ((q.mFlags & QueuedInputEvent.FLAG_UNHANDLED) != 0) {
5288 mKeyboard.process((KeyEvent)q.mEvent);
5289 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005290 }
Michael Wright899d7052014-04-23 17:23:39 -07005291
Jeff Brownf9e989d2013-04-04 23:04:03 -07005292 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005293 }
5294
Jeff Brownf9e989d2013-04-04 23:04:03 -07005295 @Override
5296 protected void onDeliverToNext(QueuedInputEvent q) {
5297 if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) {
5298 // Cancel related synthetic events if any prior stage has handled the event.
5299 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07005300 final MotionEvent event = (MotionEvent)q.mEvent;
5301 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07005302 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005303 mTrackball.cancel();
Jeff Brownf9e989d2013-04-04 23:04:03 -07005304 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005305 mJoystick.cancel();
Jeff Brownf9e989d2013-04-04 23:04:03 -07005306 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
5307 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07005308 mTouchNavigation.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07005309 }
5310 }
5311 }
5312 super.onDeliverToNext(q);
5313 }
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005314
5315 @Override
5316 protected void onWindowFocusChanged(boolean hasWindowFocus) {
5317 if (!hasWindowFocus) {
5318 mJoystick.cancel();
5319 }
5320 }
5321
5322 @Override
5323 protected void onDetachedFromWindow() {
5324 mJoystick.cancel();
5325 }
Jeff Brown678a1252013-04-09 17:46:25 -07005326 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005327
Jeff Brown678a1252013-04-09 17:46:25 -07005328 /**
5329 * Creates dpad events from unhandled trackball movements.
5330 */
5331 final class SyntheticTrackballHandler {
5332 private final TrackballAxis mX = new TrackballAxis();
5333 private final TrackballAxis mY = new TrackballAxis();
5334 private long mLastTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005335
Jeff Brown678a1252013-04-09 17:46:25 -07005336 public void process(MotionEvent event) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005337 // Translate the trackball event into DPAD keys and try to deliver those.
Jeff Brownf9e989d2013-04-04 23:04:03 -07005338 long curTime = SystemClock.uptimeMillis();
Jeff Brown678a1252013-04-09 17:46:25 -07005339 if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005340 // It has been too long since the last movement,
5341 // so restart at the beginning.
Jeff Brown678a1252013-04-09 17:46:25 -07005342 mX.reset(0);
5343 mY.reset(0);
5344 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005345 }
5346
5347 final int action = event.getAction();
5348 final int metaState = event.getMetaState();
5349 switch (action) {
5350 case MotionEvent.ACTION_DOWN:
Jeff Brown678a1252013-04-09 17:46:25 -07005351 mX.reset(2);
5352 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07005353 enqueueInputEvent(new KeyEvent(curTime, curTime,
5354 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
5355 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
5356 InputDevice.SOURCE_KEYBOARD));
5357 break;
5358 case MotionEvent.ACTION_UP:
Jeff Brown678a1252013-04-09 17:46:25 -07005359 mX.reset(2);
5360 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07005361 enqueueInputEvent(new KeyEvent(curTime, curTime,
5362 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
5363 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
5364 InputDevice.SOURCE_KEYBOARD));
5365 break;
5366 }
5367
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005368 if (DEBUG_TRACKBALL) Log.v(mTag, "TB X=" + mX.position + " step="
Jeff Brown678a1252013-04-09 17:46:25 -07005369 + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07005370 + " move=" + event.getX()
Jeff Brown678a1252013-04-09 17:46:25 -07005371 + " / Y=" + mY.position + " step="
5372 + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07005373 + " move=" + event.getY());
Jeff Brown678a1252013-04-09 17:46:25 -07005374 final float xOff = mX.collect(event.getX(), event.getEventTime(), "X");
5375 final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y");
Jeff Brownf9e989d2013-04-04 23:04:03 -07005376
5377 // Generate DPAD events based on the trackball movement.
5378 // We pick the axis that has moved the most as the direction of
5379 // the DPAD. When we generate DPAD events for one axis, then the
5380 // other axis is reset -- we don't want to perform DPAD jumps due
5381 // to slight movements in the trackball when making major movements
5382 // along the other axis.
5383 int keycode = 0;
5384 int movement = 0;
5385 float accel = 1;
5386 if (xOff > yOff) {
Jeff Brown678a1252013-04-09 17:46:25 -07005387 movement = mX.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07005388 if (movement != 0) {
5389 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
5390 : KeyEvent.KEYCODE_DPAD_LEFT;
Jeff Brown678a1252013-04-09 17:46:25 -07005391 accel = mX.acceleration;
5392 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07005393 }
5394 } else if (yOff > 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07005395 movement = mY.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07005396 if (movement != 0) {
5397 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
5398 : KeyEvent.KEYCODE_DPAD_UP;
Jeff Brown678a1252013-04-09 17:46:25 -07005399 accel = mY.acceleration;
5400 mX.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07005401 }
5402 }
5403
5404 if (keycode != 0) {
5405 if (movement < 0) movement = -movement;
5406 int accelMovement = (int)(movement * accel);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005407 if (DEBUG_TRACKBALL) Log.v(mTag, "Move: movement=" + movement
Jeff Brownf9e989d2013-04-04 23:04:03 -07005408 + " accelMovement=" + accelMovement
5409 + " accel=" + accel);
5410 if (accelMovement > movement) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005411 if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
Jeff Brownf9e989d2013-04-04 23:04:03 -07005412 + keycode);
5413 movement--;
5414 int repeatCount = accelMovement - movement;
5415 enqueueInputEvent(new KeyEvent(curTime, curTime,
5416 KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
5417 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
5418 InputDevice.SOURCE_KEYBOARD));
5419 }
5420 while (movement > 0) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005421 if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
Jeff Brownf9e989d2013-04-04 23:04:03 -07005422 + keycode);
5423 movement--;
5424 curTime = SystemClock.uptimeMillis();
5425 enqueueInputEvent(new KeyEvent(curTime, curTime,
5426 KeyEvent.ACTION_DOWN, keycode, 0, metaState,
5427 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
5428 InputDevice.SOURCE_KEYBOARD));
5429 enqueueInputEvent(new KeyEvent(curTime, curTime,
5430 KeyEvent.ACTION_UP, keycode, 0, metaState,
5431 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
5432 InputDevice.SOURCE_KEYBOARD));
5433 }
Jeff Brown678a1252013-04-09 17:46:25 -07005434 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005435 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005436 }
5437
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005438 public void cancel() {
Jeff Brown678a1252013-04-09 17:46:25 -07005439 mLastTime = Integer.MIN_VALUE;
Jeff Brown3915bb82010-11-05 15:02:16 -07005440
Jeff Brownf9e989d2013-04-04 23:04:03 -07005441 // If we reach this, we consumed a trackball event.
5442 // Because we will not translate the trackball event into a key event,
5443 // touch mode will not exit, so we exit touch mode here.
5444 if (mView != null && mAdded) {
5445 ensureTouchMode(false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07005446 }
5447 }
Jeff Brown678a1252013-04-09 17:46:25 -07005448 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005449
Jeff Brown678a1252013-04-09 17:46:25 -07005450 /**
5451 * Maintains state information for a single trackball axis, generating
5452 * discrete (DPAD) movements based on raw trackball motion.
5453 */
5454 static final class TrackballAxis {
5455 /**
5456 * The maximum amount of acceleration we will apply.
5457 */
5458 static final float MAX_ACCELERATION = 20;
5459
5460 /**
5461 * The maximum amount of time (in milliseconds) between events in order
5462 * for us to consider the user to be doing fast trackball movements,
5463 * and thus apply an acceleration.
5464 */
5465 static final long FAST_MOVE_TIME = 150;
5466
5467 /**
5468 * Scaling factor to the time (in milliseconds) between events to how
5469 * much to multiple/divide the current acceleration. When movement
5470 * is < FAST_MOVE_TIME this multiplies the acceleration; when >
5471 * FAST_MOVE_TIME it divides it.
5472 */
5473 static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
5474
5475 static final float FIRST_MOVEMENT_THRESHOLD = 0.5f;
5476 static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f;
5477 static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f;
5478
5479 float position;
5480 float acceleration = 1;
5481 long lastMoveTime = 0;
5482 int step;
5483 int dir;
5484 int nonAccelMovement;
5485
5486 void reset(int _step) {
5487 position = 0;
5488 acceleration = 1;
5489 lastMoveTime = 0;
5490 step = _step;
5491 dir = 0;
Jeff Brown6f2fba42011-02-19 01:08:02 -08005492 }
5493
Jeff Brown678a1252013-04-09 17:46:25 -07005494 /**
5495 * Add trackball movement into the state. If the direction of movement
5496 * has been reversed, the state is reset before adding the
5497 * movement (so that you don't have to compensate for any previously
5498 * collected movement before see the result of the movement in the
5499 * new direction).
5500 *
5501 * @return Returns the absolute value of the amount of movement
5502 * collected so far.
5503 */
5504 float collect(float off, long time, String axis) {
5505 long normTime;
5506 if (off > 0) {
5507 normTime = (long)(off * FAST_MOVE_TIME);
5508 if (dir < 0) {
5509 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
5510 position = 0;
5511 step = 0;
5512 acceleration = 1;
5513 lastMoveTime = 0;
5514 }
5515 dir = 1;
5516 } else if (off < 0) {
5517 normTime = (long)((-off) * FAST_MOVE_TIME);
5518 if (dir > 0) {
5519 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
5520 position = 0;
5521 step = 0;
5522 acceleration = 1;
5523 lastMoveTime = 0;
5524 }
5525 dir = -1;
5526 } else {
5527 normTime = 0;
5528 }
5529
5530 // The number of milliseconds between each movement that is
5531 // considered "normal" and will not result in any acceleration
5532 // or deceleration, scaled by the offset we have here.
5533 if (normTime > 0) {
5534 long delta = time - lastMoveTime;
5535 lastMoveTime = time;
5536 float acc = acceleration;
5537 if (delta < normTime) {
5538 // The user is scrolling rapidly, so increase acceleration.
5539 float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
5540 if (scale > 1) acc *= scale;
5541 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
5542 + off + " normTime=" + normTime + " delta=" + delta
5543 + " scale=" + scale + " acc=" + acc);
5544 acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
5545 } else {
5546 // The user is scrolling slowly, so decrease acceleration.
5547 float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
5548 if (scale > 1) acc /= scale;
5549 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
5550 + off + " normTime=" + normTime + " delta=" + delta
5551 + " scale=" + scale + " acc=" + acc);
5552 acceleration = acc > 1 ? acc : 1;
5553 }
5554 }
5555 position += off;
5556 return Math.abs(position);
Jeff Brown6f2fba42011-02-19 01:08:02 -08005557 }
Jeff Browncb1404e2011-01-15 18:14:15 -08005558
Jeff Brown678a1252013-04-09 17:46:25 -07005559 /**
5560 * Generate the number of discrete movement events appropriate for
5561 * the currently collected trackball movement.
5562 *
5563 * @return Returns the number of discrete movements, either positive
5564 * or negative, or 0 if there is not enough trackball movement yet
5565 * for a discrete movement.
5566 */
5567 int generate() {
5568 int movement = 0;
5569 nonAccelMovement = 0;
5570 do {
5571 final int dir = position >= 0 ? 1 : -1;
5572 switch (step) {
5573 // If we are going to execute the first step, then we want
5574 // to do this as soon as possible instead of waiting for
5575 // a full movement, in order to make things look responsive.
5576 case 0:
5577 if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) {
5578 return movement;
5579 }
5580 movement += dir;
5581 nonAccelMovement += dir;
5582 step = 1;
5583 break;
5584 // If we have generated the first movement, then we need
5585 // to wait for the second complete trackball motion before
5586 // generating the second discrete movement.
5587 case 1:
5588 if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) {
5589 return movement;
5590 }
5591 movement += dir;
5592 nonAccelMovement += dir;
5593 position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir;
5594 step = 2;
5595 break;
5596 // After the first two, we generate discrete movements
5597 // consistently with the trackball, applying an acceleration
5598 // if the trackball is moving quickly. This is a simple
5599 // acceleration on top of what we already compute based
5600 // on how quickly the wheel is being turned, to apply
5601 // a longer increasing acceleration to continuous movement
5602 // in one direction.
5603 default:
5604 if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) {
5605 return movement;
5606 }
5607 movement += dir;
5608 position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD;
5609 float acc = acceleration;
5610 acc *= 1.1f;
5611 acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
5612 break;
5613 }
5614 } while (true);
5615 }
5616 }
5617
5618 /**
5619 * Creates dpad events from unhandled joystick movements.
5620 */
5621 final class SyntheticJoystickHandler extends Handler {
5622 private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
5623 private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
5624
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005625 private final JoystickAxesState mJoystickAxesState = new JoystickAxesState();
5626 private final SparseArray<KeyEvent> mDeviceKeyEvents = new SparseArray<>();
Jeff Brown678a1252013-04-09 17:46:25 -07005627
5628 public SyntheticJoystickHandler() {
5629 super(true);
5630 }
5631
5632 @Override
5633 public void handleMessage(Message msg) {
5634 switch (msg.what) {
5635 case MSG_ENQUEUE_X_AXIS_KEY_REPEAT:
5636 case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: {
Jeff Brown678a1252013-04-09 17:46:25 -07005637 if (mAttachInfo.mHasWindowFocus) {
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005638 KeyEvent oldEvent = (KeyEvent) msg.obj;
5639 KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent,
5640 SystemClock.uptimeMillis(), oldEvent.getRepeatCount() + 1);
Jeff Brown678a1252013-04-09 17:46:25 -07005641 enqueueInputEvent(e);
5642 Message m = obtainMessage(msg.what, e);
5643 m.setAsynchronous(true);
5644 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay());
5645 }
5646 } break;
5647 }
5648 }
5649
5650 public void process(MotionEvent event) {
Michael Wright9adca062014-03-19 11:51:26 -07005651 switch(event.getActionMasked()) {
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005652 case MotionEvent.ACTION_CANCEL:
5653 cancel();
5654 break;
5655 case MotionEvent.ACTION_MOVE:
5656 update(event);
5657 break;
5658 default:
5659 Log.w(mTag, "Unexpected action: " + event.getActionMasked());
Michael Wright9adca062014-03-19 11:51:26 -07005660 }
Jeff Brown678a1252013-04-09 17:46:25 -07005661 }
5662
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005663 private void cancel() {
Michael Wright9adca062014-03-19 11:51:26 -07005664 removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
5665 removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005666 for (int i = 0; i < mDeviceKeyEvents.size(); i++) {
5667 final KeyEvent keyEvent = mDeviceKeyEvents.valueAt(i);
5668 if (keyEvent != null) {
5669 enqueueInputEvent(KeyEvent.changeTimeRepeat(keyEvent,
5670 SystemClock.uptimeMillis(), 0));
5671 }
5672 }
5673 mDeviceKeyEvents.clear();
5674 mJoystickAxesState.resetState();
Jeff Brown678a1252013-04-09 17:46:25 -07005675 }
5676
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005677 private void update(MotionEvent event) {
5678 final int historySize = event.getHistorySize();
5679 for (int h = 0; h < historySize; h++) {
5680 final long time = event.getHistoricalEventTime(h);
5681 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X,
5682 event.getHistoricalAxisValue(MotionEvent.AXIS_X, 0, h));
5683 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y,
5684 event.getHistoricalAxisValue(MotionEvent.AXIS_Y, 0, h));
5685 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X,
5686 event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_X, 0, h));
5687 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y,
5688 event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_Y, 0, h));
5689 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005690 final long time = event.getEventTime();
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005691 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X,
5692 event.getAxisValue(MotionEvent.AXIS_X));
5693 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y,
5694 event.getAxisValue(MotionEvent.AXIS_Y));
5695 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X,
Jeff Brownf9e989d2013-04-04 23:04:03 -07005696 event.getAxisValue(MotionEvent.AXIS_HAT_X));
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005697 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y,
Jeff Brownf9e989d2013-04-04 23:04:03 -07005698 event.getAxisValue(MotionEvent.AXIS_HAT_Y));
Jeff Browncb1404e2011-01-15 18:14:15 -08005699 }
5700
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005701 final class JoystickAxesState {
5702 // State machine: from neutral state (no button press) can go into
5703 // button STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state, emitting an ACTION_DOWN event.
5704 // From STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state can go into neutral state,
5705 // emitting an ACTION_UP event.
5706 private static final int STATE_UP_OR_LEFT = -1;
5707 private static final int STATE_NEUTRAL = 0;
5708 private static final int STATE_DOWN_OR_RIGHT = 1;
5709
5710 final int[] mAxisStatesHat = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_HAT_X, AXIS_HAT_Y}
5711 final int[] mAxisStatesStick = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_X, AXIS_Y}
5712
5713 void resetState() {
5714 mAxisStatesHat[0] = STATE_NEUTRAL;
5715 mAxisStatesHat[1] = STATE_NEUTRAL;
5716 mAxisStatesStick[0] = STATE_NEUTRAL;
5717 mAxisStatesStick[1] = STATE_NEUTRAL;
5718 }
5719
5720 void updateStateForAxis(MotionEvent event, long time, int axis, float value) {
5721 // Emit KeyEvent if necessary
5722 // axis can be AXIS_X, AXIS_Y, AXIS_HAT_X, AXIS_HAT_Y
5723 final int axisStateIndex;
5724 final int repeatMessage;
5725 if (isXAxis(axis)) {
5726 axisStateIndex = 0;
5727 repeatMessage = MSG_ENQUEUE_X_AXIS_KEY_REPEAT;
5728 } else if (isYAxis(axis)) {
5729 axisStateIndex = 1;
5730 repeatMessage = MSG_ENQUEUE_Y_AXIS_KEY_REPEAT;
5731 } else {
5732 Log.e(mTag, "Unexpected axis " + axis + " in updateStateForAxis!");
5733 return;
5734 }
5735 final int newState = joystickAxisValueToState(value);
5736
5737 final int currentState;
5738 if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) {
5739 currentState = mAxisStatesStick[axisStateIndex];
5740 } else {
5741 currentState = mAxisStatesHat[axisStateIndex];
5742 }
5743
5744 if (currentState == newState) {
5745 return;
5746 }
5747
5748 final int metaState = event.getMetaState();
5749 final int deviceId = event.getDeviceId();
5750 final int source = event.getSource();
5751
5752 if (currentState == STATE_DOWN_OR_RIGHT || currentState == STATE_UP_OR_LEFT) {
5753 // send a button release event
5754 final int keyCode = joystickAxisAndStateToKeycode(axis, currentState);
5755 if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
5756 enqueueInputEvent(new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode,
5757 0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
5758 // remove the corresponding pending UP event if focus lost/view detached
5759 mDeviceKeyEvents.put(deviceId, null);
5760 }
5761 removeMessages(repeatMessage);
5762 }
5763
5764 if (newState == STATE_DOWN_OR_RIGHT || newState == STATE_UP_OR_LEFT) {
5765 // send a button down event
5766 final int keyCode = joystickAxisAndStateToKeycode(axis, newState);
5767 if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
5768 KeyEvent keyEvent = new KeyEvent(time, time, KeyEvent.ACTION_DOWN, keyCode,
5769 0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
5770 enqueueInputEvent(keyEvent);
5771 Message m = obtainMessage(repeatMessage, keyEvent);
5772 m.setAsynchronous(true);
5773 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
5774 // store the corresponding ACTION_UP event so that it can be sent
5775 // if focus is lost or root view is removed
5776 mDeviceKeyEvents.put(deviceId,
5777 new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode,
5778 0, metaState, deviceId, 0,
5779 KeyEvent.FLAG_FALLBACK | KeyEvent.FLAG_CANCELED,
5780 source));
5781 }
5782 }
5783 if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) {
5784 mAxisStatesStick[axisStateIndex] = newState;
5785 } else {
5786 mAxisStatesHat[axisStateIndex] = newState;
5787 }
5788 }
5789
5790 private boolean isXAxis(int axis) {
5791 return axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_HAT_X;
5792 }
5793 private boolean isYAxis(int axis) {
5794 return axis == MotionEvent.AXIS_Y || axis == MotionEvent.AXIS_HAT_Y;
5795 }
5796
5797 private int joystickAxisAndStateToKeycode(int axis, int state) {
5798 if (isXAxis(axis) && state == STATE_UP_OR_LEFT) {
5799 return KeyEvent.KEYCODE_DPAD_LEFT;
5800 }
5801 if (isXAxis(axis) && state == STATE_DOWN_OR_RIGHT) {
5802 return KeyEvent.KEYCODE_DPAD_RIGHT;
5803 }
5804 if (isYAxis(axis) && state == STATE_UP_OR_LEFT) {
5805 return KeyEvent.KEYCODE_DPAD_UP;
5806 }
5807 if (isYAxis(axis) && state == STATE_DOWN_OR_RIGHT) {
5808 return KeyEvent.KEYCODE_DPAD_DOWN;
5809 }
5810 Log.e(mTag, "Unknown axis " + axis + " or direction " + state);
5811 return KeyEvent.KEYCODE_UNKNOWN; // should never happen
5812 }
5813
5814 private int joystickAxisValueToState(float value) {
5815 if (value >= 0.5f) {
5816 return STATE_DOWN_OR_RIGHT;
5817 } else if (value <= -0.5f) {
5818 return STATE_UP_OR_LEFT;
5819 } else {
5820 return STATE_NEUTRAL;
5821 }
Jeff Browncb1404e2011-01-15 18:14:15 -08005822 }
5823 }
Jeff Brown678a1252013-04-09 17:46:25 -07005824 }
Jeff Browncb1404e2011-01-15 18:14:15 -08005825
Jeff Brown678a1252013-04-09 17:46:25 -07005826 /**
5827 * Creates dpad events from unhandled touch navigation movements.
5828 */
5829 final class SyntheticTouchNavigationHandler extends Handler {
Jeff Brown4dac9012013-04-10 01:03:19 -07005830 private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler";
5831 private static final boolean LOCAL_DEBUG = false;
Jeff Brown678a1252013-04-09 17:46:25 -07005832
Jeff Brown4dac9012013-04-10 01:03:19 -07005833 // Assumed nominal width and height in millimeters of a touch navigation pad,
5834 // if no resolution information is available from the input system.
5835 private static final float DEFAULT_WIDTH_MILLIMETERS = 48;
5836 private static final float DEFAULT_HEIGHT_MILLIMETERS = 48;
Jeff Brown678a1252013-04-09 17:46:25 -07005837
Jeff Brown4dac9012013-04-10 01:03:19 -07005838 /* TODO: These constants should eventually be moved to ViewConfiguration. */
Jeff Brown678a1252013-04-09 17:46:25 -07005839
Jeff Brown4dac9012013-04-10 01:03:19 -07005840 // The nominal distance traveled to move by one unit.
5841 private static final int TICK_DISTANCE_MILLIMETERS = 12;
5842
5843 // Minimum and maximum fling velocity in ticks per second.
5844 // The minimum velocity should be set such that we perform enough ticks per
5845 // second that the fling appears to be fluid. For example, if we set the minimum
5846 // to 2 ticks per second, then there may be up to half a second delay between the next
5847 // to last and last ticks which is noticeably discrete and jerky. This value should
5848 // probably not be set to anything less than about 4.
5849 // If fling accuracy is a problem then consider tuning the tick distance instead.
5850 private static final float MIN_FLING_VELOCITY_TICKS_PER_SECOND = 6f;
5851 private static final float MAX_FLING_VELOCITY_TICKS_PER_SECOND = 20f;
5852
5853 // Fling velocity decay factor applied after each new key is emitted.
5854 // This parameter controls the deceleration and overall duration of the fling.
5855 // The fling stops automatically when its velocity drops below the minimum
5856 // fling velocity defined above.
5857 private static final float FLING_TICK_DECAY = 0.8f;
5858
5859 /* The input device that we are tracking. */
5860
5861 private int mCurrentDeviceId = -1;
5862 private int mCurrentSource;
5863 private boolean mCurrentDeviceSupported;
5864
5865 /* Configuration for the current input device. */
5866
Jeff Brown4dac9012013-04-10 01:03:19 -07005867 // The scaled tick distance. A movement of this amount should generally translate
5868 // into a single dpad event in a given direction.
5869 private float mConfigTickDistance;
5870
5871 // The minimum and maximum scaled fling velocity.
5872 private float mConfigMinFlingVelocity;
5873 private float mConfigMaxFlingVelocity;
5874
5875 /* Tracking state. */
5876
5877 // The velocity tracker for detecting flings.
5878 private VelocityTracker mVelocityTracker;
5879
5880 // The active pointer id, or -1 if none.
5881 private int mActivePointerId = -1;
5882
John Reck79d81e62013-11-05 13:26:57 -08005883 // Location where tracking started.
Jeff Brown4dac9012013-04-10 01:03:19 -07005884 private float mStartX;
5885 private float mStartY;
5886
5887 // Most recently observed position.
5888 private float mLastX;
5889 private float mLastY;
5890
5891 // Accumulated movement delta since the last direction key was sent.
Jeff Brown678a1252013-04-09 17:46:25 -07005892 private float mAccumulatedX;
5893 private float mAccumulatedY;
5894
Jeff Brown4dac9012013-04-10 01:03:19 -07005895 // Set to true if any movement was delivered to the app.
5896 // Implies that tap slop was exceeded.
5897 private boolean mConsumedMovement;
Jeff Brown678a1252013-04-09 17:46:25 -07005898
Jeff Brown4dac9012013-04-10 01:03:19 -07005899 // The most recently sent key down event.
5900 // The keycode remains set until the direction changes or a fling ends
5901 // so that repeated key events may be generated as required.
5902 private long mPendingKeyDownTime;
5903 private int mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
5904 private int mPendingKeyRepeatCount;
5905 private int mPendingKeyMetaState;
Jeff Brown678a1252013-04-09 17:46:25 -07005906
Jeff Brown4dac9012013-04-10 01:03:19 -07005907 // The current fling velocity while a fling is in progress.
5908 private boolean mFlinging;
5909 private float mFlingVelocity;
Jeff Brown678a1252013-04-09 17:46:25 -07005910
5911 public SyntheticTouchNavigationHandler() {
5912 super(true);
Jeff Brown678a1252013-04-09 17:46:25 -07005913 }
5914
5915 public void process(MotionEvent event) {
Jeff Brown4dac9012013-04-10 01:03:19 -07005916 // Update the current device information.
5917 final long time = event.getEventTime();
5918 final int deviceId = event.getDeviceId();
5919 final int source = event.getSource();
5920 if (mCurrentDeviceId != deviceId || mCurrentSource != source) {
5921 finishKeys(time);
5922 finishTracking(time);
5923 mCurrentDeviceId = deviceId;
5924 mCurrentSource = source;
5925 mCurrentDeviceSupported = false;
5926 InputDevice device = event.getDevice();
5927 if (device != null) {
5928 // In order to support an input device, we must know certain
5929 // characteristics about it, such as its size and resolution.
5930 InputDevice.MotionRange xRange = device.getMotionRange(MotionEvent.AXIS_X);
5931 InputDevice.MotionRange yRange = device.getMotionRange(MotionEvent.AXIS_Y);
5932 if (xRange != null && yRange != null) {
5933 mCurrentDeviceSupported = true;
Jeff Brown678a1252013-04-09 17:46:25 -07005934
Jeff Brown4dac9012013-04-10 01:03:19 -07005935 // Infer the resolution if it not actually known.
5936 float xRes = xRange.getResolution();
5937 if (xRes <= 0) {
5938 xRes = xRange.getRange() / DEFAULT_WIDTH_MILLIMETERS;
5939 }
5940 float yRes = yRange.getResolution();
5941 if (yRes <= 0) {
5942 yRes = yRange.getRange() / DEFAULT_HEIGHT_MILLIMETERS;
5943 }
5944 float nominalRes = (xRes + yRes) * 0.5f;
Jeff Brown678a1252013-04-09 17:46:25 -07005945
Jeff Brown4dac9012013-04-10 01:03:19 -07005946 // Precompute all of the configuration thresholds we will need.
Jeff Brown4dac9012013-04-10 01:03:19 -07005947 mConfigTickDistance = TICK_DISTANCE_MILLIMETERS * nominalRes;
5948 mConfigMinFlingVelocity =
5949 MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
5950 mConfigMaxFlingVelocity =
5951 MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
5952
5953 if (LOCAL_DEBUG) {
5954 Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId
5955 + " (" + Integer.toHexString(mCurrentSource) + "): "
Jeff Brown4dac9012013-04-10 01:03:19 -07005956 + ", mConfigTickDistance=" + mConfigTickDistance
5957 + ", mConfigMinFlingVelocity=" + mConfigMinFlingVelocity
5958 + ", mConfigMaxFlingVelocity=" + mConfigMaxFlingVelocity);
5959 }
5960 }
5961 }
Jeff Brown678a1252013-04-09 17:46:25 -07005962 }
Jeff Brown4dac9012013-04-10 01:03:19 -07005963 if (!mCurrentDeviceSupported) {
Jeff Brown678a1252013-04-09 17:46:25 -07005964 return;
5965 }
5966
Jeff Brown4dac9012013-04-10 01:03:19 -07005967 // Handle the event.
5968 final int action = event.getActionMasked();
5969 switch (action) {
Jeff Brown678a1252013-04-09 17:46:25 -07005970 case MotionEvent.ACTION_DOWN: {
Jeff Brown4dac9012013-04-10 01:03:19 -07005971 boolean caughtFling = mFlinging;
5972 finishKeys(time);
5973 finishTracking(time);
5974 mActivePointerId = event.getPointerId(0);
5975 mVelocityTracker = VelocityTracker.obtain();
5976 mVelocityTracker.addMovement(event);
Jeff Brown4dac9012013-04-10 01:03:19 -07005977 mStartX = event.getX();
5978 mStartY = event.getY();
5979 mLastX = mStartX;
5980 mLastY = mStartY;
Jeff Brown678a1252013-04-09 17:46:25 -07005981 mAccumulatedX = 0;
5982 mAccumulatedY = 0;
Jeff Brown4dac9012013-04-10 01:03:19 -07005983
5984 // If we caught a fling, then pretend that the tap slop has already
5985 // been exceeded to suppress taps whose only purpose is to stop the fling.
5986 mConsumedMovement = caughtFling;
Jeff Brown678a1252013-04-09 17:46:25 -07005987 break;
5988 }
5989
Jeff Brown4dac9012013-04-10 01:03:19 -07005990 case MotionEvent.ACTION_MOVE:
Jeff Brown678a1252013-04-09 17:46:25 -07005991 case MotionEvent.ACTION_UP: {
Jeff Brown4dac9012013-04-10 01:03:19 -07005992 if (mActivePointerId < 0) {
5993 break;
5994 }
5995 final int index = event.findPointerIndex(mActivePointerId);
5996 if (index < 0) {
5997 finishKeys(time);
5998 finishTracking(time);
5999 break;
6000 }
Jeff Brown678a1252013-04-09 17:46:25 -07006001
Jeff Brown4dac9012013-04-10 01:03:19 -07006002 mVelocityTracker.addMovement(event);
6003 final float x = event.getX(index);
6004 final float y = event.getY(index);
6005 mAccumulatedX += x - mLastX;
6006 mAccumulatedY += y - mLastY;
6007 mLastX = x;
6008 mLastY = y;
6009
6010 // Consume any accumulated movement so far.
6011 final int metaState = event.getMetaState();
6012 consumeAccumulatedMovement(time, metaState);
6013
6014 // Detect taps and flings.
6015 if (action == MotionEvent.ACTION_UP) {
Michael Wright88d7f792013-08-27 15:45:42 -07006016 if (mConsumedMovement && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
Jeff Brown4dac9012013-04-10 01:03:19 -07006017 // It might be a fling.
6018 mVelocityTracker.computeCurrentVelocity(1000, mConfigMaxFlingVelocity);
6019 final float vx = mVelocityTracker.getXVelocity(mActivePointerId);
6020 final float vy = mVelocityTracker.getYVelocity(mActivePointerId);
6021 if (!startFling(time, vx, vy)) {
6022 finishKeys(time);
Jeff Brown678a1252013-04-09 17:46:25 -07006023 }
6024 }
Jeff Brown4dac9012013-04-10 01:03:19 -07006025 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07006026 }
Jeff Brown4dac9012013-04-10 01:03:19 -07006027 break;
6028 }
6029
6030 case MotionEvent.ACTION_CANCEL: {
6031 finishKeys(time);
6032 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07006033 break;
6034 }
6035 }
Jeff Browncb1404e2011-01-15 18:14:15 -08006036 }
Jeff Brown4dac9012013-04-10 01:03:19 -07006037
6038 public void cancel(MotionEvent event) {
6039 if (mCurrentDeviceId == event.getDeviceId()
6040 && mCurrentSource == event.getSource()) {
6041 final long time = event.getEventTime();
6042 finishKeys(time);
6043 finishTracking(time);
6044 }
6045 }
6046
6047 private void finishKeys(long time) {
6048 cancelFling();
6049 sendKeyUp(time);
6050 }
6051
6052 private void finishTracking(long time) {
6053 if (mActivePointerId >= 0) {
6054 mActivePointerId = -1;
6055 mVelocityTracker.recycle();
6056 mVelocityTracker = null;
6057 }
6058 }
6059
6060 private void consumeAccumulatedMovement(long time, int metaState) {
6061 final float absX = Math.abs(mAccumulatedX);
6062 final float absY = Math.abs(mAccumulatedY);
6063 if (absX >= absY) {
6064 if (absX >= mConfigTickDistance) {
6065 mAccumulatedX = consumeAccumulatedMovement(time, metaState, mAccumulatedX,
6066 KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT);
6067 mAccumulatedY = 0;
6068 mConsumedMovement = true;
6069 }
6070 } else {
6071 if (absY >= mConfigTickDistance) {
6072 mAccumulatedY = consumeAccumulatedMovement(time, metaState, mAccumulatedY,
6073 KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN);
6074 mAccumulatedX = 0;
6075 mConsumedMovement = true;
6076 }
6077 }
6078 }
6079
6080 private float consumeAccumulatedMovement(long time, int metaState,
6081 float accumulator, int negativeKeyCode, int positiveKeyCode) {
6082 while (accumulator <= -mConfigTickDistance) {
6083 sendKeyDownOrRepeat(time, negativeKeyCode, metaState);
6084 accumulator += mConfigTickDistance;
6085 }
6086 while (accumulator >= mConfigTickDistance) {
6087 sendKeyDownOrRepeat(time, positiveKeyCode, metaState);
6088 accumulator -= mConfigTickDistance;
6089 }
6090 return accumulator;
6091 }
6092
6093 private void sendKeyDownOrRepeat(long time, int keyCode, int metaState) {
6094 if (mPendingKeyCode != keyCode) {
6095 sendKeyUp(time);
6096 mPendingKeyDownTime = time;
6097 mPendingKeyCode = keyCode;
6098 mPendingKeyRepeatCount = 0;
6099 } else {
6100 mPendingKeyRepeatCount += 1;
6101 }
6102 mPendingKeyMetaState = metaState;
6103
6104 // Note: Normally we would pass FLAG_LONG_PRESS when the repeat count is 1
6105 // but it doesn't quite make sense when simulating the events in this way.
6106 if (LOCAL_DEBUG) {
6107 Log.d(LOCAL_TAG, "Sending key down: keyCode=" + mPendingKeyCode
6108 + ", repeatCount=" + mPendingKeyRepeatCount
6109 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
6110 }
6111 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
6112 KeyEvent.ACTION_DOWN, mPendingKeyCode, mPendingKeyRepeatCount,
6113 mPendingKeyMetaState, mCurrentDeviceId,
6114 KeyEvent.FLAG_FALLBACK, mCurrentSource));
6115 }
6116
6117 private void sendKeyUp(long time) {
6118 if (mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
6119 if (LOCAL_DEBUG) {
6120 Log.d(LOCAL_TAG, "Sending key up: keyCode=" + mPendingKeyCode
6121 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
6122 }
6123 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
6124 KeyEvent.ACTION_UP, mPendingKeyCode, 0, mPendingKeyMetaState,
6125 mCurrentDeviceId, 0, KeyEvent.FLAG_FALLBACK,
6126 mCurrentSource));
6127 mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
6128 }
6129 }
6130
6131 private boolean startFling(long time, float vx, float vy) {
6132 if (LOCAL_DEBUG) {
6133 Log.d(LOCAL_TAG, "Considering fling: vx=" + vx + ", vy=" + vy
6134 + ", min=" + mConfigMinFlingVelocity);
6135 }
6136
6137 // Flings must be oriented in the same direction as the preceding movements.
6138 switch (mPendingKeyCode) {
6139 case KeyEvent.KEYCODE_DPAD_LEFT:
6140 if (-vx >= mConfigMinFlingVelocity
6141 && Math.abs(vy) < mConfigMinFlingVelocity) {
6142 mFlingVelocity = -vx;
6143 break;
6144 }
6145 return false;
6146
6147 case KeyEvent.KEYCODE_DPAD_RIGHT:
6148 if (vx >= mConfigMinFlingVelocity
6149 && Math.abs(vy) < mConfigMinFlingVelocity) {
6150 mFlingVelocity = vx;
6151 break;
6152 }
6153 return false;
6154
6155 case KeyEvent.KEYCODE_DPAD_UP:
6156 if (-vy >= mConfigMinFlingVelocity
6157 && Math.abs(vx) < mConfigMinFlingVelocity) {
6158 mFlingVelocity = -vy;
6159 break;
6160 }
6161 return false;
6162
6163 case KeyEvent.KEYCODE_DPAD_DOWN:
6164 if (vy >= mConfigMinFlingVelocity
6165 && Math.abs(vx) < mConfigMinFlingVelocity) {
6166 mFlingVelocity = vy;
6167 break;
6168 }
6169 return false;
6170 }
6171
6172 // Post the first fling event.
6173 mFlinging = postFling(time);
6174 return mFlinging;
6175 }
6176
6177 private boolean postFling(long time) {
6178 // The idea here is to estimate the time when the pointer would have
6179 // traveled one tick distance unit given the current fling velocity.
6180 // This effect creates continuity of motion.
6181 if (mFlingVelocity >= mConfigMinFlingVelocity) {
6182 long delay = (long)(mConfigTickDistance / mFlingVelocity * 1000);
6183 postAtTime(mFlingRunnable, time + delay);
6184 if (LOCAL_DEBUG) {
6185 Log.d(LOCAL_TAG, "Posted fling: velocity="
6186 + mFlingVelocity + ", delay=" + delay
6187 + ", keyCode=" + mPendingKeyCode);
6188 }
6189 return true;
6190 }
6191 return false;
6192 }
6193
6194 private void cancelFling() {
6195 if (mFlinging) {
6196 removeCallbacks(mFlingRunnable);
6197 mFlinging = false;
6198 }
6199 }
6200
6201 private final Runnable mFlingRunnable = new Runnable() {
6202 @Override
6203 public void run() {
6204 final long time = SystemClock.uptimeMillis();
6205 sendKeyDownOrRepeat(time, mPendingKeyCode, mPendingKeyMetaState);
6206 mFlingVelocity *= FLING_TICK_DECAY;
6207 if (!postFling(time)) {
6208 mFlinging = false;
6209 finishKeys(time);
6210 }
6211 }
6212 };
Jeff Browncb1404e2011-01-15 18:14:15 -08006213 }
6214
Michael Wright899d7052014-04-23 17:23:39 -07006215 final class SyntheticKeyboardHandler {
6216 public void process(KeyEvent event) {
6217 if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
6218 return;
6219 }
6220
6221 final KeyCharacterMap kcm = event.getKeyCharacterMap();
6222 final int keyCode = event.getKeyCode();
6223 final int metaState = event.getMetaState();
6224
6225 // Check for fallback actions specified by the key character map.
6226 KeyCharacterMap.FallbackAction fallbackAction =
6227 kcm.getFallbackAction(keyCode, metaState);
6228 if (fallbackAction != null) {
6229 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
6230 KeyEvent fallbackEvent = KeyEvent.obtain(
6231 event.getDownTime(), event.getEventTime(),
6232 event.getAction(), fallbackAction.keyCode,
6233 event.getRepeatCount(), fallbackAction.metaState,
6234 event.getDeviceId(), event.getScanCode(),
6235 flags, event.getSource(), null);
6236 fallbackAction.recycle();
6237 enqueueInputEvent(fallbackEvent);
6238 }
6239 }
6240 }
6241
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006242 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08006243 * Returns true if the key is used for keyboard navigation.
6244 * @param keyEvent The key event.
6245 * @return True if the key is used for keyboard navigation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006246 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08006247 private static boolean isNavigationKey(KeyEvent keyEvent) {
6248 switch (keyEvent.getKeyCode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006249 case KeyEvent.KEYCODE_DPAD_LEFT:
6250 case KeyEvent.KEYCODE_DPAD_RIGHT:
6251 case KeyEvent.KEYCODE_DPAD_UP:
6252 case KeyEvent.KEYCODE_DPAD_DOWN:
Jeff Brown4e6319b2010-12-13 10:36:51 -08006253 case KeyEvent.KEYCODE_DPAD_CENTER:
6254 case KeyEvent.KEYCODE_PAGE_UP:
6255 case KeyEvent.KEYCODE_PAGE_DOWN:
6256 case KeyEvent.KEYCODE_MOVE_HOME:
6257 case KeyEvent.KEYCODE_MOVE_END:
6258 case KeyEvent.KEYCODE_TAB:
6259 case KeyEvent.KEYCODE_SPACE:
6260 case KeyEvent.KEYCODE_ENTER:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006261 return true;
6262 }
6263 return false;
6264 }
6265
6266 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08006267 * Returns true if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006268 * @param keyEvent The key event.
Jeff Brown4e6319b2010-12-13 10:36:51 -08006269 * @return True if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006270 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08006271 private static boolean isTypingKey(KeyEvent keyEvent) {
6272 return keyEvent.getUnicodeChar() > 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006273 }
6274
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006275 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08006276 * 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 -08006277 * @param event The key event.
6278 * @return Whether this key event should be consumed (meaning the act of
6279 * leaving touch mode alone is considered the event).
6280 */
6281 private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08006282 // Only relevant in touch mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006283 if (!mAttachInfo.mInTouchMode) {
6284 return false;
6285 }
6286
Jeff Brown4e6319b2010-12-13 10:36:51 -08006287 // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
6288 final int action = event.getAction();
6289 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006290 return false;
6291 }
6292
Jeff Brown4e6319b2010-12-13 10:36:51 -08006293 // Don't leave touch mode if the IME told us not to.
6294 if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
6295 return false;
6296 }
6297
6298 // If the key can be used for keyboard navigation then leave touch mode
6299 // and select a focused view if needed (in ensureTouchMode).
6300 // When a new focused view is selected, we consume the navigation key because
6301 // navigation doesn't make much sense unless a view already has focus so
6302 // the key's purpose is to set focus.
6303 if (isNavigationKey(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006304 return ensureTouchMode(false);
6305 }
Jeff Brown4e6319b2010-12-13 10:36:51 -08006306
6307 // If the key can be used for typing then leave touch mode
6308 // and select a focused view if needed (in ensureTouchMode).
6309 // Always allow the view to process the typing key.
6310 if (isTypingKey(event)) {
6311 ensureTouchMode(false);
6312 return false;
6313 }
6314
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006315 return false;
6316 }
6317
Christopher Tatea53146c2010-09-07 11:57:52 -07006318 /* drag/drop */
Mathew Inwoode5ad5982018-08-17 15:07:52 +01006319 @UnsupportedAppUsage
Christopher Tate407b4e92010-11-30 17:14:08 -08006320 void setLocalDragState(Object obj) {
6321 mLocalDragState = obj;
6322 }
6323
Christopher Tatea53146c2010-09-07 11:57:52 -07006324 private void handleDragEvent(DragEvent event) {
6325 // From the root, only drag start/end/location are dispatched. entered/exited
6326 // are determined and dispatched by the viewgroup hierarchy, who then report
6327 // that back here for ultimate reporting back to the framework.
6328 if (mView != null && mAdded) {
6329 final int what = event.mAction;
6330
Vladislav Kaznacheev7fe1f792016-07-14 17:15:02 -07006331 // Cache the drag description when the operation starts, then fill it in
6332 // on subsequent calls as a convenience
6333 if (what == DragEvent.ACTION_DRAG_STARTED) {
6334 mCurrentDragView = null; // Start the current-recipient tracking
6335 mDragDescription = event.mClipDescription;
6336 } else {
Vladislav Kaznacheevcd84cfa2016-07-26 15:17:49 -07006337 if (what == DragEvent.ACTION_DRAG_ENDED) {
6338 mDragDescription = null;
6339 }
Vladislav Kaznacheev7fe1f792016-07-14 17:15:02 -07006340 event.mClipDescription = mDragDescription;
6341 }
6342
Christopher Tatea53146c2010-09-07 11:57:52 -07006343 if (what == DragEvent.ACTION_DRAG_EXITED) {
6344 // A direct EXITED event means that the window manager knows we've just crossed
6345 // a window boundary, so the current drag target within this one must have
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006346 // just been exited. Send the EXITED notification to the current drag view, if any.
Vadim Tryshev45bee6b2016-09-19 11:00:37 -07006347 if (View.sCascadedDragDrop) {
Vadim Tryshevef128112016-09-16 14:05:53 -07006348 mView.dispatchDragEnterExitInPreN(event);
6349 }
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006350 setDragFocus(null, event);
Christopher Tatea53146c2010-09-07 11:57:52 -07006351 } else {
Christopher Tatea53146c2010-09-07 11:57:52 -07006352 // For events with a [screen] location, translate into window coordinates
6353 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
6354 mDragPoint.set(event.mX, event.mY);
6355 if (mTranslator != null) {
6356 mTranslator.translatePointInScreenToAppWindow(mDragPoint);
6357 }
6358
6359 if (mCurScrollY != 0) {
6360 mDragPoint.offset(0, mCurScrollY);
6361 }
6362
6363 event.mX = mDragPoint.x;
6364 event.mY = mDragPoint.y;
6365 }
6366
6367 // Remember who the current drag target is pre-dispatch
6368 final View prevDragView = mCurrentDragView;
6369
Vadim Tryshev69733172016-09-30 17:25:30 -07006370 if (what == DragEvent.ACTION_DROP && event.mClipData != null) {
6371 event.mClipData.prepareToEnterProcess();
Vladislav Kaznacheev854d3f22016-08-11 10:19:36 -07006372 }
6373
Christopher Tatea53146c2010-09-07 11:57:52 -07006374 // Now dispatch the drag/drop event
Chris Tated4533f12010-10-19 15:15:08 -07006375 boolean result = mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07006376
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006377 if (what == DragEvent.ACTION_DRAG_LOCATION && !event.mEventHandlerWasCalled) {
6378 // If the LOCATION event wasn't delivered to any handler, no view now has a drag
6379 // focus.
6380 setDragFocus(null, event);
6381 }
6382
Christopher Tatea53146c2010-09-07 11:57:52 -07006383 // If we changed apparent drag target, tell the OS about it
6384 if (prevDragView != mCurrentDragView) {
6385 try {
6386 if (prevDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07006387 mWindowSession.dragRecipientExited(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07006388 }
6389 if (mCurrentDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07006390 mWindowSession.dragRecipientEntered(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07006391 }
6392 } catch (RemoteException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006393 Slog.e(mTag, "Unable to note drag target change");
Christopher Tatea53146c2010-09-07 11:57:52 -07006394 }
Christopher Tatea53146c2010-09-07 11:57:52 -07006395 }
Chris Tated4533f12010-10-19 15:15:08 -07006396
Christopher Tate407b4e92010-11-30 17:14:08 -08006397 // Report the drop result when we're done
Chris Tated4533f12010-10-19 15:15:08 -07006398 if (what == DragEvent.ACTION_DROP) {
6399 try {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006400 Log.i(mTag, "Reporting drop result: " + result);
Jeff Brown98365d72012-08-19 20:30:52 -07006401 mWindowSession.reportDropResult(mWindow, result);
Chris Tated4533f12010-10-19 15:15:08 -07006402 } catch (RemoteException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006403 Log.e(mTag, "Unable to report drop result");
Chris Tated4533f12010-10-19 15:15:08 -07006404 }
6405 }
Christopher Tate407b4e92010-11-30 17:14:08 -08006406
Vladislav Kaznacheev82063912015-11-20 14:20:13 -08006407 // When the drag operation ends, reset drag-related state
Christopher Tate407b4e92010-11-30 17:14:08 -08006408 if (what == DragEvent.ACTION_DRAG_ENDED) {
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006409 mCurrentDragView = null;
Christopher Tate407b4e92010-11-30 17:14:08 -08006410 setLocalDragState(null);
Vladislav Kaznacheev82063912015-11-20 14:20:13 -08006411 mAttachInfo.mDragToken = null;
Vladislav Kaznacheev4f639742015-11-18 13:21:35 -08006412 if (mAttachInfo.mDragSurface != null) {
6413 mAttachInfo.mDragSurface.release();
6414 mAttachInfo.mDragSurface = null;
6415 }
Christopher Tate407b4e92010-11-30 17:14:08 -08006416 }
Christopher Tatea53146c2010-09-07 11:57:52 -07006417 }
6418 }
6419 event.recycle();
6420 }
6421
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006422 public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
6423 if (mSeq != args.seq) {
6424 // The sequence has changed, so we need to update our value and make
6425 // sure to do a traversal afterward so the window manager is given our
6426 // most recent data.
6427 mSeq = args.seq;
6428 mAttachInfo.mForceReportNewAttributes = true;
Igor Murashkina86ab6402013-08-30 12:58:36 -07006429 scheduleTraversals();
Joe Onorato14782f72011-01-25 19:53:17 -08006430 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006431 if (mView == null) return;
6432 if (args.localChanges != 0) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006433 mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006434 }
Chris Craikd36a81f2014-07-17 10:16:51 -07006435
6436 int visibility = args.globalVisibility&View.SYSTEM_UI_CLEARABLE_FLAGS;
6437 if (visibility != mAttachInfo.mGlobalSystemUiVisibility) {
6438 mAttachInfo.mGlobalSystemUiVisibility = visibility;
6439 mView.dispatchSystemUiVisibilityChanged(visibility);
Dianne Hackborncf675782012-05-10 15:07:24 -07006440 }
Joe Onorato664644d2011-01-23 17:53:23 -08006441 }
6442
Phil Weaver964c68e2016-10-27 16:22:05 -07006443 /**
6444 * Notify that the window title changed
6445 */
6446 public void onWindowTitleChanged() {
6447 mAttachInfo.mForceReportNewAttributes = true;
6448 }
6449
Craig Mautner9c795042014-10-28 19:59:59 -07006450 public void handleDispatchWindowShown() {
6451 mAttachInfo.mTreeObserver.dispatchOnWindowShown();
6452 }
6453
Clara Bayarrifcd7e802016-03-10 12:58:18 +00006454 public void handleRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
Clara Bayarri75e09792015-07-29 16:20:40 +01006455 Bundle data = new Bundle();
6456 ArrayList<KeyboardShortcutGroup> list = new ArrayList<>();
6457 if (mView != null) {
Clara Bayarrifcd7e802016-03-10 12:58:18 +00006458 mView.requestKeyboardShortcuts(list, deviceId);
Clara Bayarri75e09792015-07-29 16:20:40 +01006459 }
6460 data.putParcelableArrayList(WindowManager.PARCEL_KEY_SHORTCUTS_ARRAY, list);
6461 try {
6462 receiver.send(0, data);
6463 } catch (RemoteException e) {
6464 }
6465 }
6466
Mathew Inwoode5ad5982018-08-17 15:07:52 +01006467 @UnsupportedAppUsage
Christopher Tate2c095f32010-10-04 14:13:40 -07006468 public void getLastTouchPoint(Point outLocation) {
6469 outLocation.x = (int) mLastTouchPoint.x;
6470 outLocation.y = (int) mLastTouchPoint.y;
6471 }
6472
Vladislav Kaznacheevba761122016-01-22 12:09:45 -08006473 public int getLastTouchSource() {
6474 return mLastTouchSource;
6475 }
6476
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006477 public void setDragFocus(View newDragTarget, DragEvent event) {
Vadim Tryshev45bee6b2016-09-19 11:00:37 -07006478 if (mCurrentDragView != newDragTarget && !View.sCascadedDragDrop) {
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006479 // Send EXITED and ENTERED notifications to the old and new drag focus views.
6480
6481 final float tx = event.mX;
6482 final float ty = event.mY;
6483 final int action = event.mAction;
Vadim Trysheva61efa42016-09-28 15:15:52 -07006484 final ClipData td = event.mClipData;
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006485 // Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED.
6486 event.mX = 0;
6487 event.mY = 0;
Vadim Trysheva61efa42016-09-28 15:15:52 -07006488 event.mClipData = null;
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006489
6490 if (mCurrentDragView != null) {
6491 event.mAction = DragEvent.ACTION_DRAG_EXITED;
6492 mCurrentDragView.callDragEventHandler(event);
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006493 }
6494
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006495 if (newDragTarget != null) {
6496 event.mAction = DragEvent.ACTION_DRAG_ENTERED;
6497 newDragTarget.callDragEventHandler(event);
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006498 }
6499
6500 event.mAction = action;
6501 event.mX = tx;
6502 event.mY = ty;
Vadim Trysheva61efa42016-09-28 15:15:52 -07006503 event.mClipData = td;
Christopher Tatea53146c2010-09-07 11:57:52 -07006504 }
Vadim Tryshevef128112016-09-16 14:05:53 -07006505
6506 mCurrentDragView = newDragTarget;
Christopher Tatea53146c2010-09-07 11:57:52 -07006507 }
6508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006509 private AudioManager getAudioManager() {
6510 if (mView == null) {
6511 throw new IllegalStateException("getAudioManager called when there is no mView");
6512 }
6513 if (mAudioManager == null) {
6514 mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
6515 }
6516 return mAudioManager;
6517 }
6518
Dake Gud9dbd272018-03-13 11:38:42 -07006519 private @Nullable AutofillManager getAutofillManager() {
6520 if (mView instanceof ViewGroup) {
6521 ViewGroup decorView = (ViewGroup) mView;
6522 if (decorView.getChildCount() > 0) {
6523 // We cannot use decorView's Context for querying AutofillManager: DecorView's
6524 // context is based on Application Context, it would allocate a different
6525 // AutofillManager instance.
6526 return decorView.getChildAt(0).getContext()
6527 .getSystemService(AutofillManager.class);
6528 }
6529 }
6530 return null;
6531 }
6532
6533 private boolean isAutofillUiShowing() {
6534 AutofillManager afm = getAutofillManager();
6535 if (afm == null) {
6536 return false;
6537 }
6538 return afm.isAutofillUiShowing();
6539 }
6540
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006541 public AccessibilityInteractionController getAccessibilityInteractionController() {
6542 if (mView == null) {
6543 throw new IllegalStateException("getAccessibilityInteractionController"
6544 + " called when there is no mView");
6545 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07006546 if (mAccessibilityInteractionController == null) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006547 mAccessibilityInteractionController = new AccessibilityInteractionController(this);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006548 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07006549 return mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006550 }
6551
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07006552 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
6553 boolean insetsPending) throws RemoteException {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006554
6555 float appScale = mAttachInfo.mApplicationScale;
Mitsuru Oshima3d914922009-05-13 22:29:15 -07006556 boolean restore = false;
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006557 if (params != null && mTranslator != null) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07006558 restore = true;
6559 params.backup();
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006560 mTranslator.translateWindowLayout(params);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07006561 }
Robert Carrc6d5af52018-02-26 17:46:00 -08006562
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006563 if (params != null) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006564 if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
Bryce Leef858b572017-06-29 14:03:33 -07006565
Robert Carrc6d5af52018-02-26 17:46:00 -08006566 if (mOrigWindowType != params.type) {
6567 // For compatibility with old apps, don't crash here.
6568 if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
6569 Slog.w(mTag, "Window type can not be changed after "
6570 + "the window is added; ignoring change of " + mView);
6571 params.type = mOrigWindowType;
6572 }
6573 }
Dianne Hackborn180c4842011-09-13 12:39:25 -07006574 }
Robert Carrc6d5af52018-02-26 17:46:00 -08006575
chaviwbe43ac82018-04-04 15:14:49 -07006576 long frameNumber = -1;
6577 if (mSurface.isValid()) {
6578 frameNumber = mSurface.getNextFrameNumber();
6579 }
6580
6581 int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params,
Dianne Hackborn189ee182010-12-02 21:48:53 -08006582 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
chaviwbe43ac82018-04-04 15:14:49 -07006583 (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
6584 insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006585 mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
Adrian Roos5c6b6222017-11-07 17:36:10 +01006586 mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout,
Andrii Kulian44607962017-03-16 11:06:24 -07006587 mPendingMergedConfiguration, mSurface);
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08006588
6589 mPendingAlwaysConsumeNavBar =
6590 (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR) != 0;
6591
Mitsuru Oshima3d914922009-05-13 22:29:15 -07006592 if (restore) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07006593 params.restore();
Mitsuru Oshima3d914922009-05-13 22:29:15 -07006594 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006595
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006596 if (mTranslator != null) {
6597 mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006598 mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006599 mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
6600 mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
Adrian Roosfa104232014-06-20 16:10:14 -07006601 mTranslator.translateRectInScreenToAppWindow(mPendingStableInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07006602 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07006603 return relayoutResult;
6604 }
Romain Guy8506ab42009-06-11 17:35:47 -07006605
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07006606 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006607 * {@inheritDoc}
6608 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07006609 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006610 public void playSoundEffect(int effectId) {
6611 checkThread();
6612
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07006613 try {
6614 final AudioManager audioManager = getAudioManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006615
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07006616 switch (effectId) {
6617 case SoundEffectConstants.CLICK:
6618 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
6619 return;
6620 case SoundEffectConstants.NAVIGATION_DOWN:
6621 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
6622 return;
6623 case SoundEffectConstants.NAVIGATION_LEFT:
6624 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
6625 return;
6626 case SoundEffectConstants.NAVIGATION_RIGHT:
6627 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
6628 return;
6629 case SoundEffectConstants.NAVIGATION_UP:
6630 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
6631 return;
6632 default:
6633 throw new IllegalArgumentException("unknown effect id " + effectId +
6634 " not defined in " + SoundEffectConstants.class.getCanonicalName());
6635 }
6636 } catch (IllegalStateException e) {
6637 // Exception thrown by getAudioManager() when mView is null
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006638 Log.e(mTag, "FATAL EXCEPTION when attempting to play sound effect: " + e);
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07006639 e.printStackTrace();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006640 }
6641 }
6642
6643 /**
6644 * {@inheritDoc}
6645 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07006646 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006647 public boolean performHapticFeedback(int effectId, boolean always) {
6648 try {
Jeff Brown98365d72012-08-19 20:30:52 -07006649 return mWindowSession.performHapticFeedback(mWindow, effectId, always);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006650 } catch (RemoteException e) {
6651 return false;
6652 }
6653 }
6654
6655 /**
6656 * {@inheritDoc}
6657 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07006658 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006659 public View focusSearch(View focused, int direction) {
6660 checkThread();
6661 if (!(mView instanceof ViewGroup)) {
6662 return null;
6663 }
6664 return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
6665 }
6666
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08006667 /**
6668 * {@inheritDoc}
6669 */
6670 @Override
Evan Rosky57223312017-02-08 14:42:45 -08006671 public View keyboardNavigationClusterSearch(View currentCluster,
6672 @FocusDirection int direction) {
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08006673 checkThread();
Vadim Tryshevb5ced222017-01-17 19:31:35 -08006674 return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
6675 mView, currentCluster, direction);
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08006676 }
6677
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006678 public void debug() {
6679 mView.debug();
6680 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006681
Jeff Brown5182c782013-10-15 20:31:52 -07006682 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
6683 String innerPrefix = prefix + " ";
6684 writer.print(prefix); writer.println("ViewRoot:");
6685 writer.print(innerPrefix); writer.print("mAdded="); writer.print(mAdded);
6686 writer.print(" mRemoved="); writer.println(mRemoved);
6687 writer.print(innerPrefix); writer.print("mConsumeBatchedInputScheduled=");
6688 writer.println(mConsumeBatchedInputScheduled);
Michael Wright9d744c72014-02-18 21:27:42 -08006689 writer.print(innerPrefix); writer.print("mConsumeBatchedInputImmediatelyScheduled=");
6690 writer.println(mConsumeBatchedInputImmediatelyScheduled);
Jeff Brown5182c782013-10-15 20:31:52 -07006691 writer.print(innerPrefix); writer.print("mPendingInputEventCount=");
6692 writer.println(mPendingInputEventCount);
6693 writer.print(innerPrefix); writer.print("mProcessInputEventsScheduled=");
6694 writer.println(mProcessInputEventsScheduled);
6695 writer.print(innerPrefix); writer.print("mTraversalScheduled=");
6696 writer.print(mTraversalScheduled);
Daniel Koulomzin087ae472015-12-16 17:52:25 -05006697 writer.print(innerPrefix); writer.print("mIsAmbientMode=");
6698 writer.print(mIsAmbientMode);
Jeff Brown5182c782013-10-15 20:31:52 -07006699 if (mTraversalScheduled) {
6700 writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
6701 } else {
6702 writer.println();
6703 }
6704 mFirstInputStage.dump(innerPrefix, writer);
6705
6706 mChoreographer.dump(prefix, writer);
6707
6708 writer.print(prefix); writer.println("View Hierarchy:");
6709 dumpViewHierarchy(innerPrefix, writer, mView);
6710 }
6711
6712 private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) {
6713 writer.print(prefix);
6714 if (view == null) {
6715 writer.println("null");
6716 return;
6717 }
6718 writer.println(view.toString());
6719 if (!(view instanceof ViewGroup)) {
6720 return;
6721 }
6722 ViewGroup grp = (ViewGroup)view;
6723 final int N = grp.getChildCount();
6724 if (N <= 0) {
6725 return;
6726 }
6727 prefix = prefix + " ";
6728 for (int i=0; i<N; i++) {
6729 dumpViewHierarchy(prefix, writer, grp.getChildAt(i));
6730 }
6731 }
6732
Romain Guy211370f2012-02-01 16:10:55 -08006733 public void dumpGfxInfo(int[] info) {
Romain Guy54ab3472012-06-14 12:52:53 -07006734 info[0] = info[1] = 0;
Romain Guy65b345f2011-07-27 18:51:50 -07006735 if (mView != null) {
6736 getGfxInfo(mView, info);
Romain Guy65b345f2011-07-27 18:51:50 -07006737 }
6738 }
6739
Romain Guya998dff2012-03-23 18:58:36 -07006740 private static void getGfxInfo(View view, int[] info) {
Chris Craik64a12e12014-03-28 18:12:12 -07006741 RenderNode renderNode = view.mRenderNode;
Romain Guy65b345f2011-07-27 18:51:50 -07006742 info[0]++;
Chris Craik64a12e12014-03-28 18:12:12 -07006743 if (renderNode != null) {
John Reckfe5e7b72014-05-23 17:42:28 -07006744 info[1] += renderNode.getDebugSize();
Romain Guy65b345f2011-07-27 18:51:50 -07006745 }
6746
6747 if (view instanceof ViewGroup) {
6748 ViewGroup group = (ViewGroup) view;
6749
6750 int count = group.getChildCount();
6751 for (int i = 0; i < count; i++) {
6752 getGfxInfo(group.getChildAt(i), info);
6753 }
6754 }
6755 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006756
Craig Mautner8f303ad2013-06-14 11:32:22 -07006757 /**
6758 * @param immediate True, do now if not in traversal. False, put on queue and do later.
6759 * @return True, request has been queued. False, request has been completed.
6760 */
6761 boolean die(boolean immediate) {
Craig Mautnerdf2390a2012-08-29 20:59:22 -07006762 // Make sure we do execute immediately if we are in the middle of a traversal or the damage
6763 // done by dispatchDetachedFromWindow will cause havoc on return.
6764 if (immediate && !mIsInTraversal) {
Dianne Hackborn94d69142009-09-28 22:14:42 -07006765 doDie();
Craig Mautner8f303ad2013-06-14 11:32:22 -07006766 return false;
Dianne Hackborn94d69142009-09-28 22:14:42 -07006767 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07006768
6769 if (!mIsDrawing) {
6770 destroyHardwareRenderer();
6771 } else {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006772 Log.e(mTag, "Attempting to destroy the window while drawing!\n" +
Craig Mautner8f303ad2013-06-14 11:32:22 -07006773 " window=" + this + ", title=" + mWindowAttributes.getTitle());
6774 }
6775 mHandler.sendEmptyMessage(MSG_DIE);
6776 return true;
Dianne Hackborn94d69142009-09-28 22:14:42 -07006777 }
6778
6779 void doDie() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006780 checkThread();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006781 if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006782 synchronized (this) {
Craig Mautner8f303ad2013-06-14 11:32:22 -07006783 if (mRemoved) {
6784 return;
6785 }
6786 mRemoved = true;
Romain Guy16260e72011-09-01 14:26:11 -07006787 if (mAdded) {
Romain Guy16260e72011-09-01 14:26:11 -07006788 dispatchDetachedFromWindow();
6789 }
6790
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006791 if (mAdded && !mFirst) {
Romain Guy29d89972010-09-22 16:10:57 -07006792 destroyHardwareRenderer();
6793
Romain Guyedbca122012-04-04 18:25:53 -07006794 if (mView != null) {
6795 int viewVisibility = mView.getVisibility();
6796 boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
6797 if (mWindowAttributesChanged || viewVisibilityChanged) {
6798 // If layout params have been changed, first give them
6799 // to the window manager to make sure it has the correct
6800 // animation info.
6801 try {
6802 if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
Jeff Brown98365d72012-08-19 20:30:52 -07006803 & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
6804 mWindowSession.finishDrawing(mWindow);
Romain Guyedbca122012-04-04 18:25:53 -07006805 }
6806 } catch (RemoteException e) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006807 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006808 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07006809
Romain Guyedbca122012-04-04 18:25:53 -07006810 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006811 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006812 }
Romain Guyedbca122012-04-04 18:25:53 -07006813
6814 mAdded = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006815 }
Craig Mautner05eb7302013-06-03 17:24:21 -07006816 WindowManagerGlobal.getInstance().doRemoveView(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006817 }
6818
Dianne Hackborn5fd21692011-06-07 14:09:47 -07006819 public void requestUpdateConfiguration(Configuration config) {
Jeff Browna175a5b2012-02-15 19:18:31 -08006820 Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
6821 mHandler.sendMessage(msg);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07006822 }
6823
Dianne Hackborna53de062012-05-08 18:53:51 -07006824 public void loadSystemProperties() {
Romain Guy5bb3c732012-11-29 17:52:58 -08006825 mHandler.post(new Runnable() {
6826 @Override
6827 public void run() {
6828 // Profiling
6829 mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false);
6830 profileRendering(mAttachInfo.mHasWindowFocus);
6831
6832 // Hardware rendering
Stan Iliev45faba52016-06-28 13:33:15 -04006833 if (mAttachInfo.mThreadedRenderer != null) {
6834 if (mAttachInfo.mThreadedRenderer.loadSystemProperties()) {
Romain Guy5bb3c732012-11-29 17:52:58 -08006835 invalidate();
6836 }
6837 }
6838
6839 // Layout debugging
Kiyoung Kim89052d92018-12-20 18:26:10 +09006840 boolean layout = DisplayProperties.debug_layout().orElse(false);
Romain Guy5bb3c732012-11-29 17:52:58 -08006841 if (layout != mAttachInfo.mDebugLayout) {
6842 mAttachInfo.mDebugLayout = layout;
6843 if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
6844 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
6845 }
6846 }
Dianne Hackborna53de062012-05-08 18:53:51 -07006847 }
Romain Guy5bb3c732012-11-29 17:52:58 -08006848 });
Dianne Hackborna53de062012-05-08 18:53:51 -07006849 }
6850
Romain Guy29d89972010-09-22 16:10:57 -07006851 private void destroyHardwareRenderer() {
Stan Iliev45faba52016-06-28 13:33:15 -04006852 ThreadedRenderer hardwareRenderer = mAttachInfo.mThreadedRenderer;
Romain Guya998dff2012-03-23 18:58:36 -07006853
6854 if (hardwareRenderer != null) {
6855 if (mView != null) {
6856 hardwareRenderer.destroyHardwareResources(mView);
6857 }
John Reckf47a5942014-06-30 16:20:04 -07006858 hardwareRenderer.destroy();
Romain Guya998dff2012-03-23 18:58:36 -07006859 hardwareRenderer.setRequested(false);
6860
Stan Iliev45faba52016-06-28 13:33:15 -04006861 mAttachInfo.mThreadedRenderer = null;
Chris Craikd36a81f2014-07-17 10:16:51 -07006862 mAttachInfo.mHardwareAccelerated = false;
Romain Guy29d89972010-09-22 16:10:57 -07006863 }
6864 }
6865
Mathew Inwoode5ad5982018-08-17 15:07:52 +01006866 @UnsupportedAppUsage
Andrii Kulian44607962017-03-16 11:06:24 -07006867 private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Filip Gruszczynski2217f612015-05-26 11:32:08 -07006868 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
Andrii Kulian44607962017-03-16 11:06:24 -07006869 MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
Adrian Roos5c6b6222017-11-07 17:36:10 +01006870 boolean alwaysConsumeNavBar, int displayId,
6871 DisplayCutout.ParcelableWrapper displayCutout) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006872 if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
Svetoslav Ganov758143e2012-08-06 16:40:27 -07006873 + " contentInsets=" + contentInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006874 + " visibleInsets=" + visibleInsets.toShortString()
Chong Zhangd153c4f2015-11-06 20:26:40 -08006875 + " reportDraw=" + reportDraw
6876 + " backDropFrame=" + backDropFrame);
Chong Zhangdcee1de2015-10-06 10:26:00 -07006877
6878 // Tell all listeners that we are resizing the window so that the chrome can get
6879 // updated as fast as possible on a separate thread,
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09006880 if (mDragResizing && mUseMTRenderer) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08006881 boolean fullscreen = frame.equals(backDropFrame);
Chong Zhangdcee1de2015-10-06 10:26:00 -07006882 synchronized (mWindowCallbacks) {
6883 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08006884 mWindowCallbacks.get(i).onWindowSizeIsChanging(backDropFrame, fullscreen,
6885 visibleInsets, stableInsets);
Chong Zhangdcee1de2015-10-06 10:26:00 -07006886 }
6887 }
6888 }
6889
Svetoslav Ganov758143e2012-08-06 16:40:27 -07006890 Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006891 if (mTranslator != null) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07006892 mTranslator.translateRectInScreenToAppWindow(frame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006893 mTranslator.translateRectInScreenToAppWindow(overscanInsets);
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07006894 mTranslator.translateRectInScreenToAppWindow(contentInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006895 mTranslator.translateRectInScreenToAppWindow(visibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07006896 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07006897 SomeArgs args = SomeArgs.obtain();
6898 final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
6899 args.arg1 = sameProcessCall ? new Rect(frame) : frame;
6900 args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets;
6901 args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
Andrii Kulian44607962017-03-16 11:06:24 -07006902 args.arg4 = sameProcessCall && mergedConfiguration != null
Wale Ogunwalecdc8ada2017-03-30 13:55:36 -07006903 ? new MergedConfiguration(mergedConfiguration) : mergedConfiguration;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006904 args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
Adrian Roosfa104232014-06-20 16:10:14 -07006905 args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
Filip Gruszczynski2217f612015-05-26 11:32:08 -07006906 args.arg7 = sameProcessCall ? new Rect(outsets) : outsets;
Jorim Jaggia7262a82015-11-03 15:15:40 +01006907 args.arg8 = sameProcessCall ? new Rect(backDropFrame) : backDropFrame;
Adrian Roos5c6b6222017-11-07 17:36:10 +01006908 args.arg9 = displayCutout.get(); // DisplayCutout is immutable.
Jorim Jaggia4a58ef2016-01-27 02:10:08 -08006909 args.argi1 = forceLayout ? 1 : 0;
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08006910 args.argi2 = alwaysConsumeNavBar ? 1 : 0;
Andrii Kulianb047b8b2017-02-08 18:38:26 -08006911 args.argi3 = displayId;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07006912 msg.obj = args;
Jeff Browna175a5b2012-02-15 19:18:31 -08006913 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006914 }
Chet Haase1f4786b2011-11-02 10:51:52 -07006915
Craig Mautner5702d4d2012-06-30 14:10:16 -07006916 public void dispatchMoved(int newX, int newY) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006917 if (DEBUG_LAYOUT) Log.v(mTag, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
Craig Mautner5702d4d2012-06-30 14:10:16 -07006918 if (mTranslator != null) {
6919 PointF point = new PointF(newX, newY);
6920 mTranslator.translatePointInScreenToAppWindow(point);
6921 newX = (int) (point.x + 0.5);
6922 newY = (int) (point.y + 0.5);
6923 }
6924 Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY);
6925 mHandler.sendMessage(msg);
6926 }
6927
Jeff Brown4952dfd2011-11-30 19:23:22 -08006928 /**
6929 * Represents a pending input event that is waiting in a queue.
6930 *
6931 * Input events are processed in serial order by the timestamp specified by
Romain Guy211370f2012-02-01 16:10:55 -08006932 * {@link InputEvent#getEventTimeNano()}. In general, the input dispatcher delivers
Jeff Brown4952dfd2011-11-30 19:23:22 -08006933 * one input event to the application at a time and waits for the application
6934 * to finish handling it before delivering the next one.
6935 *
6936 * However, because the application or IME can synthesize and inject multiple
6937 * key events at a time without going through the input dispatcher, we end up
6938 * needing a queue on the application's side.
6939 */
6940 private static final class QueuedInputEvent {
Jeff Brownf9e989d2013-04-04 23:04:03 -07006941 public static final int FLAG_DELIVER_POST_IME = 1 << 0;
6942 public static final int FLAG_DEFERRED = 1 << 1;
6943 public static final int FLAG_FINISHED = 1 << 2;
6944 public static final int FLAG_FINISHED_HANDLED = 1 << 3;
6945 public static final int FLAG_RESYNTHESIZED = 1 << 4;
Michael Wright899d7052014-04-23 17:23:39 -07006946 public static final int FLAG_UNHANDLED = 1 << 5;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006947
6948 public QueuedInputEvent mNext;
6949
6950 public InputEvent mEvent;
Jeff Brown32cbc38552011-12-01 14:01:49 -08006951 public InputEventReceiver mReceiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006952 public int mFlags;
Jeff Brownf9e989d2013-04-04 23:04:03 -07006953
6954 public boolean shouldSkipIme() {
6955 if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
6956 return true;
6957 }
6958 return mEvent instanceof MotionEvent
Prashant Malanifecbc672016-07-22 15:38:05 -07006959 && (mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
6960 || mEvent.isFromSource(InputDevice.SOURCE_ROTARY_ENCODER));
Jeff Brownf9e989d2013-04-04 23:04:03 -07006961 }
Michael Wright899d7052014-04-23 17:23:39 -07006962
6963 public boolean shouldSendToSynthesizer() {
6964 if ((mFlags & FLAG_UNHANDLED) != 0) {
6965 return true;
6966 }
6967
6968 return false;
6969 }
Michael Wright06a79252014-05-05 17:45:29 -07006970
6971 @Override
6972 public String toString() {
6973 StringBuilder sb = new StringBuilder("QueuedInputEvent{flags=");
6974 boolean hasPrevious = false;
6975 hasPrevious = flagToString("DELIVER_POST_IME", FLAG_DELIVER_POST_IME, hasPrevious, sb);
6976 hasPrevious = flagToString("DEFERRED", FLAG_DEFERRED, hasPrevious, sb);
6977 hasPrevious = flagToString("FINISHED", FLAG_FINISHED, hasPrevious, sb);
6978 hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb);
6979 hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb);
6980 hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb);
6981 if (!hasPrevious) {
6982 sb.append("0");
6983 }
6984 sb.append(", hasNextQueuedEvent=" + (mEvent != null ? "true" : "false"));
6985 sb.append(", hasInputEventReceiver=" + (mReceiver != null ? "true" : "false"));
6986 sb.append(", mEvent=" + mEvent + "}");
6987 return sb.toString();
6988 }
6989
6990 private boolean flagToString(String name, int flag,
6991 boolean hasPrevious, StringBuilder sb) {
6992 if ((mFlags & flag) != 0) {
6993 if (hasPrevious) {
6994 sb.append("|");
6995 }
6996 sb.append(name);
6997 return true;
6998 }
6999 return hasPrevious;
7000 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08007001 }
7002
7003 private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
Jeff Brown32cbc38552011-12-01 14:01:49 -08007004 InputEventReceiver receiver, int flags) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08007005 QueuedInputEvent q = mQueuedInputEventPool;
7006 if (q != null) {
7007 mQueuedInputEventPoolSize -= 1;
7008 mQueuedInputEventPool = q.mNext;
7009 q.mNext = null;
7010 } else {
7011 q = new QueuedInputEvent();
Jeff Brown46b9ac02010-04-22 18:58:52 -07007012 }
7013
Jeff Brown4952dfd2011-11-30 19:23:22 -08007014 q.mEvent = event;
Jeff Brown32cbc38552011-12-01 14:01:49 -08007015 q.mReceiver = receiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08007016 q.mFlags = flags;
Jeff Brown4952dfd2011-11-30 19:23:22 -08007017 return q;
7018 }
7019
7020 private void recycleQueuedInputEvent(QueuedInputEvent q) {
7021 q.mEvent = null;
Jeff Brown32cbc38552011-12-01 14:01:49 -08007022 q.mReceiver = null;
Jeff Brown4952dfd2011-11-30 19:23:22 -08007023
7024 if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
7025 mQueuedInputEventPoolSize += 1;
7026 q.mNext = mQueuedInputEventPool;
7027 mQueuedInputEventPool = q;
7028 }
7029 }
7030
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007031 @UnsupportedAppUsage
Jeff Brownf9261d22012-02-03 13:49:15 -08007032 void enqueueInputEvent(InputEvent event) {
7033 enqueueInputEvent(event, null, 0, false);
7034 }
7035
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007036 @UnsupportedAppUsage
Jeff Brown4952dfd2011-11-30 19:23:22 -08007037 void enqueueInputEvent(InputEvent event,
Jeff Brownf9261d22012-02-03 13:49:15 -08007038 InputEventReceiver receiver, int flags, boolean processImmediately) {
Michael Wright5bd69e62015-05-14 14:48:08 +01007039 adjustInputEventForCompatibility(event);
Jeff Brown32cbc38552011-12-01 14:01:49 -08007040 QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
Jeff Brown4952dfd2011-11-30 19:23:22 -08007041
Jeff Brown4952dfd2011-11-30 19:23:22 -08007042 // Always enqueue the input event in order, regardless of its time stamp.
7043 // We do this because the application or the IME may inject key events
7044 // in response to touch events and we want to ensure that the injected keys
7045 // are processed in the order they were received and we cannot trust that
7046 // the time stamp of injected events are monotonic.
Michael Wrightc8a7e542013-03-20 17:58:33 -07007047 QueuedInputEvent last = mPendingInputEventTail;
Jeff Brown4952dfd2011-11-30 19:23:22 -08007048 if (last == null) {
Michael Wrightc8a7e542013-03-20 17:58:33 -07007049 mPendingInputEventHead = q;
7050 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08007051 } else {
Jeff Brown4952dfd2011-11-30 19:23:22 -08007052 last.mNext = q;
Michael Wrightc8a7e542013-03-20 17:58:33 -07007053 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08007054 }
Michael Wright95ae9422013-03-14 10:58:50 -07007055 mPendingInputEventCount += 1;
7056 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
7057 mPendingInputEventCount);
Jeff Brown4952dfd2011-11-30 19:23:22 -08007058
Jeff Brownf9261d22012-02-03 13:49:15 -08007059 if (processImmediately) {
7060 doProcessInputEvents();
7061 } else {
7062 scheduleProcessInputEvents();
7063 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08007064 }
7065
7066 private void scheduleProcessInputEvents() {
Jeff Brown96e942d2011-11-30 19:55:01 -08007067 if (!mProcessInputEventsScheduled) {
7068 mProcessInputEventsScheduled = true;
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007069 Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
7070 msg.setAsynchronous(true);
7071 mHandler.sendMessage(msg);
Jeff Brown4952dfd2011-11-30 19:23:22 -08007072 }
7073 }
7074
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007075 void doProcessInputEvents() {
Jeff Brownf9e989d2013-04-04 23:04:03 -07007076 // Deliver all pending input events in the queue.
Michael Wrightc8a7e542013-03-20 17:58:33 -07007077 while (mPendingInputEventHead != null) {
7078 QueuedInputEvent q = mPendingInputEventHead;
7079 mPendingInputEventHead = q.mNext;
7080 if (mPendingInputEventHead == null) {
7081 mPendingInputEventTail = null;
7082 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08007083 q.mNext = null;
Jeff Brown29c0ed22013-01-14 13:50:37 -08007084
Michael Wright95ae9422013-03-14 10:58:50 -07007085 mPendingInputEventCount -= 1;
7086 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
7087 mPendingInputEventCount);
7088
John Reckba6adf62015-02-19 14:36:50 -08007089 long eventTime = q.mEvent.getEventTimeNano();
7090 long oldestEventTime = eventTime;
7091 if (q.mEvent instanceof MotionEvent) {
7092 MotionEvent me = (MotionEvent)q.mEvent;
7093 if (me.getHistorySize() > 0) {
7094 oldestEventTime = me.getHistoricalEventTimeNano(0);
7095 }
7096 }
7097 mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
7098
Jeff Brownf9e989d2013-04-04 23:04:03 -07007099 deliverInputEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08007100 }
7101
7102 // We are done processing all input events that we can process right now
7103 // so we can clear the pending flag immediately.
Jeff Brown96e942d2011-11-30 19:55:01 -08007104 if (mProcessInputEventsScheduled) {
7105 mProcessInputEventsScheduled = false;
Jeff Browna175a5b2012-02-15 19:18:31 -08007106 mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
Jeff Brown4952dfd2011-11-30 19:23:22 -08007107 }
7108 }
7109
Jeff Brownf9e989d2013-04-04 23:04:03 -07007110 private void deliverInputEvent(QueuedInputEvent q) {
Michael Wrightd2c3adc2014-02-18 22:50:50 -08007111 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
7112 q.mEvent.getSequenceNumber());
7113 if (mInputEventConsistencyVerifier != null) {
7114 mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
7115 }
Michael Wrightc8a7e542013-03-20 17:58:33 -07007116
Michael Wright899d7052014-04-23 17:23:39 -07007117 InputStage stage;
7118 if (q.shouldSendToSynthesizer()) {
7119 stage = mSyntheticInputStage;
7120 } else {
7121 stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
7122 }
7123
Evan Roskycd80e612018-05-17 17:46:09 -07007124 if (q.mEvent instanceof KeyEvent) {
7125 mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
7126 }
7127
Michael Wrightd2c3adc2014-02-18 22:50:50 -08007128 if (stage != null) {
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08007129 handleWindowFocusChanged();
Michael Wrightd2c3adc2014-02-18 22:50:50 -08007130 stage.deliver(q);
7131 } else {
7132 finishInputEvent(q);
Michael Wrightbf020962013-03-28 17:27:50 -07007133 }
Michael Wrightbf020962013-03-28 17:27:50 -07007134 }
7135
Jeff Brownf9e989d2013-04-04 23:04:03 -07007136 private void finishInputEvent(QueuedInputEvent q) {
Michael Wrightd2c3adc2014-02-18 22:50:50 -08007137 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
7138 q.mEvent.getSequenceNumber());
Michael Wright9d744c72014-02-18 21:27:42 -08007139
Jeff Brown32cbc38552011-12-01 14:01:49 -08007140 if (q.mReceiver != null) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07007141 boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
Jeff Brown32cbc38552011-12-01 14:01:49 -08007142 q.mReceiver.finishInputEvent(q.mEvent, handled);
Jeff Brown92cc2d82011-12-02 01:19:47 -08007143 } else {
7144 q.mEvent.recycleIfNeededAfterDispatch();
Jeff Brown4952dfd2011-11-30 19:23:22 -08007145 }
7146
7147 recycleQueuedInputEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08007148 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08007149
Michael Wright5bd69e62015-05-14 14:48:08 +01007150 private void adjustInputEventForCompatibility(InputEvent e) {
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07007151 if (mTargetSdkVersion < Build.VERSION_CODES.M && e instanceof MotionEvent) {
Michael Wright5bd69e62015-05-14 14:48:08 +01007152 MotionEvent motion = (MotionEvent) e;
7153 final int mask =
7154 MotionEvent.BUTTON_STYLUS_PRIMARY | MotionEvent.BUTTON_STYLUS_SECONDARY;
7155 final int buttonState = motion.getButtonState();
7156 final int compatButtonState = (buttonState & mask) >> 4;
7157 if (compatButtonState != 0) {
7158 motion.setButtonState(buttonState | compatButtonState);
7159 }
7160 }
7161 }
7162
Jeff Brownf9e989d2013-04-04 23:04:03 -07007163 static boolean isTerminalInputEvent(InputEvent event) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08007164 if (event instanceof KeyEvent) {
7165 final KeyEvent keyEvent = (KeyEvent)event;
7166 return keyEvent.getAction() == KeyEvent.ACTION_UP;
7167 } else {
7168 final MotionEvent motionEvent = (MotionEvent)event;
7169 final int action = motionEvent.getAction();
7170 return action == MotionEvent.ACTION_UP
7171 || action == MotionEvent.ACTION_CANCEL
7172 || action == MotionEvent.ACTION_HOVER_EXIT;
Jeff Brown4952dfd2011-11-30 19:23:22 -08007173 }
7174 }
7175
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007176 void scheduleConsumeBatchedInput() {
7177 if (!mConsumeBatchedInputScheduled) {
7178 mConsumeBatchedInputScheduled = true;
7179 mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
7180 mConsumedBatchedInputRunnable, null);
Jeff Brown4a06c802012-02-15 15:06:01 -08007181 }
7182 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007183
7184 void unscheduleConsumeBatchedInput() {
7185 if (mConsumeBatchedInputScheduled) {
7186 mConsumeBatchedInputScheduled = false;
7187 mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT,
7188 mConsumedBatchedInputRunnable, null);
7189 }
7190 }
7191
Michael Wright9d744c72014-02-18 21:27:42 -08007192 void scheduleConsumeBatchedInputImmediately() {
7193 if (!mConsumeBatchedInputImmediatelyScheduled) {
7194 unscheduleConsumeBatchedInput();
7195 mConsumeBatchedInputImmediatelyScheduled = true;
7196 mHandler.post(mConsumeBatchedInputImmediatelyRunnable);
7197 }
7198 }
7199
Jeff Brown771526c2012-04-27 15:13:25 -07007200 void doConsumeBatchedInput(long frameTimeNanos) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007201 if (mConsumeBatchedInputScheduled) {
7202 mConsumeBatchedInputScheduled = false;
Jeff Brown330314c2012-04-27 02:20:22 -07007203 if (mInputEventReceiver != null) {
Michael Wright9d744c72014-02-18 21:27:42 -08007204 if (mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos)
7205 && frameTimeNanos != -1) {
Michael Wright62ce65d2013-10-25 14:50:36 -07007206 // If we consumed a batch here, we want to go ahead and schedule the
7207 // consumption of batched input events on the next frame. Otherwise, we would
7208 // wait until we have more input events pending and might get starved by other
Michael Wright9d744c72014-02-18 21:27:42 -08007209 // things occurring in the process. If the frame time is -1, however, then
7210 // we're in a non-batching mode, so there's no need to schedule this.
Michael Wright62ce65d2013-10-25 14:50:36 -07007211 scheduleConsumeBatchedInput();
7212 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007213 }
Jeff Brown330314c2012-04-27 02:20:22 -07007214 doProcessInputEvents();
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007215 }
7216 }
7217
7218 final class TraversalRunnable implements Runnable {
7219 @Override
7220 public void run() {
7221 doTraversal();
7222 }
7223 }
7224 final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
Jeff Brown4a06c802012-02-15 15:06:01 -08007225
Jeff Brown32cbc38552011-12-01 14:01:49 -08007226 final class WindowInputEventReceiver extends InputEventReceiver {
7227 public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
7228 super(inputChannel, looper);
Jeff Brown46b9ac02010-04-22 18:58:52 -07007229 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08007230
7231 @Override
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -07007232 public void onInputEvent(InputEvent event, int displayId) {
Jeff Brownf9261d22012-02-03 13:49:15 -08007233 enqueueInputEvent(event, this, 0, true);
Jeff Brown32cbc38552011-12-01 14:01:49 -08007234 }
Jeff Brown072ec962012-02-07 14:46:57 -08007235
7236 @Override
7237 public void onBatchedInputEventPending() {
Michael Wright9d744c72014-02-18 21:27:42 -08007238 if (mUnbufferedInputDispatch) {
7239 super.onBatchedInputEventPending();
7240 } else {
7241 scheduleConsumeBatchedInput();
7242 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007243 }
7244
7245 @Override
7246 public void dispose() {
7247 unscheduleConsumeBatchedInput();
7248 super.dispose();
Jeff Brown072ec962012-02-07 14:46:57 -08007249 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08007250 }
7251 WindowInputEventReceiver mInputEventReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007252
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007253 final class ConsumeBatchedInputRunnable implements Runnable {
7254 @Override
7255 public void run() {
Jeff Brown771526c2012-04-27 15:13:25 -07007256 doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007257 }
7258 }
7259 final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =
7260 new ConsumeBatchedInputRunnable();
7261 boolean mConsumeBatchedInputScheduled;
7262
Michael Wright9d744c72014-02-18 21:27:42 -08007263 final class ConsumeBatchedInputImmediatelyRunnable implements Runnable {
7264 @Override
7265 public void run() {
7266 doConsumeBatchedInput(-1);
7267 }
7268 }
7269 final ConsumeBatchedInputImmediatelyRunnable mConsumeBatchedInputImmediatelyRunnable =
7270 new ConsumeBatchedInputImmediatelyRunnable();
7271 boolean mConsumeBatchedInputImmediatelyScheduled;
7272
Jeff Brown6cb7b462012-03-05 13:21:17 -08007273 final class InvalidateOnAnimationRunnable implements Runnable {
7274 private boolean mPosted;
Igor Murashkina86ab6402013-08-30 12:58:36 -07007275 private final ArrayList<View> mViews = new ArrayList<View>();
7276 private final ArrayList<AttachInfo.InvalidateInfo> mViewRects =
Jeff Brown6cb7b462012-03-05 13:21:17 -08007277 new ArrayList<AttachInfo.InvalidateInfo>();
7278 private View[] mTempViews;
7279 private AttachInfo.InvalidateInfo[] mTempViewRects;
7280
7281 public void addView(View view) {
7282 synchronized (this) {
7283 mViews.add(view);
7284 postIfNeededLocked();
7285 }
7286 }
7287
7288 public void addViewRect(AttachInfo.InvalidateInfo info) {
7289 synchronized (this) {
7290 mViewRects.add(info);
7291 postIfNeededLocked();
7292 }
7293 }
7294
7295 public void removeView(View view) {
7296 synchronized (this) {
7297 mViews.remove(view);
7298
7299 for (int i = mViewRects.size(); i-- > 0; ) {
7300 AttachInfo.InvalidateInfo info = mViewRects.get(i);
7301 if (info.target == view) {
7302 mViewRects.remove(i);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08007303 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08007304 }
7305 }
7306
7307 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007308 mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08007309 mPosted = false;
7310 }
7311 }
7312 }
7313
7314 @Override
7315 public void run() {
7316 final int viewCount;
7317 final int viewRectCount;
7318 synchronized (this) {
7319 mPosted = false;
7320
7321 viewCount = mViews.size();
7322 if (viewCount != 0) {
7323 mTempViews = mViews.toArray(mTempViews != null
7324 ? mTempViews : new View[viewCount]);
7325 mViews.clear();
7326 }
7327
7328 viewRectCount = mViewRects.size();
7329 if (viewRectCount != 0) {
7330 mTempViewRects = mViewRects.toArray(mTempViewRects != null
7331 ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]);
7332 mViewRects.clear();
7333 }
7334 }
7335
7336 for (int i = 0; i < viewCount; i++) {
7337 mTempViews[i].invalidate();
Adam Powell3e3c4ee2012-05-16 17:34:21 -07007338 mTempViews[i] = null;
Jeff Brown6cb7b462012-03-05 13:21:17 -08007339 }
7340
7341 for (int i = 0; i < viewRectCount; i++) {
7342 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
7343 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08007344 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08007345 }
7346 }
7347
7348 private void postIfNeededLocked() {
7349 if (!mPosted) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007350 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08007351 mPosted = true;
7352 }
7353 }
7354 }
7355 final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
7356 new InvalidateOnAnimationRunnable();
7357
Jeff Browna175a5b2012-02-15 19:18:31 -08007358 public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
7359 Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
7360 mHandler.sendMessageDelayed(msg, delayMilliseconds);
7361 }
7362
Jeff Browna175a5b2012-02-15 19:18:31 -08007363 public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
7364 long delayMilliseconds) {
7365 final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
7366 mHandler.sendMessageDelayed(msg, delayMilliseconds);
7367 }
7368
Jeff Brown6cb7b462012-03-05 13:21:17 -08007369 public void dispatchInvalidateOnAnimation(View view) {
7370 mInvalidateOnAnimationRunnable.addView(view);
7371 }
7372
7373 public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) {
7374 mInvalidateOnAnimationRunnable.addViewRect(info);
7375 }
7376
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007377 @UnsupportedAppUsage
Jeff Brown6cb7b462012-03-05 13:21:17 -08007378 public void cancelInvalidate(View view) {
7379 mHandler.removeMessages(MSG_INVALIDATE, view);
7380 // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning
7381 // them to the pool
7382 mHandler.removeMessages(MSG_INVALIDATE_RECT, view);
7383 mInvalidateOnAnimationRunnable.removeView(view);
7384 }
7385
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007386 @UnsupportedAppUsage
keunyoung30f420f2013-08-02 14:23:10 -07007387 public void dispatchInputEvent(InputEvent event) {
Jae Seo6a6059a2014-04-17 21:35:29 -07007388 dispatchInputEvent(event, null);
7389 }
7390
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007391 @UnsupportedAppUsage
Jae Seo6a6059a2014-04-17 21:35:29 -07007392 public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
7393 SomeArgs args = SomeArgs.obtain();
7394 args.arg1 = event;
7395 args.arg2 = receiver;
7396 Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
Jeff Browne0dbd002012-02-15 19:34:58 -08007397 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08007398 mHandler.sendMessage(msg);
7399 }
7400
Michael Wright899d7052014-04-23 17:23:39 -07007401 public void synthesizeInputEvent(InputEvent event) {
7402 Message msg = mHandler.obtainMessage(MSG_SYNTHESIZE_INPUT_EVENT, event);
7403 msg.setAsynchronous(true);
7404 mHandler.sendMessage(msg);
7405 }
7406
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007407 @UnsupportedAppUsage
Jeff Browna175a5b2012-02-15 19:18:31 -08007408 public void dispatchKeyFromIme(KeyEvent event) {
7409 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
Jeff Browne0dbd002012-02-15 19:34:58 -08007410 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08007411 mHandler.sendMessage(msg);
Jeff Browncb1404e2011-01-15 18:14:15 -08007412 }
7413
Dake Gu6a20a192018-02-08 12:09:30 -08007414 public void dispatchKeyFromAutofill(KeyEvent event) {
7415 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_AUTOFILL, event);
7416 msg.setAsynchronous(true);
7417 mHandler.sendMessage(msg);
7418 }
7419
Michael Wright899d7052014-04-23 17:23:39 -07007420 /**
7421 * Reinject unhandled {@link InputEvent}s in order to synthesize fallbacks events.
7422 *
7423 * Note that it is the responsibility of the caller of this API to recycle the InputEvent it
7424 * passes in.
7425 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007426 @UnsupportedAppUsage
Michael Wright3da28342014-04-22 17:00:11 -07007427 public void dispatchUnhandledInputEvent(InputEvent event) {
Michael Wright899d7052014-04-23 17:23:39 -07007428 if (event instanceof MotionEvent) {
7429 event = MotionEvent.obtain((MotionEvent) event);
Michael Wright3da28342014-04-22 17:00:11 -07007430 }
Michael Wright899d7052014-04-23 17:23:39 -07007431 synthesizeInputEvent(event);
Michael Wright3da28342014-04-22 17:00:11 -07007432 }
7433
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007434 public void dispatchAppVisibility(boolean visible) {
Jeff Browna175a5b2012-02-15 19:18:31 -08007435 Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007436 msg.arg1 = visible ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08007437 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007438 }
7439
7440 public void dispatchGetNewSurface() {
Jeff Browna175a5b2012-02-15 19:18:31 -08007441 Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
7442 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007443 }
7444
7445 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08007446 synchronized (this) {
Dianne Hackborn011944c2017-12-15 15:44:55 -08007447 mWindowFocusChanged = true;
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08007448 mUpcomingWindowFocus = hasFocus;
7449 mUpcomingInTouchMode = inTouchMode;
7450 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007451 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08007452 msg.what = MSG_WINDOW_FOCUS_CHANGED;
Jeff Browna175a5b2012-02-15 19:18:31 -08007453 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007454 }
7455
Craig Mautner9c795042014-10-28 19:59:59 -07007456 public void dispatchWindowShown() {
7457 mHandler.sendEmptyMessage(MSG_DISPATCH_WINDOW_SHOWN);
7458 }
7459
Dianne Hackbornffa42482009-09-23 22:20:11 -07007460 public void dispatchCloseSystemDialogs(String reason) {
7461 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08007462 msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
Dianne Hackbornffa42482009-09-23 22:20:11 -07007463 msg.obj = reason;
Jeff Browna175a5b2012-02-15 19:18:31 -08007464 mHandler.sendMessage(msg);
Dianne Hackbornffa42482009-09-23 22:20:11 -07007465 }
Christopher Tatea53146c2010-09-07 11:57:52 -07007466
7467 public void dispatchDragEvent(DragEvent event) {
Chris Tate91e9bb32010-10-12 12:58:43 -07007468 final int what;
7469 if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
Jeff Browna175a5b2012-02-15 19:18:31 -08007470 what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
7471 mHandler.removeMessages(what);
Chris Tate91e9bb32010-10-12 12:58:43 -07007472 } else {
Jeff Browna175a5b2012-02-15 19:18:31 -08007473 what = MSG_DISPATCH_DRAG_EVENT;
Chris Tate91e9bb32010-10-12 12:58:43 -07007474 }
Jeff Browna175a5b2012-02-15 19:18:31 -08007475 Message msg = mHandler.obtainMessage(what, event);
7476 mHandler.sendMessage(msg);
Christopher Tatea53146c2010-09-07 11:57:52 -07007477 }
7478
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08007479 public void updatePointerIcon(float x, float y) {
7480 final int what = MSG_UPDATE_POINTER_ICON;
7481 mHandler.removeMessages(what);
7482 final long now = SystemClock.uptimeMillis();
7483 final MotionEvent event = MotionEvent.obtain(
7484 0, now, MotionEvent.ACTION_HOVER_MOVE, x, y, 0);
7485 Message msg = mHandler.obtainMessage(what, event);
7486 mHandler.sendMessage(msg);
7487 }
7488
Dianne Hackborn9a230e02011-10-06 11:51:27 -07007489 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
7490 int localValue, int localChanges) {
7491 SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
7492 args.seq = seq;
7493 args.globalVisibility = globalVisibility;
7494 args.localValue = localValue;
7495 args.localChanges = localChanges;
Jeff Browna175a5b2012-02-15 19:18:31 -08007496 mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
7497 }
7498
7499 public void dispatchCheckFocus() {
7500 if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
7501 // This will result in a call to checkFocus() below.
7502 mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
7503 }
Joe Onorato664644d2011-01-23 17:53:23 -08007504 }
7505
Clara Bayarrifcd7e802016-03-10 12:58:18 +00007506 public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
7507 mHandler.obtainMessage(
7508 MSG_REQUEST_KEYBOARD_SHORTCUTS, deviceId, 0, receiver).sendToTarget();
Clara Bayarri75e09792015-07-29 16:20:40 +01007509 }
7510
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08007511 public void dispatchPointerCaptureChanged(boolean on) {
7512 final int what = MSG_POINTER_CAPTURE_CHANGED;
7513 mHandler.removeMessages(what);
7514 Message msg = mHandler.obtainMessage(what);
7515 msg.arg1 = on ? 1 : 0;
7516 mHandler.sendMessage(msg);
7517 }
7518
svetoslavganov75986cf2009-05-14 22:28:01 -07007519 /**
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07007520 * Post a callback to send a
7521 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
Svetoslav Ganova0156172011-06-26 17:55:44 -07007522 * This event is send at most once every
7523 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07007524 */
Alan Viverette77e9a282013-09-12 17:16:09 -07007525 private void postSendWindowContentChangedCallback(View source, int changeType) {
Eugene Susla72c510f2018-01-23 21:12:11 +00007526 if (mSendWindowContentChangedAccessibilityEvent == null) {
7527 mSendWindowContentChangedAccessibilityEvent =
7528 new SendWindowContentChangedAccessibilityEvent();
7529 }
7530 mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07007531 }
7532
7533 /**
7534 * Remove a posted callback to send a
7535 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
7536 */
7537 private void removeSendWindowContentChangedCallback() {
Eugene Susla72c510f2018-01-23 21:12:11 +00007538 if (mSendWindowContentChangedAccessibilityEvent != null) {
7539 mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07007540 }
7541 }
7542
Igor Murashkina86ab6402013-08-30 12:58:36 -07007543 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007544 public boolean showContextMenuForChild(View originalView) {
7545 return false;
7546 }
7547
Igor Murashkina86ab6402013-08-30 12:58:36 -07007548 @Override
Oren Blasberged391262015-09-01 12:12:51 -07007549 public boolean showContextMenuForChild(View originalView, float x, float y) {
7550 return false;
7551 }
7552
7553 @Override
Adam Powell6e346362010-07-23 10:18:23 -07007554 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
7555 return null;
7556 }
7557
Igor Murashkina86ab6402013-08-30 12:58:36 -07007558 @Override
Clara Bayarri4423d912015-03-02 19:42:48 +00007559 public ActionMode startActionModeForChild(
7560 View originalView, ActionMode.Callback callback, int type) {
7561 return null;
7562 }
7563
7564 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007565 public void createContextMenu(ContextMenu menu) {
7566 }
7567
Igor Murashkina86ab6402013-08-30 12:58:36 -07007568 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007569 public void childDrawableStateChanged(View child) {
7570 }
7571
Igor Murashkina86ab6402013-08-30 12:58:36 -07007572 @Override
Svetoslav Ganov736c2752011-04-22 18:30:36 -07007573 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
George Mount41725de2015-04-09 08:23:05 -07007574 if (mView == null || mStopped || mPausedForTransition) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -07007575 return false;
7576 }
Eugene Suslaccce5c92017-05-22 13:14:57 -07007577
Eugene Susla72c510f2018-01-23 21:12:11 +00007578 // Immediately flush pending content changed event (if any) to preserve event order
7579 if (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
7580 && mSendWindowContentChangedAccessibilityEvent != null
7581 && mSendWindowContentChangedAccessibilityEvent.mSource != null) {
7582 mSendWindowContentChangedAccessibilityEvent.removeCallbacksAndRun();
7583 }
Eugene Suslaccce5c92017-05-22 13:14:57 -07007584
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07007585 // Intercept accessibility focus events fired by virtual nodes to keep
7586 // track of accessibility focus position in such nodes.
Svetoslav Ganov791fd312012-05-14 15:12:30 -07007587 final int eventType = event.getEventType();
7588 switch (eventType) {
7589 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07007590 final long sourceNodeId = event.getSourceNodeId();
7591 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
7592 sourceNodeId);
7593 View source = mView.findViewByAccessibilityId(accessibilityViewId);
7594 if (source != null) {
7595 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
7596 if (provider != null) {
Svetoslavb3ba1d42014-09-26 15:20:40 -07007597 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
7598 sourceNodeId);
7599 final AccessibilityNodeInfo node;
Phil Weaverf00cd142017-03-03 13:44:00 -08007600 node = provider.createAccessibilityNodeInfo(virtualNodeId);
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07007601 setAccessibilityFocus(source, node);
7602 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07007603 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07007604 } break;
7605 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07007606 final long sourceNodeId = event.getSourceNodeId();
7607 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
7608 sourceNodeId);
7609 View source = mView.findViewByAccessibilityId(accessibilityViewId);
7610 if (source != null) {
7611 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
7612 if (provider != null) {
7613 setAccessibilityFocus(null, null);
7614 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07007615 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07007616 } break;
Svetoslavf0c758b2014-09-03 17:47:37 -07007617
7618
7619 case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: {
Alan Viverette34457f52015-03-25 13:09:20 -07007620 handleWindowContentChangedEvent(event);
Svetoslavf0c758b2014-09-03 17:47:37 -07007621 } break;
Svetoslav Ganov791fd312012-05-14 15:12:30 -07007622 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007623 mAccessibilityManager.sendAccessibilityEvent(event);
Svetoslav Ganov736c2752011-04-22 18:30:36 -07007624 return true;
7625 }
7626
Alan Viverette34457f52015-03-25 13:09:20 -07007627 /**
7628 * Updates the focused virtual view, when necessary, in response to a
7629 * content changed event.
7630 * <p>
7631 * This is necessary to get updated bounds after a position change.
7632 *
7633 * @param event an accessibility event of type
7634 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}
7635 */
7636 private void handleWindowContentChangedEvent(AccessibilityEvent event) {
Alan Viverette25acc7e2015-05-19 11:32:08 -07007637 final View focusedHost = mAccessibilityFocusedHost;
7638 if (focusedHost == null || mAccessibilityFocusedVirtualView == null) {
7639 // No virtual view focused, nothing to do here.
Alan Viverette34457f52015-03-25 13:09:20 -07007640 return;
7641 }
7642
Alan Viverette25acc7e2015-05-19 11:32:08 -07007643 final AccessibilityNodeProvider provider = focusedHost.getAccessibilityNodeProvider();
Alan Viverette34457f52015-03-25 13:09:20 -07007644 if (provider == null) {
Alan Viverette25acc7e2015-05-19 11:32:08 -07007645 // Error state: virtual view with no provider. Clear focus.
7646 mAccessibilityFocusedHost = null;
7647 mAccessibilityFocusedVirtualView = null;
Phil Weavere37cfab2016-04-07 21:01:57 -07007648 focusedHost.clearAccessibilityFocusNoCallbacks(0);
Alan Viverette34457f52015-03-25 13:09:20 -07007649 return;
7650 }
7651
7652 // We only care about change types that may affect the bounds of the
7653 // focused virtual view.
7654 final int changes = event.getContentChangeTypes();
7655 if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) == 0
7656 && changes != AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) {
7657 return;
7658 }
7659
7660 final long eventSourceNodeId = event.getSourceNodeId();
7661 final int changedViewId = AccessibilityNodeInfo.getAccessibilityViewId(eventSourceNodeId);
7662
7663 // Search up the tree for subtree containment.
7664 boolean hostInSubtree = false;
7665 View root = mAccessibilityFocusedHost;
7666 while (root != null && !hostInSubtree) {
7667 if (changedViewId == root.getAccessibilityViewId()) {
7668 hostInSubtree = true;
7669 } else {
7670 final ViewParent parent = root.getParent();
7671 if (parent instanceof View) {
7672 root = (View) parent;
7673 } else {
7674 root = null;
7675 }
7676 }
7677 }
7678
7679 // We care only about changes in subtrees containing the host view.
7680 if (!hostInSubtree) {
7681 return;
7682 }
7683
7684 final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId();
7685 int focusedChildId = AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId);
Alan Viverette34457f52015-03-25 13:09:20 -07007686
7687 // Refresh the node for the focused virtual view.
Alan Viverettea7ea65e2015-05-15 11:30:21 -07007688 final Rect oldBounds = mTempRect;
7689 mAccessibilityFocusedVirtualView.getBoundsInScreen(oldBounds);
Alan Viverette34457f52015-03-25 13:09:20 -07007690 mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo(focusedChildId);
Alan Viverette25acc7e2015-05-19 11:32:08 -07007691 if (mAccessibilityFocusedVirtualView == null) {
7692 // Error state: The node no longer exists. Clear focus.
7693 mAccessibilityFocusedHost = null;
Phil Weavere37cfab2016-04-07 21:01:57 -07007694 focusedHost.clearAccessibilityFocusNoCallbacks(0);
Alan Viverette25acc7e2015-05-19 11:32:08 -07007695
7696 // This will probably fail, but try to keep the provider's internal
7697 // state consistent by clearing focus.
7698 provider.performAction(focusedChildId,
7699 AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(), null);
Alan Viverettea7ea65e2015-05-15 11:30:21 -07007700 invalidateRectOnScreen(oldBounds);
Alan Viverette25acc7e2015-05-19 11:32:08 -07007701 } else {
7702 // The node was refreshed, invalidate bounds if necessary.
7703 final Rect newBounds = mAccessibilityFocusedVirtualView.getBoundsInScreen();
7704 if (!oldBounds.equals(newBounds)) {
7705 oldBounds.union(newBounds);
7706 invalidateRectOnScreen(oldBounds);
7707 }
Alan Viverettea7ea65e2015-05-15 11:30:21 -07007708 }
Alan Viverette34457f52015-03-25 13:09:20 -07007709 }
7710
Svetoslav Ganov42138042012-03-20 11:51:39 -07007711 @Override
Alan Viverette77e9a282013-09-12 17:16:09 -07007712 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
Phil Weaver63e45032017-05-11 10:54:37 -07007713 postSendWindowContentChangedCallback(Preconditions.checkNotNull(source), changeType);
Svetoslav Ganov42138042012-03-20 11:51:39 -07007714 }
7715
Fabrice Di Meglio9dd4c5c2013-02-08 18:15:07 -08007716 @Override
7717 public boolean canResolveLayoutDirection() {
7718 return true;
7719 }
7720
7721 @Override
7722 public boolean isLayoutDirectionResolved() {
7723 return true;
7724 }
7725
7726 @Override
7727 public int getLayoutDirection() {
7728 return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT;
7729 }
7730
7731 @Override
7732 public boolean canResolveTextDirection() {
7733 return true;
7734 }
7735
7736 @Override
7737 public boolean isTextDirectionResolved() {
7738 return true;
7739 }
7740
7741 @Override
7742 public int getTextDirection() {
7743 return View.TEXT_DIRECTION_RESOLVED_DEFAULT;
7744 }
7745
7746 @Override
7747 public boolean canResolveTextAlignment() {
7748 return true;
7749 }
7750
7751 @Override
7752 public boolean isTextAlignmentResolved() {
7753 return true;
7754 }
7755
7756 @Override
7757 public int getTextAlignment() {
7758 return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT;
7759 }
7760
Eugene Susla72c510f2018-01-23 21:12:11 +00007761 private View getCommonPredecessor(View first, View second) {
7762 if (mTempHashSet == null) {
7763 mTempHashSet = new HashSet<View>();
7764 }
7765 HashSet<View> seen = mTempHashSet;
7766 seen.clear();
7767 View firstCurrent = first;
7768 while (firstCurrent != null) {
7769 seen.add(firstCurrent);
7770 ViewParent firstCurrentParent = firstCurrent.mParent;
7771 if (firstCurrentParent instanceof View) {
7772 firstCurrent = (View) firstCurrentParent;
7773 } else {
7774 firstCurrent = null;
7775 }
7776 }
7777 View secondCurrent = second;
7778 while (secondCurrent != null) {
7779 if (seen.contains(secondCurrent)) {
7780 seen.clear();
7781 return secondCurrent;
7782 }
7783 ViewParent secondCurrentParent = secondCurrent.mParent;
7784 if (secondCurrentParent instanceof View) {
7785 secondCurrent = (View) secondCurrentParent;
7786 } else {
7787 secondCurrent = null;
7788 }
7789 }
7790 seen.clear();
7791 return null;
7792 }
7793
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007794 void checkThread() {
7795 if (mThread != Thread.currentThread()) {
7796 throw new CalledFromWrongThreadException(
7797 "Only the original thread that created a view hierarchy can touch its views.");
7798 }
7799 }
7800
Igor Murashkina86ab6402013-08-30 12:58:36 -07007801 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007802 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Joe Onoratoc6cc0f82011-04-12 11:53:13 -07007803 // ViewAncestor never intercepts touch event, so this can be a no-op
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007804 }
7805
Igor Murashkina86ab6402013-08-30 12:58:36 -07007806 @Override
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07007807 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
Yigit Boyard62d5e92016-01-19 18:56:20 -08007808 if (rectangle == null) {
7809 return scrollToRectOrFocus(null, immediate);
7810 }
7811 rectangle.offset(child.getLeft() - child.getScrollX(),
7812 child.getTop() - child.getScrollY());
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07007813 final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
Yigit Boyard62d5e92016-01-19 18:56:20 -08007814 mTempRect.set(rectangle);
7815 mTempRect.offset(0, -mCurScrollY);
7816 mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
7817 try {
7818 mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect);
7819 } catch (RemoteException re) {
7820 /* ignore */
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07007821 }
7822 return scrolled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007823 }
Romain Guy8506ab42009-06-11 17:35:47 -07007824
Igor Murashkina86ab6402013-08-30 12:58:36 -07007825 @Override
Adam Powell539ee872012-02-03 19:00:49 -08007826 public void childHasTransientStateChanged(View child, boolean hasTransientState) {
7827 // Do nothing.
7828 }
7829
Adam Powell10ba2772014-04-15 09:46:51 -07007830 @Override
7831 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
7832 return false;
7833 }
7834
7835 @Override
7836 public void onStopNestedScroll(View target) {
7837 }
7838
7839 @Override
7840 public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
7841 }
7842
7843 @Override
7844 public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
7845 int dxUnconsumed, int dyUnconsumed) {
7846 }
7847
7848 @Override
7849 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
7850 }
7851
7852 @Override
Adam Powellb36e4f92014-05-01 10:23:33 -07007853 public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
Adam Powell10ba2772014-04-15 09:46:51 -07007854 return false;
7855 }
7856
Adam Powellb72be592014-07-16 21:41:31 -07007857 @Override
7858 public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
7859 return false;
7860 }
7861
Adam Powellb6ab0982015-01-07 17:00:12 -08007862 @Override
7863 public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
7864 return false;
7865 }
7866
Robert Carr49cd9f82017-05-25 18:24:42 -07007867
7868 private void reportNextDraw() {
7869 if (mReportNextDraw == false) {
7870 drawPending();
7871 }
7872 mReportNextDraw = true;
7873 }
7874
Jorim Jaggib774e552015-08-24 14:52:45 -07007875 /**
7876 * Force the window to report its next draw.
7877 * <p>
7878 * This method is only supposed to be used to speed up the interaction from SystemUI and window
7879 * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE
7880 * unless you fully understand this interaction.
7881 * @hide
7882 */
7883 public void setReportNextDraw() {
Robert Carr49cd9f82017-05-25 18:24:42 -07007884 reportNextDraw();
Jorim Jaggib774e552015-08-24 14:52:45 -07007885 invalidate();
7886 }
7887
Craig Mautnerbc57cd12013-08-19 15:47:42 -07007888 void changeCanvasOpacity(boolean opaque) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08007889 Log.d(mTag, "changeCanvasOpacity: opaque=" + opaque);
Stan Iliev45faba52016-06-28 13:33:15 -04007890 if (mAttachInfo.mThreadedRenderer != null) {
7891 mAttachInfo.mThreadedRenderer.setOpaque(opaque);
John Reck63a06672014-05-07 13:45:54 -07007892 }
Craig Mautnerbc57cd12013-08-19 15:47:42 -07007893 }
7894
Evan Rosky5e29c072017-06-02 17:31:22 -07007895 /**
7896 * Dispatches a KeyEvent to all registered key fallback handlers.
7897 *
7898 * @param event
7899 * @return {@code true} if the event was handled, {@code false} otherwise.
7900 */
Evan Roskycd80e612018-05-17 17:46:09 -07007901 public boolean dispatchUnhandledKeyEvent(KeyEvent event) {
Evan Rosky4807ae22018-03-22 16:04:15 -07007902 return mUnhandledKeyManager.dispatch(mView, event);
Evan Rosky5e29c072017-06-02 17:31:22 -07007903 }
7904
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07007905 class TakenSurfaceHolder extends BaseSurfaceHolder {
7906 @Override
7907 public boolean onAllowLockCanvas() {
7908 return mDrawingAllowed;
7909 }
7910
7911 @Override
7912 public void onRelayoutContainer() {
7913 // Not currently interesting -- from changing between fixed and layout size.
7914 }
7915
Igor Murashkina86ab6402013-08-30 12:58:36 -07007916 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07007917 public void setFormat(int format) {
7918 ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
7919 }
7920
Igor Murashkina86ab6402013-08-30 12:58:36 -07007921 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07007922 public void setType(int type) {
7923 ((RootViewSurfaceTaker)mView).setSurfaceType(type);
7924 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07007925
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07007926 @Override
7927 public void onUpdateSurface() {
7928 // We take care of format and type changes on our own.
7929 throw new IllegalStateException("Shouldn't be here");
7930 }
7931
Igor Murashkina86ab6402013-08-30 12:58:36 -07007932 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07007933 public boolean isCreating() {
7934 return mIsCreating;
7935 }
7936
7937 @Override
7938 public void setFixedSize(int width, int height) {
7939 throw new UnsupportedOperationException(
7940 "Currently only support sizing from layout");
7941 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07007942
7943 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07007944 public void setKeepScreenOn(boolean screenOn) {
7945 ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
7946 }
7947 }
Romain Guy8506ab42009-06-11 17:35:47 -07007948
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007949 static class W extends IWindow.Stub {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007950 private final WeakReference<ViewRootImpl> mViewAncestor;
Jeff Brown98365d72012-08-19 20:30:52 -07007951 private final IWindowSession mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007952
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007953 W(ViewRootImpl viewAncestor) {
7954 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
Jeff Brown98365d72012-08-19 20:30:52 -07007955 mWindowSession = viewAncestor.mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007956 }
7957
Igor Murashkina86ab6402013-08-30 12:58:36 -07007958 @Override
Dianne Hackbornc4aad012013-02-22 15:05:25 -08007959 public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Filip Gruszczynski2217f612015-05-26 11:32:08 -07007960 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
Andrii Kulian44607962017-03-16 11:06:24 -07007961 MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
Adrian Roos5c6b6222017-11-07 17:36:10 +01007962 boolean alwaysConsumeNavBar, int displayId,
7963 DisplayCutout.ParcelableWrapper displayCutout) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007964 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007965 if (viewAncestor != null) {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08007966 viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
Andrii Kulian44607962017-03-16 11:06:24 -07007967 visibleInsets, stableInsets, outsets, reportDraw, mergedConfiguration,
Adrian Roos5c6b6222017-11-07 17:36:10 +01007968 backDropFrame, forceLayout, alwaysConsumeNavBar, displayId, displayCutout);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007969 }
7970 }
7971
Craig Mautner5702d4d2012-06-30 14:10:16 -07007972 @Override
7973 public void moved(int newX, int newY) {
7974 final ViewRootImpl viewAncestor = mViewAncestor.get();
7975 if (viewAncestor != null) {
7976 viewAncestor.dispatchMoved(newX, newY);
7977 }
7978 }
7979
Igor Murashkina86ab6402013-08-30 12:58:36 -07007980 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007981 public void dispatchAppVisibility(boolean visible) {
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.dispatchAppVisibility(visible);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007985 }
7986 }
7987
Igor Murashkina86ab6402013-08-30 12:58:36 -07007988 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007989 public void dispatchGetNewSurface() {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007990 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007991 if (viewAncestor != null) {
7992 viewAncestor.dispatchGetNewSurface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007993 }
7994 }
7995
Igor Murashkina86ab6402013-08-30 12:58:36 -07007996 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007997 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007998 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007999 if (viewAncestor != null) {
8000 viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008001 }
8002 }
8003
8004 private static int checkCallingPermission(String permission) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008005 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08008006 return ActivityManager.getService().checkPermission(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008007 permission, Binder.getCallingPid(), Binder.getCallingUid());
8008 } catch (RemoteException e) {
8009 return PackageManager.PERMISSION_DENIED;
8010 }
8011 }
8012
Igor Murashkina86ab6402013-08-30 12:58:36 -07008013 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008014 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07008015 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008016 if (viewAncestor != null) {
8017 final View view = viewAncestor.mView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008018 if (view != null) {
8019 if (checkCallingPermission(Manifest.permission.DUMP) !=
8020 PackageManager.PERMISSION_GRANTED) {
8021 throw new SecurityException("Insufficient permissions to invoke"
8022 + " executeCommand() from pid=" + Binder.getCallingPid()
8023 + ", uid=" + Binder.getCallingUid());
8024 }
8025
8026 OutputStream clientStream = null;
8027 try {
8028 clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
8029 ViewDebug.dispatchCommand(view, command, parameters, clientStream);
8030 } catch (IOException e) {
8031 e.printStackTrace();
8032 } finally {
8033 if (clientStream != null) {
8034 try {
8035 clientStream.close();
8036 } catch (IOException e) {
8037 e.printStackTrace();
8038 }
8039 }
8040 }
8041 }
8042 }
8043 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07008044
8045 @Override
Dianne Hackbornffa42482009-09-23 22:20:11 -07008046 public void closeSystemDialogs(String reason) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07008047 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008048 if (viewAncestor != null) {
8049 viewAncestor.dispatchCloseSystemDialogs(reason);
Dianne Hackbornffa42482009-09-23 22:20:11 -07008050 }
8051 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07008052
8053 @Override
Marco Nelissenbf6956b2009-11-09 15:21:13 -08008054 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
8055 boolean sync) {
Dianne Hackborn19382ac2009-09-11 21:13:37 -07008056 if (sync) {
8057 try {
Jeff Brown98365d72012-08-19 20:30:52 -07008058 mWindowSession.wallpaperOffsetsComplete(asBinder());
Dianne Hackborn19382ac2009-09-11 21:13:37 -07008059 } catch (RemoteException e) {
8060 }
8061 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07008062 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008063
Igor Murashkina86ab6402013-08-30 12:58:36 -07008064 @Override
Dianne Hackborn75804932009-10-20 20:15:20 -07008065 public void dispatchWallpaperCommand(String action, int x, int y,
8066 int z, Bundle extras, boolean sync) {
8067 if (sync) {
8068 try {
Jeff Brown98365d72012-08-19 20:30:52 -07008069 mWindowSession.wallpaperCommandComplete(asBinder(), null);
Dianne Hackborn75804932009-10-20 20:15:20 -07008070 } catch (RemoteException e) {
8071 }
8072 }
8073 }
Christopher Tatea53146c2010-09-07 11:57:52 -07008074
8075 /* Drag/drop */
Igor Murashkina86ab6402013-08-30 12:58:36 -07008076 @Override
Christopher Tatea53146c2010-09-07 11:57:52 -07008077 public void dispatchDragEvent(DragEvent event) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07008078 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008079 if (viewAncestor != null) {
8080 viewAncestor.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07008081 }
8082 }
Joe Onorato664644d2011-01-23 17:53:23 -08008083
Igor Murashkina86ab6402013-08-30 12:58:36 -07008084 @Override
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08008085 public void updatePointerIcon(float x, float y) {
8086 final ViewRootImpl viewAncestor = mViewAncestor.get();
8087 if (viewAncestor != null) {
8088 viewAncestor.updatePointerIcon(x, y);
8089 }
8090 }
8091
8092 @Override
Dianne Hackborn9a230e02011-10-06 11:51:27 -07008093 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
8094 int localValue, int localChanges) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07008095 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008096 if (viewAncestor != null) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07008097 viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility,
8098 localValue, localChanges);
Joe Onorato664644d2011-01-23 17:53:23 -08008099 }
8100 }
Dianne Hackborn12d3a942012-04-27 14:16:30 -07008101
Igor Murashkina86ab6402013-08-30 12:58:36 -07008102 @Override
Craig Mautner9c795042014-10-28 19:59:59 -07008103 public void dispatchWindowShown() {
8104 final ViewRootImpl viewAncestor = mViewAncestor.get();
8105 if (viewAncestor != null) {
8106 viewAncestor.dispatchWindowShown();
8107 }
8108 }
Clara Bayarri75e09792015-07-29 16:20:40 +01008109
8110 @Override
Clara Bayarrifcd7e802016-03-10 12:58:18 +00008111 public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
8112 ViewRootImpl viewAncestor = mViewAncestor.get();
8113 if (viewAncestor != null) {
8114 viewAncestor.dispatchRequestKeyboardShortcuts(receiver, deviceId);
8115 }
Clara Bayarri75e09792015-07-29 16:20:40 +01008116 }
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08008117
8118 @Override
8119 public void dispatchPointerCaptureChanged(boolean hasCapture) {
8120 final ViewRootImpl viewAncestor = mViewAncestor.get();
8121 if (viewAncestor != null) {
8122 viewAncestor.dispatchPointerCaptureChanged(hasCapture);
8123 }
8124 }
8125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008126 }
8127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008128 public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
Mathew Inwoode5ad5982018-08-17 15:07:52 +01008129 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008130 public CalledFromWrongThreadException(String msg) {
8131 super(msg);
8132 }
8133 }
8134
Alan Viverettebea0c7da2015-09-01 16:00:20 -04008135 static HandlerActionQueue getRunQueue() {
8136 HandlerActionQueue rq = sRunQueues.get();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008137 if (rq != null) {
8138 return rq;
8139 }
Alan Viverettebea0c7da2015-09-01 16:00:20 -04008140 rq = new HandlerActionQueue();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008141 sRunQueues.set(rq);
8142 return rq;
8143 }
Romain Guy8506ab42009-06-11 17:35:47 -07008144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008145 /**
Skuhneb8160872015-09-22 09:51:39 -07008146 * Start a drag resizing which will inform all listeners that a window resize is taking place.
8147 */
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08008148 private void startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets,
Jorim Jaggic39c7b02016-03-24 10:47:07 -07008149 Rect stableInsets, int resizeMode) {
Skuhneb8160872015-09-22 09:51:39 -07008150 if (!mDragResizing) {
8151 mDragResizing = true;
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09008152 if (mUseMTRenderer) {
8153 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
8154 mWindowCallbacks.get(i).onWindowDragResizeStart(
8155 initialBounds, fullscreen, systemInsets, stableInsets, resizeMode);
8156 }
Skuhneb8160872015-09-22 09:51:39 -07008157 }
8158 mFullRedrawNeeded = true;
8159 }
8160 }
8161
8162 /**
8163 * End a drag resize which will inform all listeners that a window resize has ended.
8164 */
8165 private void endDragResizing() {
8166 if (mDragResizing) {
8167 mDragResizing = false;
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09008168 if (mUseMTRenderer) {
8169 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
8170 mWindowCallbacks.get(i).onWindowDragResizeEnd();
8171 }
Skuhneb8160872015-09-22 09:51:39 -07008172 }
8173 mFullRedrawNeeded = true;
8174 }
8175 }
8176
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07008177 private boolean updateContentDrawBounds() {
8178 boolean updated = false;
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09008179 if (mUseMTRenderer) {
8180 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
8181 updated |=
8182 mWindowCallbacks.get(i).onContentDrawn(mWindowAttributes.surfaceInsets.left,
8183 mWindowAttributes.surfaceInsets.top, mWidth, mHeight);
8184 }
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07008185 }
8186 return updated | (mDragResizing && mReportNextDraw);
8187 }
8188
8189 private void requestDrawWindow() {
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09008190 if (!mUseMTRenderer) {
8191 return;
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07008192 }
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09008193 mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size());
Jorim Jaggi16b63192016-03-25 18:32:19 -07008194 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
8195 mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw);
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07008196 }
8197 }
8198
Skuhneb8160872015-09-22 09:51:39 -07008199 /**
Jorim Jaggi4846ee32016-01-07 17:39:12 +01008200 * Tells this instance that its corresponding activity has just relaunched. In this case, we
8201 * need to force a relayout of the window to make sure we get the correct bounds from window
8202 * manager.
8203 */
8204 public void reportActivityRelaunched() {
8205 mActivityRelaunched = true;
8206 }
8207
8208 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008209 * Class for managing the accessibility interaction connection
8210 * based on the global accessibility state.
8211 */
8212 final class AccessibilityInteractionConnectionManager
8213 implements AccessibilityStateChangeListener {
Igor Murashkina86ab6402013-08-30 12:58:36 -07008214 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008215 public void onAccessibilityStateChanged(boolean enabled) {
8216 if (enabled) {
8217 ensureConnection();
Phil Weaver05a29822017-09-22 11:03:06 -07008218 if (mAttachInfo.mHasWindowFocus && (mView != null)) {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08008219 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
8220 View focusedView = mView.findFocus();
8221 if (focusedView != null && focusedView != mView) {
8222 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
8223 }
8224 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008225 } else {
8226 ensureNoConnection();
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07008227 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008228 }
8229 }
8230
8231 public void ensureConnection() {
Phil Weaverf00cd142017-03-03 13:44:00 -08008232 final boolean registered = mAttachInfo.mAccessibilityWindowId
8233 != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
Chris Craikcce47eb2014-07-16 15:12:15 -07008234 if (!registered) {
8235 mAttachInfo.mAccessibilityWindowId =
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08008236 mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
Svet Ganov240aed92017-12-02 12:32:23 -08008237 mContext.getPackageName(),
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08008238 new AccessibilityInteractionConnection(ViewRootImpl.this));
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008239 }
8240 }
8241
8242 public void ensureNoConnection() {
Phil Weaverf00cd142017-03-03 13:44:00 -08008243 final boolean registered = mAttachInfo.mAccessibilityWindowId
8244 != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008245 if (registered) {
Phil Weaverf00cd142017-03-03 13:44:00 -08008246 mAttachInfo.mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008247 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
8248 }
8249 }
8250 }
8251
Chris Craikcce47eb2014-07-16 15:12:15 -07008252 final class HighContrastTextManager implements HighTextContrastChangeListener {
8253 HighContrastTextManager() {
John Reck938e8842017-08-24 13:41:59 -07008254 ThreadedRenderer.setHighContrastText(mAccessibilityManager.isHighTextContrastEnabled());
Chris Craikcce47eb2014-07-16 15:12:15 -07008255 }
8256 @Override
8257 public void onHighTextContrastStateChanged(boolean enabled) {
John Reck938e8842017-08-24 13:41:59 -07008258 ThreadedRenderer.setHighContrastText(enabled);
Chris Craikcce47eb2014-07-16 15:12:15 -07008259
8260 // Destroy Displaylists so they can be recreated with high contrast recordings
8261 destroyHardwareResources();
Chris Craikd36a81f2014-07-17 10:16:51 -07008262
8263 // Schedule redraw, which will rerecord + redraw all text
8264 invalidate();
Chris Craikcce47eb2014-07-16 15:12:15 -07008265 }
8266 }
8267
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008268 /**
8269 * This class is an interface this ViewAncestor provides to the
8270 * AccessibilityManagerService to the latter can interact with
8271 * the view hierarchy in this ViewAncestor.
8272 */
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07008273 static final class AccessibilityInteractionConnection
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008274 extends IAccessibilityInteractionConnection.Stub {
Svetoslav Ganov02107852011-10-03 17:06:56 -07008275 private final WeakReference<ViewRootImpl> mViewRootImpl;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008276
Svetoslav Ganovf79f4762011-10-28 15:40:32 -07008277 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) {
8278 mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008279 }
8280
Svetoslav Ganov42138042012-03-20 11:51:39 -07008281 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07008282 public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07008283 Region interactiveRegion, int interactionId,
8284 IAccessibilityInteractionConnectionCallback callback, int flags,
Phil Weaverc2e28932016-12-08 12:29:25 -08008285 int interrogatingPid, long interrogatingTid, MagnificationSpec spec, Bundle args) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07008286 ViewRootImpl viewRootImpl = mViewRootImpl.get();
8287 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07008288 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov02107852011-10-03 17:06:56 -07008289 .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07008290 interactiveRegion, interactionId, callback, flags, interrogatingPid,
Phil Weaverc2e28932016-12-08 12:29:25 -08008291 interrogatingTid, spec, args);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008292 } else {
8293 // We cannot make the call and notify the caller so it does not wait.
8294 try {
8295 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
8296 } catch (RemoteException re) {
8297 /* best effort - ignore */
8298 }
Svetoslav Ganov601ad802011-06-09 14:47:38 -07008299 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008300 }
8301
Svetoslav Ganov42138042012-03-20 11:51:39 -07008302 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07008303 public void performAccessibilityAction(long accessibilityNodeId, int action,
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07008304 Bundle arguments, int interactionId,
8305 IAccessibilityInteractionConnectionCallback callback, int flags,
Svet Ganov7498efd2014-09-03 21:33:00 -07008306 int interrogatingPid, long interrogatingTid) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07008307 ViewRootImpl viewRootImpl = mViewRootImpl.get();
8308 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07008309 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07008310 .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
Svet Ganov7498efd2014-09-03 21:33:00 -07008311 interactionId, callback, flags, interrogatingPid, interrogatingTid);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008312 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008313 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008314 try {
8315 callback.setPerformAccessibilityActionResult(false, interactionId);
8316 } catch (RemoteException re) {
8317 /* best effort - ignore */
8318 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008319 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008320 }
8321
Svetoslav Ganov42138042012-03-20 11:51:39 -07008322 @Override
Svetoslav Ganov80943d82013-01-02 10:25:37 -08008323 public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07008324 String viewId, Region interactiveRegion, int interactionId,
Svetoslav Ganov80943d82013-01-02 10:25:37 -08008325 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07008326 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07008327 ViewRootImpl viewRootImpl = mViewRootImpl.get();
8328 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07008329 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov80943d82013-01-02 10:25:37 -08008330 .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07008331 viewId, interactiveRegion, interactionId, callback, flags,
8332 interrogatingPid, interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008333 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008334 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008335 try {
8336 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
8337 } catch (RemoteException re) {
8338 /* best effort - ignore */
8339 }
8340 }
8341 }
8342
Svetoslav Ganov42138042012-03-20 11:51:39 -07008343 @Override
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008344 public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
Svetoslav9ae9ed22014-09-02 16:36:35 -07008345 Region interactiveRegion, int interactionId,
8346 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07008347 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008348 ViewRootImpl viewRootImpl = mViewRootImpl.get();
8349 if (viewRootImpl != null && viewRootImpl.mView != null) {
8350 viewRootImpl.getAccessibilityInteractionController()
8351 .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
Svetoslav9ae9ed22014-09-02 16:36:35 -07008352 interactiveRegion, interactionId, callback, flags, interrogatingPid,
8353 interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008354 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008355 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008356 try {
8357 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
8358 } catch (RemoteException re) {
8359 /* best effort - ignore */
8360 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008361 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008362 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008363
Svetoslav Ganov42138042012-03-20 11:51:39 -07008364 @Override
Svetoslav9ae9ed22014-09-02 16:36:35 -07008365 public void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion,
8366 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07008367 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008368 ViewRootImpl viewRootImpl = mViewRootImpl.get();
8369 if (viewRootImpl != null && viewRootImpl.mView != null) {
8370 viewRootImpl.getAccessibilityInteractionController()
Svetoslav9ae9ed22014-09-02 16:36:35 -07008371 .findFocusClientThread(accessibilityNodeId, focusType, interactiveRegion,
8372 interactionId, callback, flags, interrogatingPid, interrogatingTid,
8373 spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07008374 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008375 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008376 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008377 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008378 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008379 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008380 }
8381 }
8382 }
8383
Svetoslav Ganov42138042012-03-20 11:51:39 -07008384 @Override
Svetoslav9ae9ed22014-09-02 16:36:35 -07008385 public void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion,
8386 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07008387 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008388 ViewRootImpl viewRootImpl = mViewRootImpl.get();
8389 if (viewRootImpl != null && viewRootImpl.mView != null) {
8390 viewRootImpl.getAccessibilityInteractionController()
Svetoslav9ae9ed22014-09-02 16:36:35 -07008391 .focusSearchClientThread(accessibilityNodeId, direction, interactiveRegion,
8392 interactionId, callback, flags, interrogatingPid, interrogatingTid,
8393 spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07008394 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008395 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008396 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008397 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008398 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008399 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008400 }
8401 }
8402 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008403 }
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07008404
Eugene Susla72c510f2018-01-23 21:12:11 +00008405 private class SendWindowContentChangedAccessibilityEvent implements Runnable {
8406 private int mChangeTypes = 0;
8407
8408 public View mSource;
8409 public long mLastEventTimeMillis;
Eugene Susla9af1378c2018-03-22 16:29:10 -07008410 /**
8411 * Override for {@link AccessibilityEvent#originStackTrace} to provide the stack trace
8412 * of the original {@link #runOrPost} call instead of one for sending the delayed event
8413 * from a looper.
8414 */
8415 public StackTraceElement[] mOrigin;
Eugene Susla72c510f2018-01-23 21:12:11 +00008416
8417 @Override
8418 public void run() {
8419 // Protect against re-entrant code and attempt to do the right thing in the case that
8420 // we're multithreaded.
8421 View source = mSource;
8422 mSource = null;
8423 if (source == null) {
8424 Log.e(TAG, "Accessibility content change has no source");
8425 return;
8426 }
8427 // The accessibility may be turned off while we were waiting so check again.
8428 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
8429 mLastEventTimeMillis = SystemClock.uptimeMillis();
8430 AccessibilityEvent event = AccessibilityEvent.obtain();
8431 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
8432 event.setContentChangeTypes(mChangeTypes);
Eugene Susla9af1378c2018-03-22 16:29:10 -07008433 if (AccessibilityEvent.DEBUG_ORIGIN) event.originStackTrace = mOrigin;
Eugene Susla72c510f2018-01-23 21:12:11 +00008434 source.sendAccessibilityEventUnchecked(event);
8435 } else {
8436 mLastEventTimeMillis = 0;
8437 }
8438 // In any case reset to initial state.
8439 source.resetSubtreeAccessibilityStateChanged();
8440 mChangeTypes = 0;
Eugene Susla9af1378c2018-03-22 16:29:10 -07008441 if (AccessibilityEvent.DEBUG_ORIGIN) mOrigin = null;
Eugene Susla72c510f2018-01-23 21:12:11 +00008442 }
8443
8444 public void runOrPost(View source, int changeType) {
8445 if (mHandler.getLooper() != Looper.myLooper()) {
8446 CalledFromWrongThreadException e = new CalledFromWrongThreadException("Only the "
8447 + "original thread that created a view hierarchy can touch its views.");
8448 // TODO: Throw the exception
8449 Log.e(TAG, "Accessibility content change on non-UI thread. Future Android "
8450 + "versions will throw an exception.", e);
8451 // Attempt to recover. This code does not eliminate the thread safety issue, but
8452 // it should force any issues to happen near the above log.
8453 mHandler.removeCallbacks(this);
8454 if (mSource != null) {
8455 // Dispatch whatever was pending. It's still possible that the runnable started
8456 // just before we removed the callbacks, and bad things will happen, but at
8457 // least they should happen very close to the logged error.
8458 run();
8459 }
8460 }
8461 if (mSource != null) {
8462 // If there is no common predecessor, then mSource points to
8463 // a removed view, hence in this case always prefer the source.
8464 View predecessor = getCommonPredecessor(mSource, source);
Eugene Susla9af1378c2018-03-22 16:29:10 -07008465 if (predecessor != null) {
8466 predecessor = predecessor.getSelfOrParentImportantForA11y();
8467 }
Eugene Susla72c510f2018-01-23 21:12:11 +00008468 mSource = (predecessor != null) ? predecessor : source;
8469 mChangeTypes |= changeType;
8470 return;
8471 }
8472 mSource = source;
8473 mChangeTypes = changeType;
Eugene Susla9af1378c2018-03-22 16:29:10 -07008474 if (AccessibilityEvent.DEBUG_ORIGIN) {
8475 mOrigin = Thread.currentThread().getStackTrace();
8476 }
Eugene Susla72c510f2018-01-23 21:12:11 +00008477 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
8478 final long minEventIntevalMillis =
8479 ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
8480 if (timeSinceLastMillis >= minEventIntevalMillis) {
8481 removeCallbacksAndRun();
8482 } else {
8483 mHandler.postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
8484 }
8485 }
8486
8487 public void removeCallbacksAndRun() {
8488 mHandler.removeCallbacks(this);
8489 run();
8490 }
8491 }
8492
Evan Rosky4807ae22018-03-22 16:04:15 -07008493 private static class UnhandledKeyManager {
Evan Rosky4807ae22018-03-22 16:04:15 -07008494 // This is used to ensure that unhandled events are only dispatched once. We attempt
Evan Rosky5e29c072017-06-02 17:31:22 -07008495 // to dispatch more than once in order to achieve a certain order. Specifically, if we
Evan Rosky4807ae22018-03-22 16:04:15 -07008496 // are in an Activity or Dialog (and have a Window.Callback), the unhandled events should
Evan Roskycd80e612018-05-17 17:46:09 -07008497 // be dispatched after the view hierarchy, but before the Callback. However, if we aren't
Evan Rosky4807ae22018-03-22 16:04:15 -07008498 // in an activity, we still want unhandled keys to be dispatched.
Evan Roskycd80e612018-05-17 17:46:09 -07008499 private boolean mDispatched = true;
Evan Rosky5e29c072017-06-02 17:31:22 -07008500
Evan Roskycd80e612018-05-17 17:46:09 -07008501 // Keeps track of which Views have unhandled key focus for which keys. This doesn't
8502 // include modifiers.
8503 private final SparseArray<WeakReference<View>> mCapturedKeys = new SparseArray<>();
Evan Rosky5e29c072017-06-02 17:31:22 -07008504
Evan Roskycd80e612018-05-17 17:46:09 -07008505 // The current receiver. This value is transient and used between the pre-dispatch and
8506 // pre-view phase to ensure that other input-stages don't interfere with tracking.
8507 private WeakReference<View> mCurrentReceiver = null;
8508
8509 boolean dispatch(View root, KeyEvent event) {
8510 if (mDispatched) {
8511 return false;
Evan Rosky5e29c072017-06-02 17:31:22 -07008512 }
Evan Roskycd80e612018-05-17 17:46:09 -07008513 View consumer;
8514 try {
8515 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "UnhandledKeyEvent dispatch");
8516 mDispatched = true;
8517
8518 consumer = root.dispatchUnhandledKeyEvent(event);
8519
8520 // If an unhandled listener handles one, then keep track of it so that the
8521 // consuming view is first to receive its repeats and release as well.
8522 if (event.getAction() == KeyEvent.ACTION_DOWN) {
8523 int keycode = event.getKeyCode();
8524 if (consumer != null && !KeyEvent.isModifierKey(keycode)) {
8525 mCapturedKeys.put(keycode, new WeakReference<>(consumer));
8526 }
8527 }
8528 } finally {
8529 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
8530 }
8531 return consumer != null;
8532 }
8533
8534 /**
8535 * Called before the event gets dispatched to anything
8536 */
8537 void preDispatch(KeyEvent event) {
8538 // Always clean-up 'up' events since it's possible for earlier dispatch stages to
8539 // consume them without consuming the corresponding 'down' event.
8540 mCurrentReceiver = null;
Evan Rosky5e29c072017-06-02 17:31:22 -07008541 if (event.getAction() == KeyEvent.ACTION_UP) {
Evan Roskycd80e612018-05-17 17:46:09 -07008542 int idx = mCapturedKeys.indexOfKey(event.getKeyCode());
8543 if (idx >= 0) {
8544 mCurrentReceiver = mCapturedKeys.valueAt(idx);
8545 mCapturedKeys.removeAt(idx);
8546 }
Evan Rosky5e29c072017-06-02 17:31:22 -07008547 }
8548 }
8549
Evan Roskycd80e612018-05-17 17:46:09 -07008550 /**
8551 * Called before the event gets dispatched to the view hierarchy
8552 * @return {@code true} if an unhandled handler has focus and consumed the event
8553 */
8554 boolean preViewDispatch(KeyEvent event) {
8555 mDispatched = false;
8556 if (mCurrentReceiver == null) {
8557 mCurrentReceiver = mCapturedKeys.get(event.getKeyCode());
8558 }
Evan Rosky4807ae22018-03-22 16:04:15 -07008559 if (mCurrentReceiver != null) {
8560 View target = mCurrentReceiver.get();
Evan Roskycd80e612018-05-17 17:46:09 -07008561 if (event.getAction() == KeyEvent.ACTION_UP) {
Evan Rosky4807ae22018-03-22 16:04:15 -07008562 mCurrentReceiver = null;
Evan Rosky5e29c072017-06-02 17:31:22 -07008563 }
8564 if (target != null && target.isAttachedToWindow()) {
Evan Rosky4807ae22018-03-22 16:04:15 -07008565 target.onUnhandledKeyEvent(event);
Evan Rosky5e29c072017-06-02 17:31:22 -07008566 }
8567 // consume anyways so that we don't feed uncaptured key events to other views
8568 return true;
8569 }
Evan Roskycd80e612018-05-17 17:46:09 -07008570 return false;
Evan Rosky5e29c072017-06-02 17:31:22 -07008571 }
8572 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008573}