blob: 798401d87b5a6877944ef77b524ab4b67c09be43 [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) {
1379 mSurface.release();
1380 }
Dianne Hackbornce418e62011-03-01 14:31:38 -08001381 }
1382 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001383
George Mount41725de2015-04-09 08:23:05 -07001384 /**
1385 * Block the input events during an Activity Transition. The KEYCODE_BACK event is allowed
1386 * through to allow quick reversal of the Activity Transition.
1387 *
1388 * @param paused true to pause, false to resume.
1389 */
1390 public void setPausedForTransition(boolean paused) {
1391 mPausedForTransition = paused;
1392 }
1393
Craig Mautner8f303ad2013-06-14 11:32:22 -07001394 @Override
Romain Guycfef1232012-02-23 13:50:37 -08001395 public ViewParent getParent() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001396 return null;
1397 }
1398
Craig Mautner8f303ad2013-06-14 11:32:22 -07001399 @Override
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001400 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401 if (child != mView) {
1402 throw new RuntimeException("child is not mine, honest!");
1403 }
1404 // Note: don't apply scroll offset, because we want to know its
1405 // visibility in the virtual canvas being given to the view hierarchy.
1406 return r.intersect(0, 0, mWidth, mHeight);
1407 }
1408
Igor Murashkina86ab6402013-08-30 12:58:36 -07001409 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001410 public void bringChildToFront(View child) {
1411 }
1412
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001413 int getHostVisibility() {
Bryce Lee16e50892017-04-11 01:59:37 +00001414 return (mAppVisible || mForceDecorViewVisibility) ? mView.getVisibility() : View.GONE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001415 }
Romain Guy8506ab42009-06-11 17:35:47 -07001416
Chet Haasecca2c982011-05-20 14:34:18 -07001417 /**
1418 * Add LayoutTransition to the list of transitions to be started in the next traversal.
1419 * This list will be cleared after the transitions on the list are start()'ed. These
1420 * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
1421 * happens during the layout phase of traversal, which we want to complete before any of the
1422 * animations are started (because those animations may side-effect properties that layout
1423 * depends upon, like the bounding rectangles of the affected views). So we add the transition
1424 * to the list and it is started just prior to starting the drawing phase of traversal.
1425 *
1426 * @param transition The LayoutTransition to be started on the next traversal.
1427 *
1428 * @hide
1429 */
1430 public void requestTransitionStart(LayoutTransition transition) {
1431 if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
1432 if (mPendingTransitions == null) {
1433 mPendingTransitions = new ArrayList<LayoutTransition>();
1434 }
1435 mPendingTransitions.add(transition);
1436 }
1437 }
1438
John Recka5dda642014-05-22 15:43:54 -07001439 /**
1440 * Notifies the HardwareRenderer that a new frame will be coming soon.
1441 * Currently only {@link ThreadedRenderer} cares about this, and uses
1442 * this knowledge to adjust the scheduling of off-thread animations
1443 */
1444 void notifyRendererOfFramePending() {
Stan Iliev45faba52016-06-28 13:33:15 -04001445 if (mAttachInfo.mThreadedRenderer != null) {
1446 mAttachInfo.mThreadedRenderer.notifyFramePending();
John Recka5dda642014-05-22 15:43:54 -07001447 }
1448 }
1449
Mathew Inwoode5ad5982018-08-17 15:07:52 +01001450 @UnsupportedAppUsage
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001451 void scheduleTraversals() {
1452 if (!mTraversalScheduled) {
1453 mTraversalScheduled = true;
Jeff Brown3d4e7efe2015-02-26 15:34:16 -08001454 mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001455 mChoreographer.postCallback(
1456 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
Michael Wright9d744c72014-02-18 21:27:42 -08001457 if (!mUnbufferedInputDispatch) {
1458 scheduleConsumeBatchedInput();
1459 }
John Recka5dda642014-05-22 15:43:54 -07001460 notifyRendererOfFramePending();
Jeff Brownc2932a12014-11-20 18:04:05 -08001461 pokeDrawLockIfNeeded();
Jeff Brown96e942d2011-11-30 19:55:01 -08001462 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001463 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001464
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001465 void unscheduleTraversals() {
1466 if (mTraversalScheduled) {
1467 mTraversalScheduled = false;
Jeff Brown3d4e7efe2015-02-26 15:34:16 -08001468 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001469 mChoreographer.removeCallbacks(
1470 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
1471 }
1472 }
1473
1474 void doTraversal() {
1475 if (mTraversalScheduled) {
1476 mTraversalScheduled = false;
Jeff Brown3d4e7efe2015-02-26 15:34:16 -08001477 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001478
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001479 if (mProfile) {
1480 Debug.startMethodTracing("ViewAncestor");
Jeff Brown96e942d2011-11-30 19:55:01 -08001481 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001482
Chris Craike22c59b2015-05-21 18:33:37 -07001483 performTraversals();
Jeff Brown96e942d2011-11-30 19:55:01 -08001484
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001485 if (mProfile) {
1486 Debug.stopMethodTracing();
1487 mProfile = false;
1488 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001489 }
1490 }
1491
Dianne Hackborn9d090892012-06-11 18:35:41 -07001492 private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) {
1493 // Update window's global keep screen on flag: if a view has requested
1494 // that the screen be kept on, then it is always set; otherwise, it is
1495 // set to whatever the client last requested for the global state.
1496 if (mAttachInfo.mKeepScreenOn) {
1497 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
1498 } else {
1499 params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
1500 | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1501 }
1502 }
1503
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001504 private boolean collectViewAttributes() {
Chris Craikd36a81f2014-07-17 10:16:51 -07001505 if (mAttachInfo.mRecomputeGlobalAttributes) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001506 //Log.i(mTag, "Computing view hierarchy attributes!");
Chris Craikd36a81f2014-07-17 10:16:51 -07001507 mAttachInfo.mRecomputeGlobalAttributes = false;
1508 boolean oldScreenOn = mAttachInfo.mKeepScreenOn;
1509 mAttachInfo.mKeepScreenOn = false;
1510 mAttachInfo.mSystemUiVisibility = 0;
1511 mAttachInfo.mHasSystemUiListeners = false;
1512 mView.dispatchCollectViewAttributes(mAttachInfo, 0);
1513 mAttachInfo.mSystemUiVisibility &= ~mAttachInfo.mDisabledSystemUiVisibility;
Craig Mautner7eac0f52012-09-13 13:14:14 -07001514 WindowManager.LayoutParams params = mWindowAttributes;
Chris Craikd36a81f2014-07-17 10:16:51 -07001515 mAttachInfo.mSystemUiVisibility |= getImpliedSystemUiVisibility(params);
1516 if (mAttachInfo.mKeepScreenOn != oldScreenOn
1517 || mAttachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
1518 || mAttachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
Dianne Hackborn9d090892012-06-11 18:35:41 -07001519 applyKeepScreenOnFlag(params);
Chris Craikd36a81f2014-07-17 10:16:51 -07001520 params.subtreeSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
1521 params.hasSystemUiListeners = mAttachInfo.mHasSystemUiListeners;
1522 mView.dispatchWindowSystemUiVisiblityChanged(mAttachInfo.mSystemUiVisibility);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001523 return true;
1524 }
1525 }
1526 return false;
1527 }
1528
John Spurlockbd957402013-10-03 11:38:39 -04001529 private int getImpliedSystemUiVisibility(WindowManager.LayoutParams params) {
1530 int vis = 0;
1531 // Translucent decor window flags imply stable system ui visibility.
1532 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) != 0) {
1533 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
1534 }
1535 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) != 0) {
1536 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
1537 }
1538 return vis;
1539 }
1540
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001541 private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
1542 final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
1543 int childWidthMeasureSpec;
1544 int childHeightMeasureSpec;
1545 boolean windowSizeMayChange = false;
1546
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001547 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(mTag,
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001548 "Measuring " + host + " in display " + desiredWindowWidth
1549 + "x" + desiredWindowHeight + "...");
1550
1551 boolean goodMeasure = false;
1552 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
1553 // On large screens, we don't want to allow dialogs to just
1554 // stretch to fill the entire width of the screen to display
1555 // one line of text. First try doing the layout at a smaller
1556 // size to see if it will fit.
1557 final DisplayMetrics packageMetrics = res.getDisplayMetrics();
1558 res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
1559 int baseSize = 0;
1560 if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
1561 baseSize = (int)mTmpValue.getDimension(packageMetrics);
1562 }
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08001563 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": baseSize=" + baseSize
1564 + ", desiredWindowWidth=" + desiredWindowWidth);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001565 if (baseSize != 0 && desiredWindowWidth > baseSize) {
1566 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
1567 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001568 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001569 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08001570 + host.getMeasuredWidth() + "," + host.getMeasuredHeight()
1571 + ") from width spec: " + MeasureSpec.toString(childWidthMeasureSpec)
1572 + " and height spec: " + MeasureSpec.toString(childHeightMeasureSpec));
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001573 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1574 goodMeasure = true;
1575 } else {
1576 // Didn't fit in that size... try expanding a bit.
1577 baseSize = (baseSize+desiredWindowWidth)/2;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001578 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": next baseSize="
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001579 + baseSize);
1580 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001581 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001582 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001583 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1584 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001585 if (DEBUG_DIALOG) Log.v(mTag, "Good!");
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001586 goodMeasure = true;
1587 }
1588 }
1589 }
1590 }
1591
1592 if (!goodMeasure) {
1593 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
1594 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001595 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001596 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
1597 windowSizeMayChange = true;
1598 }
1599 }
1600
1601 if (DBG) {
1602 System.out.println("======================================");
1603 System.out.println("performTraversals -- after measure");
1604 host.debug();
1605 }
1606
1607 return windowSizeMayChange;
1608 }
1609
Alan Viverettefed3f722013-11-14 14:48:20 -08001610 /**
1611 * Modifies the input matrix such that it maps view-local coordinates to
1612 * on-screen coordinates.
1613 *
1614 * @param m input matrix to modify
1615 */
1616 void transformMatrixToGlobal(Matrix m) {
Dake Gu7bf379c2014-07-15 16:29:38 -07001617 m.preTranslate(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
Alan Viverettefed3f722013-11-14 14:48:20 -08001618 }
1619
1620 /**
1621 * Modifies the input matrix such that it maps on-screen coordinates to
1622 * view-local coordinates.
1623 *
1624 * @param m input matrix to modify
1625 */
1626 void transformMatrixToLocal(Matrix m) {
Dake Gu7bf379c2014-07-15 16:29:38 -07001627 m.postTranslate(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
Alan Viverettefed3f722013-11-14 14:48:20 -08001628 }
1629
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001630 /* package */ WindowInsets getWindowInsets(boolean forceConstruct) {
1631 if (mLastWindowInsets == null || forceConstruct) {
1632 mDispatchContentInsets.set(mAttachInfo.mContentInsets);
1633 mDispatchStableInsets.set(mAttachInfo.mStableInsets);
Adrian Roos5c6b6222017-11-07 17:36:10 +01001634 mDispatchDisplayCutout = mAttachInfo.mDisplayCutout.get();
1635
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001636 Rect contentInsets = mDispatchContentInsets;
1637 Rect stableInsets = mDispatchStableInsets;
Adrian Roos5c6b6222017-11-07 17:36:10 +01001638 DisplayCutout displayCutout = mDispatchDisplayCutout;
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001639 // For dispatch we preserve old logic, but for direct requests from Views we allow to
1640 // immediately use pending insets.
1641 if (!forceConstruct
1642 && (!mPendingContentInsets.equals(contentInsets) ||
Adrian Roos5c6b6222017-11-07 17:36:10 +01001643 !mPendingStableInsets.equals(stableInsets) ||
1644 !mPendingDisplayCutout.get().equals(displayCutout))) {
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001645 contentInsets = mPendingContentInsets;
1646 stableInsets = mPendingStableInsets;
Adrian Roos5c6b6222017-11-07 17:36:10 +01001647 displayCutout = mPendingDisplayCutout.get();
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001648 }
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001649 Rect outsets = mAttachInfo.mOutsets;
1650 if (outsets.left > 0 || outsets.top > 0 || outsets.right > 0 || outsets.bottom > 0) {
1651 contentInsets = new Rect(contentInsets.left + outsets.left,
1652 contentInsets.top + outsets.top, contentInsets.right + outsets.right,
1653 contentInsets.bottom + outsets.bottom);
1654 }
Adrian Roos7419a172018-05-24 18:20:51 +02001655 contentInsets = ensureInsetsNonNegative(contentInsets, "content");
1656 stableInsets = ensureInsetsNonNegative(stableInsets, "stable");
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001657 mLastWindowInsets = new WindowInsets(contentInsets,
Adam Powell01f280d2015-05-18 16:07:42 -07001658 null /* windowDecorInsets */, stableInsets,
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08001659 mContext.getResources().getConfiguration().isScreenRound(),
Adrian Roos5c6b6222017-11-07 17:36:10 +01001660 mAttachInfo.mAlwaysConsumeNavBar, displayCutout);
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001661 }
1662 return mLastWindowInsets;
1663 }
1664
Adrian Roos7419a172018-05-24 18:20:51 +02001665 private Rect ensureInsetsNonNegative(Rect insets, String kind) {
1666 if (insets.left < 0 || insets.top < 0 || insets.right < 0 || insets.bottom < 0) {
Adrian Roos7419a172018-05-24 18:20:51 +02001667 return new Rect(Math.max(0, insets.left),
1668 Math.max(0, insets.top),
1669 Math.max(0, insets.right),
1670 Math.max(0, insets.bottom));
1671 }
1672 return insets;
1673 }
1674
Adam Powell2accbf92014-04-16 23:14:57 +00001675 void dispatchApplyInsets(View host) {
Adrian Roos2b0dcb32017-12-12 16:07:55 +01001676 WindowInsets insets = getWindowInsets(true /* forceConstruct */);
Adrian Roosfa02da62018-01-15 16:01:18 +01001677 final boolean dispatchCutout = (mWindowAttributes.layoutInDisplayCutoutMode
1678 == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS);
1679 if (!dispatchCutout) {
Adrian Roos2b0dcb32017-12-12 16:07:55 +01001680 // Window is either not laid out in cutout or the status bar inset takes care of
1681 // clearing the cutout, so we don't need to dispatch the cutout to the hierarchy.
Adrian Roosd07bafd2017-12-11 17:30:56 +01001682 insets = insets.consumeDisplayCutout();
Adrian Roos2b0dcb32017-12-12 16:07:55 +01001683 }
1684 host.dispatchApplyWindowInsets(insets);
Adam Powell2accbf92014-04-16 23:14:57 +00001685 }
1686
Chong Zhangf6525ce2016-01-14 17:09:56 -08001687 private static boolean shouldUseDisplaySize(final WindowManager.LayoutParams lp) {
1688 return lp.type == TYPE_STATUS_BAR_PANEL
1689 || lp.type == TYPE_INPUT_METHOD
1690 || lp.type == TYPE_VOLUME_OVERLAY;
1691 }
1692
1693 private int dipToPx(int dip) {
1694 final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
1695 return (int) (displayMetrics.density * dip + 0.5f);
1696 }
1697
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001698 private void performTraversals() {
1699 // cache mView since it is used so much below...
1700 final View host = mView;
1701
1702 if (DBG) {
1703 System.out.println("======================================");
1704 System.out.println("performTraversals");
1705 host.debug();
1706 }
1707
1708 if (host == null || !mAdded)
1709 return;
1710
Craig Mautnerdf2390a2012-08-29 20:59:22 -07001711 mIsInTraversal = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001712 mWillDrawSoon = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001713 boolean windowSizeMayChange = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001714 boolean newSurface = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001715 boolean surfaceChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001716 WindowManager.LayoutParams lp = mWindowAttributes;
1717
1718 int desiredWindowWidth;
1719 int desiredWindowHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001720
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001721 final int viewVisibility = getHostVisibility();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001722 final boolean viewVisibilityChanged = !mFirst
Andrii Kulian74b561a2017-08-11 09:06:46 -07001723 && (mViewVisibility != viewVisibility || mNewSurfaceNeeded
1724 // Also check for possible double visibility update, which will make current
1725 // viewVisibility value equal to mViewVisibility and we may miss it.
1726 || mAppVisibilityChanged);
1727 mAppVisibilityChanged = false;
Adam Powell06f9eb82016-08-24 17:09:01 -07001728 final boolean viewUserVisibilityChanged = !mFirst &&
1729 ((mViewVisibility == View.VISIBLE) != (viewVisibility == View.VISIBLE));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001730
1731 WindowManager.LayoutParams params = null;
1732 if (mWindowAttributesChanged) {
1733 mWindowAttributesChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001734 surfaceChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001735 params = lp;
1736 }
Adam Lesinski4ece3d62016-06-16 18:05:41 -07001737 CompatibilityInfo compatibilityInfo =
1738 mDisplay.getDisplayAdjustments().getCompatibilityInfo();
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001739 if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
1740 params = lp;
Jeff Brown96e942d2011-11-30 19:55:01 -08001741 mFullRedrawNeeded = true;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001742 mLayoutRequested = true;
1743 if (mLastInCompatMode) {
Adam Lesinski95c42972013-10-02 10:13:27 -07001744 params.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001745 mLastInCompatMode = false;
1746 } else {
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 = true;
1749 }
1750 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001751
Romain Guyf21c9b02011-09-06 16:56:54 -07001752 mWindowAttributesChangesFlag = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -07001753
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001754 Rect frame = mWinFrame;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 if (mFirst) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001756 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001757 mLayoutRequested = true;
1758
Andrii Kulian44607962017-03-16 11:06:24 -07001759 final Configuration config = mContext.getResources().getConfiguration();
Chong Zhangf6525ce2016-01-14 17:09:56 -08001760 if (shouldUseDisplaySize(lp)) {
Dianne Hackborna239c842011-06-01 12:28:20 -07001761 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001762 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001763 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001764 desiredWindowWidth = size.x;
1765 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001766 } else {
Adrian Roos9e370f22018-03-06 18:19:45 +01001767 desiredWindowWidth = mWinFrame.width();
1768 desiredWindowHeight = mWinFrame.height();
Dianne Hackborna239c842011-06-01 12:28:20 -07001769 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001770
Romain Guyc5d55862011-01-21 19:01:46 -08001771 // We used to use the following condition to choose 32 bits drawing caches:
1772 // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
1773 // However, windows are now always 32 bits by default, so choose 32 bits
Chris Craikd36a81f2014-07-17 10:16:51 -07001774 mAttachInfo.mUse32BitDrawingCache = true;
1775 mAttachInfo.mHasWindowFocus = false;
1776 mAttachInfo.mWindowVisibility = viewVisibility;
1777 mAttachInfo.mRecomputeGlobalAttributes = false;
Andrii Kulian44607962017-03-16 11:06:24 -07001778 mLastConfigurationFromResources.setTo(config);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001779 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Fabrice Di Megliob003e282012-10-17 17:20:19 -07001780 // Set the layout direction if it has not been set before (inherit is the default)
1781 if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
Andrii Kulian44607962017-03-16 11:06:24 -07001782 host.setLayoutDirection(config.getLayoutDirection());
Fabrice Di Megliob003e282012-10-17 17:20:19 -07001783 }
Chris Craikd36a81f2014-07-17 10:16:51 -07001784 host.dispatchAttachedToWindow(mAttachInfo, 0);
1785 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
Adam Powell2accbf92014-04-16 23:14:57 +00001786 dispatchApplyInsets(host);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001787 } else {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001788 desiredWindowWidth = frame.width();
1789 desiredWindowHeight = frame.height();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001790 if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001791 if (DEBUG_ORIENTATION) Log.v(mTag, "View " + host + " resized to: " + frame);
Jeff Brown96e942d2011-11-30 19:55:01 -08001792 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001793 mLayoutRequested = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001794 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001795 }
1796 }
1797
1798 if (viewVisibilityChanged) {
Bryce Lee16e50892017-04-11 01:59:37 +00001799 mAttachInfo.mWindowVisibility = viewVisibility;
1800 host.dispatchWindowVisibilityChanged(viewVisibility);
Adam Powell06f9eb82016-08-24 17:09:01 -07001801 if (viewUserVisibilityChanged) {
Adam Powell64e1ba42016-08-22 09:09:44 -07001802 host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE);
1803 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001804 if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
Skuhneb8160872015-09-22 09:51:39 -07001805 endDragResizing();
Romain Guy65b345f2011-07-27 18:51:50 -07001806 destroyHardwareResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001807 }
1808 if (viewVisibility == View.GONE) {
1809 // After making a window gone, we will count it as being
1810 // shown for the first time the next time it gets focus.
1811 mHasHadWindowFocus = false;
1812 }
1813 }
1814
Alan Viverette7dbc3bf2015-01-28 16:14:36 -08001815 // Non-visible windows can't hold accessibility focus.
1816 if (mAttachInfo.mWindowVisibility != View.VISIBLE) {
1817 host.clearAccessibilityFocus();
1818 }
1819
Chet Haaseb78c2842012-04-19 13:39:50 -07001820 // Execute enqueued actions on every traversal in case a detached view enqueued an action
Chris Craikd36a81f2014-07-17 10:16:51 -07001821 getRunQueue().executeActions(mAttachInfo.mHandler);
Chet Haaseb78c2842012-04-19 13:39:50 -07001822
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001823 boolean insetsChanged = false;
Romain Guy8506ab42009-06-11 17:35:47 -07001824
Craig Mautner72d6f212015-02-19 16:33:09 -08001825 boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001826 if (layoutRequested) {
Romain Guy15df6702009-08-17 20:17:30 -07001827
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001828 final Resources res = mView.getContext().getResources();
1829
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001830 if (mFirst) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001831 // make sure touch mode code executes by setting cached value
1832 // to opposite of the added touch mode.
1833 mAttachInfo.mInTouchMode = !mAddedTouchMode;
Romain Guy2d4cff62010-04-09 15:39:00 -07001834 ensureTouchModeLocally(mAddedTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001835 } else {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001836 if (!mPendingOverscanInsets.equals(mAttachInfo.mOverscanInsets)) {
1837 insetsChanged = true;
1838 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001839 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001840 insetsChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001841 }
Adrian Roosfa104232014-06-20 16:10:14 -07001842 if (!mPendingStableInsets.equals(mAttachInfo.mStableInsets)) {
1843 insetsChanged = true;
1844 }
Adrian Roos5c6b6222017-11-07 17:36:10 +01001845 if (!mPendingDisplayCutout.equals(mAttachInfo.mDisplayCutout)) {
1846 insetsChanged = true;
1847 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001848 if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001849 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001850 if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001851 + mAttachInfo.mVisibleInsets);
1852 }
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001853 if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) {
1854 insetsChanged = true;
1855 }
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08001856 if (mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar) {
1857 insetsChanged = true;
1858 }
Chong Zhangf6525ce2016-01-14 17:09:56 -08001859 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
1860 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001861 windowSizeMayChange = true;
Chong Zhangf6525ce2016-01-14 17:09:56 -08001862
1863 if (shouldUseDisplaySize(lp)) {
1864 // NOTE -- system code, won't try to do compat mode.
1865 Point size = new Point();
1866 mDisplay.getRealSize(size);
1867 desiredWindowWidth = size.x;
1868 desiredWindowHeight = size.y;
1869 } else {
1870 Configuration config = res.getConfiguration();
1871 desiredWindowWidth = dipToPx(config.screenWidthDp);
1872 desiredWindowHeight = dipToPx(config.screenHeightDp);
1873 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001874 }
1875 }
1876
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001877 // Ask host how big it wants to be
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001878 windowSizeMayChange |= measureHierarchy(host, lp, res,
1879 desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001880 }
1881
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001882 if (collectViewAttributes()) {
1883 params = lp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001884 }
Chris Craikd36a81f2014-07-17 10:16:51 -07001885 if (mAttachInfo.mForceReportNewAttributes) {
1886 mAttachInfo.mForceReportNewAttributes = false;
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001887 params = lp;
1888 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001889
Chris Craikd36a81f2014-07-17 10:16:51 -07001890 if (mFirst || mAttachInfo.mViewVisibilityChanged) {
1891 mAttachInfo.mViewVisibilityChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001892 int resizeMode = mSoftInputMode &
1893 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
1894 // If we are in auto resize mode, then we need to determine
1895 // what mode to use now.
1896 if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001897 final int N = mAttachInfo.mScrollContainers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001898 for (int i=0; i<N; i++) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001899 if (mAttachInfo.mScrollContainers.get(i).isShown()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001900 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
1901 }
1902 }
1903 if (resizeMode == 0) {
1904 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
1905 }
1906 if ((lp.softInputMode &
1907 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
1908 lp.softInputMode = (lp.softInputMode &
1909 ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
1910 resizeMode;
1911 params = lp;
1912 }
1913 }
1914 }
Romain Guy8506ab42009-06-11 17:35:47 -07001915
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001916 if (params != null) {
1917 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
1918 if (!PixelFormat.formatHasAlpha(params.format)) {
1919 params.format = PixelFormat.TRANSLUCENT;
1920 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001921 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001922 mAttachInfo.mOverscanRequested = (params.flags
1923 & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001924 }
1925
Adrian Roosfa104232014-06-20 16:10:14 -07001926 if (mApplyInsetsRequested) {
1927 mApplyInsetsRequested = false;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001928 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Adam Powell2accbf92014-04-16 23:14:57 +00001929 dispatchApplyInsets(host);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001930 if (mLayoutRequested) {
1931 // Short-circuit catching a new layout request here, so
1932 // we don't need to go through two layout passes when things
1933 // change due to fitting system windows, which can happen a lot.
1934 windowSizeMayChange |= measureHierarchy(host, lp,
1935 mView.getContext().getResources(),
1936 desiredWindowWidth, desiredWindowHeight);
1937 }
1938 }
1939
1940 if (layoutRequested) {
1941 // Clear this now, so that if anything requests a layout in the
1942 // rest of this function we will catch it and re-run a full
1943 // layout pass.
1944 mLayoutRequested = false;
1945 }
1946
1947 boolean windowShouldResize = layoutRequested && windowSizeMayChange
Dianne Hackborn189ee182010-12-02 21:48:53 -08001948 && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
Romain Guy2e4f4262010-04-06 11:07:52 -07001949 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
1950 frame.width() < desiredWindowWidth && frame.width() != mWidth)
1951 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
1952 frame.height() < desiredWindowHeight && frame.height() != mHeight));
Jorim Jaggi4846ee32016-01-07 17:39:12 +01001953 windowShouldResize |= mDragResizing && mResizeMode == RESIZE_MODE_FREEFORM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001954
Jorim Jaggi4846ee32016-01-07 17:39:12 +01001955 // If the activity was just relaunched, it might have unfrozen the task bounds (while
1956 // relaunching), so we need to force a call into window manager to pick up the latest
1957 // bounds.
1958 windowShouldResize |= mActivityRelaunched;
1959
Jeff Brown2e05ec32013-09-30 15:57:43 -07001960 // Determine whether to compute insets.
1961 // If there are no inset listeners remaining then we may still need to compute
1962 // insets in case the old insets were non-empty and must be reset.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001963 final boolean computesInternalInsets =
Chris Craikd36a81f2014-07-17 10:16:51 -07001964 mAttachInfo.mTreeObserver.hasComputeInternalInsetsListeners()
1965 || mAttachInfo.mHasNonEmptyGivenInternalInsets;
Romain Guy812ccbe2010-06-01 14:07:24 -07001966
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001967 boolean insetsPending = false;
1968 int relayoutResult = 0;
Chet Haased86fb2c2016-05-04 07:26:02 -07001969 boolean updatedConfiguration = false;
Romain Guy812ccbe2010-06-01 14:07:24 -07001970
Robert Carrb2594852016-04-25 16:21:13 -07001971 final int surfaceGenerationId = mSurface.getGenerationId();
1972
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08001973 final boolean isViewVisible = viewVisibility == View.VISIBLE;
Andrii Kulianb2e37802017-01-11 00:36:44 -08001974 final boolean windowRelayoutWasForced = mForceNextWindowRelayout;
Bryce Lee46b01652017-06-07 23:01:56 +00001975 if (mFirst || windowShouldResize || insetsChanged ||
1976 viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
Jorim Jaggia4a58ef2016-01-27 02:10:08 -08001977 mForceNextWindowRelayout = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001978
Alan Viverette64bf97a2015-09-18 16:42:00 -04001979 if (isViewVisible) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001980 // If this window is giving internal insets to the window
1981 // manager, and it is being added or changing its visibility,
1982 // then we want to first give the window manager "fake"
1983 // insets to cause it to effectively ignore the content of
1984 // the window during layout. This avoids it briefly causing
1985 // other windows to resize/move based on the raw frame of the
1986 // window, waiting until we can finish laying out this window
1987 // and get back to the window manager with the ultimately
1988 // computed insets.
Romain Guy812ccbe2010-06-01 14:07:24 -07001989 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001990 }
1991
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001992 if (mSurfaceHolder != null) {
1993 mSurfaceHolder.mSurfaceLock.lock();
1994 mDrawingAllowed = true;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001995 }
Romain Guy812ccbe2010-06-01 14:07:24 -07001996
Romain Guyc361da82010-10-25 15:29:10 -07001997 boolean hwInitialized = false;
Chong Zhang75eccbd2016-07-12 19:25:08 -07001998 boolean contentInsetsChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001999 boolean hadSurface = mSurface.isValid();
Romain Guy812ccbe2010-06-01 14:07:24 -07002000
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002001 try {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07002002 if (DEBUG_LAYOUT) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002003 Log.i(mTag, "host=w:" + host.getMeasuredWidth() + ", h:" +
Dianne Hackborn189ee182010-12-02 21:48:53 -08002004 host.getMeasuredHeight() + ", params=" + params);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07002005 }
Romain Guy2a83f002011-01-18 18:28:21 -08002006
Stan Iliev45faba52016-06-28 13:33:15 -04002007 if (mAttachInfo.mThreadedRenderer != null) {
John Reckf7d9c1d2014-04-09 10:01:03 -07002008 // relayoutWindow may decide to destroy mSurface. As that decision
2009 // happens in WindowManager service, we need to be defensive here
2010 // and stop using the surface in case it gets destroyed.
Stan Iliev45faba52016-06-28 13:33:15 -04002011 if (mAttachInfo.mThreadedRenderer.pauseSurface(mSurface)) {
John Reck01a5ea32014-12-03 13:01:07 -08002012 // Animations were running so we need to push a frame
2013 // to resume them
2014 mDirty.set(0, 0, mWidth, mHeight);
2015 }
John Reckba6adf62015-02-19 14:36:50 -08002016 mChoreographer.mFrameInfo.addFlags(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED);
John Reckf7d9c1d2014-04-09 10:01:03 -07002017 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07002018 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
2019
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002020 if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
Dianne Hackbornc4aad012013-02-22 15:05:25 -08002021 + " overscan=" + mPendingOverscanInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002022 + " content=" + mPendingContentInsets.toShortString()
2023 + " visible=" + mPendingVisibleInsets.toShortString()
Adrian Roos5c6b6222017-11-07 17:36:10 +01002024 + " stable=" + mPendingStableInsets.toShortString()
2025 + " cutout=" + mPendingDisplayCutout.get().toString()
Filip Gruszczynski0ec13282015-06-25 11:26:01 -07002026 + " outsets=" + mPendingOutsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002027 + " surface=" + mSurface);
Romain Guy8506ab42009-06-11 17:35:47 -07002028
Bryce Leef858b572017-06-29 14:03:33 -07002029 // If the pending {@link MergedConfiguration} handed back from
2030 // {@link #relayoutWindow} does not match the one last reported,
2031 // WindowManagerService has reported back a frame from a configuration not yet
2032 // handled by the client. In this case, we need to accept the configuration so we
2033 // do not lay out and draw with the wrong configuration.
2034 if (!mPendingMergedConfiguration.equals(mLastReportedMergedConfiguration)) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002035 if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: "
Bryce Leef858b572017-06-29 14:03:33 -07002036 + mPendingMergedConfiguration.getMergedConfiguration());
Andrii Kulian44607962017-03-16 11:06:24 -07002037 performConfigurationChange(mPendingMergedConfiguration, !mFirst,
2038 INVALID_DISPLAY /* same display */);
Chet Haased86fb2c2016-05-04 07:26:02 -07002039 updatedConfiguration = true;
Dianne Hackborn694f79b2010-03-17 19:44:59 -07002040 }
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07002041
Dianne Hackbornc4aad012013-02-22 15:05:25 -08002042 final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
2043 mAttachInfo.mOverscanInsets);
Chong Zhang75eccbd2016-07-12 19:25:08 -07002044 contentInsetsChanged = !mPendingContentInsets.equals(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002045 mAttachInfo.mContentInsets);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08002046 final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002047 mAttachInfo.mVisibleInsets);
Adrian Roosfa104232014-06-20 16:10:14 -07002048 final boolean stableInsetsChanged = !mPendingStableInsets.equals(
2049 mAttachInfo.mStableInsets);
Adrian Roos5c6b6222017-11-07 17:36:10 +01002050 final boolean cutoutChanged = !mPendingDisplayCutout.equals(
2051 mAttachInfo.mDisplayCutout);
Filip Gruszczynski2217f612015-05-26 11:32:08 -07002052 final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets);
Chong Zhangf4abc2b2015-11-12 23:40:58 -08002053 final boolean surfaceSizeChanged = (relayoutResult
2054 & WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
Adrian Roosdcf50a4f2018-01-29 18:31:34 +01002055 surfaceChanged |= surfaceSizeChanged;
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08002056 final boolean alwaysConsumeNavBarChanged =
2057 mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002058 if (contentInsetsChanged) {
2059 mAttachInfo.mContentInsets.set(mPendingContentInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002060 if (DEBUG_LAYOUT) Log.v(mTag, "Content insets changing to: "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002061 + mAttachInfo.mContentInsets);
2062 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08002063 if (overscanInsetsChanged) {
2064 mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002065 if (DEBUG_LAYOUT) Log.v(mTag, "Overscan insets changing to: "
Dianne Hackbornc4aad012013-02-22 15:05:25 -08002066 + mAttachInfo.mOverscanInsets);
2067 // Need to relayout with content insets.
2068 contentInsetsChanged = true;
2069 }
Adrian Roosfa104232014-06-20 16:10:14 -07002070 if (stableInsetsChanged) {
2071 mAttachInfo.mStableInsets.set(mPendingStableInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002072 if (DEBUG_LAYOUT) Log.v(mTag, "Decor insets changing to: "
Adrian Roosfa104232014-06-20 16:10:14 -07002073 + mAttachInfo.mStableInsets);
2074 // Need to relayout with content insets.
2075 contentInsetsChanged = true;
2076 }
Adrian Roos5c6b6222017-11-07 17:36:10 +01002077 if (cutoutChanged) {
2078 mAttachInfo.mDisplayCutout.set(mPendingDisplayCutout);
2079 if (DEBUG_LAYOUT) {
2080 Log.v(mTag, "DisplayCutout changing to: " + mAttachInfo.mDisplayCutout);
2081 }
2082 // Need to relayout with content insets.
2083 contentInsetsChanged = true;
2084 }
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08002085 if (alwaysConsumeNavBarChanged) {
2086 mAttachInfo.mAlwaysConsumeNavBar = mPendingAlwaysConsumeNavBar;
2087 contentInsetsChanged = true;
2088 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002089 if (contentInsetsChanged || mLastSystemUiVisibility !=
Adrian Roosfa104232014-06-20 16:10:14 -07002090 mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested
Filip Gruszczynski2217f612015-05-26 11:32:08 -07002091 || mLastOverscanRequested != mAttachInfo.mOverscanRequested
2092 || outsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002093 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08002094 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Filip Gruszczynski2217f612015-05-26 11:32:08 -07002095 mAttachInfo.mOutsets.set(mPendingOutsets);
Adrian Roosfa104232014-06-20 16:10:14 -07002096 mApplyInsetsRequested = false;
Adam Powell2accbf92014-04-16 23:14:57 +00002097 dispatchApplyInsets(host);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002098 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002099 if (visibleInsetsChanged) {
2100 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002101 if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002102 + mAttachInfo.mVisibleInsets);
2103 }
2104
2105 if (!hadSurface) {
2106 if (mSurface.isValid()) {
2107 // If we are creating a new surface, then we need to
2108 // completely redraw it. Also, when we get to the
2109 // point of drawing it we will hold off and schedule
2110 // a new traversal instead. This is so we can tell the
2111 // window manager about all of the windows being displayed
2112 // before actually drawing them, so it can display then
2113 // all at once.
2114 newSurface = true;
Jeff Brown96e942d2011-11-30 19:55:01 -08002115 mFullRedrawNeeded = true;
Jack Palevich61a6e682009-10-09 17:37:50 -07002116 mPreviousTransparentRegion.setEmpty();
Romain Guy8506ab42009-06-11 17:35:47 -07002117
John Reck63005e62015-05-19 15:00:13 -07002118 // Only initialize up-front if transparent regions are not
2119 // requested, otherwise defer to see if the entire window
2120 // will be transparent
Stan Iliev45faba52016-06-28 13:33:15 -04002121 if (mAttachInfo.mThreadedRenderer != null) {
Dianne Hackborn64825172011-03-02 21:32:58 -08002122 try {
Stan Iliev45faba52016-06-28 13:33:15 -04002123 hwInitialized = mAttachInfo.mThreadedRenderer.initialize(
John Reck79d81e62013-11-05 13:26:57 -08002124 mSurface);
John Reck63005e62015-05-19 15:00:13 -07002125 if (hwInitialized && (host.mPrivateFlags
2126 & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
2127 // Don't pre-allocate if transparent regions
2128 // are requested as they may not be needed
Jorim Jaggi7823ee72018-07-17 15:24:16 +02002129 mAttachInfo.mThreadedRenderer.allocateBuffers(mSurface);
John Reck63005e62015-05-19 15:00:13 -07002130 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07002131 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002132 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08002133 return;
2134 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002135 }
2136 }
2137 } else if (!mSurface.isValid()) {
2138 // If the surface has been removed, then reset the scroll
2139 // positions.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002140 if (mLastScrolledFocus != null) {
2141 mLastScrolledFocus.clear();
2142 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002143 mScrollY = mCurScrollY = 0;
Adrian Roos0e7ae4e2014-10-01 15:33:22 +02002144 if (mView instanceof RootViewSurfaceTaker) {
2145 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
2146 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002147 if (mScroller != null) {
2148 mScroller.abortAnimation();
2149 }
Romain Guy1d0c7082011-08-03 16:22:24 -07002150 // Our surface is gone
Stan Iliev45faba52016-06-28 13:33:15 -04002151 if (mAttachInfo.mThreadedRenderer != null &&
2152 mAttachInfo.mThreadedRenderer.isEnabled()) {
2153 mAttachInfo.mThreadedRenderer.destroy();
Romain Guy1d0c7082011-08-03 16:22:24 -07002154 }
Chong Zhangf4abc2b2015-11-12 23:40:58 -08002155 } else if ((surfaceGenerationId != mSurface.getGenerationId()
Andrii Kulianb2e37802017-01-11 00:36:44 -08002156 || surfaceSizeChanged || windowRelayoutWasForced)
Chong Zhangf4abc2b2015-11-12 23:40:58 -08002157 && mSurfaceHolder == null
Stan Iliev45faba52016-06-28 13:33:15 -04002158 && mAttachInfo.mThreadedRenderer != null) {
Jeff Brown96e942d2011-11-30 19:55:01 -08002159 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08002160 try {
Chong Zhangf4abc2b2015-11-12 23:40:58 -08002161 // Need to do updateSurface (which leads to CanvasContext::setSurface and
2162 // re-create the EGLSurface) if either the Surface changed (as indicated by
2163 // generation id), or WindowManager changed the surface size. The latter is
2164 // because on some chips, changing the consumer side's BufferQueue size may
2165 // not take effect immediately unless we create a new EGLSurface.
2166 // Note that frame size change doesn't always imply surface size change (eg.
2167 // drag resizing uses fullscreen surface), need to check surfaceSizeChanged
2168 // flag from WindowManager.
Stan Iliev45faba52016-06-28 13:33:15 -04002169 mAttachInfo.mThreadedRenderer.updateSurface(mSurface);
Igor Murashkina86ab6402013-08-30 12:58:36 -07002170 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002171 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08002172 return;
2173 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002174 }
Chong Zhang0275e392015-09-17 10:41:44 -07002175
Jorim Jaggi4846ee32016-01-07 17:39:12 +01002176 final boolean freeformResizing = (relayoutResult
2177 & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFORM) != 0;
2178 final boolean dockedResizing = (relayoutResult
2179 & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_DOCKED) != 0;
2180 final boolean dragResizing = freeformResizing || dockedResizing;
Chong Zhang0275e392015-09-17 10:41:44 -07002181 if (mDragResizing != dragResizing) {
Skuhneb8160872015-09-22 09:51:39 -07002182 if (dragResizing) {
Jorim Jaggi4846ee32016-01-07 17:39:12 +01002183 mResizeMode = freeformResizing
2184 ? RESIZE_MODE_FREEFORM
2185 : RESIZE_MODE_DOCKED_DIVIDER;
Adrian Roos5c6b6222017-11-07 17:36:10 +01002186 // TODO: Need cutout?
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002187 startDragResizing(mPendingBackDropFrame,
2188 mWinFrame.equals(mPendingBackDropFrame), mPendingVisibleInsets,
2189 mPendingStableInsets, mResizeMode);
Skuhneb8160872015-09-22 09:51:39 -07002190 } else {
2191 // We shouldn't come here, but if we come we should end the resize.
2192 endDragResizing();
2193 }
Chong Zhang0275e392015-09-17 10:41:44 -07002194 }
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09002195 if (!mUseMTRenderer) {
Skuhneb8160872015-09-22 09:51:39 -07002196 if (dragResizing) {
2197 mCanvasOffsetX = mWinFrame.left;
2198 mCanvasOffsetY = mWinFrame.top;
2199 } else {
2200 mCanvasOffsetX = mCanvasOffsetY = 0;
2201 }
Chong Zhang0275e392015-09-17 10:41:44 -07002202 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002203 } catch (RemoteException e) {
2204 }
Romain Guy1d0c7082011-08-03 16:22:24 -07002205
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002206 if (DEBUG_ORIENTATION) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07002207 TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002208
Chris Craikd36a81f2014-07-17 10:16:51 -07002209 mAttachInfo.mWindowLeft = frame.left;
2210 mAttachInfo.mWindowTop = frame.top;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002211
2212 // !!FIXME!! This next section handles the case where we did not get the
2213 // window size we asked for. We should avoid this by getting a maximum size from
2214 // the window session beforehand.
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07002215 if (mWidth != frame.width() || mHeight != frame.height()) {
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07002216 mWidth = frame.width();
2217 mHeight = frame.height();
2218 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002219
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002220 if (mSurfaceHolder != null) {
2221 // The app owns the surface; tell it about what is going on.
2222 if (mSurface.isValid()) {
2223 // XXX .copyFrom() doesn't work!
2224 //mSurfaceHolder.mSurface.copyFrom(mSurface);
2225 mSurfaceHolder.mSurface = mSurface;
2226 }
Jeff Brown30bc34f2011-01-25 12:56:56 -08002227 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002228 mSurfaceHolder.mSurfaceLock.unlock();
2229 if (mSurface.isValid()) {
John Reck208c47c2016-06-09 16:26:21 -07002230 if (!hadSurface) {
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002231 mSurfaceHolder.ungetCallbacks();
2232
2233 mIsCreating = true;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002234 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
2235 if (callbacks != null) {
2236 for (SurfaceHolder.Callback c : callbacks) {
2237 c.surfaceCreated(mSurfaceHolder);
2238 }
2239 }
2240 surfaceChanged = true;
2241 }
John Reck208c47c2016-06-09 16:26:21 -07002242 if (surfaceChanged || surfaceGenerationId != mSurface.getGenerationId()) {
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002243 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
2244 if (callbacks != null) {
2245 for (SurfaceHolder.Callback c : callbacks) {
2246 c.surfaceChanged(mSurfaceHolder, lp.format,
2247 mWidth, mHeight);
2248 }
2249 }
2250 }
2251 mIsCreating = false;
2252 } else if (hadSurface) {
2253 mSurfaceHolder.ungetCallbacks();
2254 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002255 if (callbacks != null) {
2256 for (SurfaceHolder.Callback c : callbacks) {
2257 c.surfaceDestroyed(mSurfaceHolder);
2258 }
2259 }
2260 mSurfaceHolder.mSurfaceLock.lock();
Jozef BABJAK93c5b6a2011-02-22 09:33:19 +01002261 try {
2262 mSurfaceHolder.mSurface = new Surface();
2263 } finally {
2264 mSurfaceHolder.mSurfaceLock.unlock();
2265 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002266 }
2267 }
Romain Guy53389bd2010-09-07 17:16:32 -07002268
Stan Iliev45faba52016-06-28 13:33:15 -04002269 final ThreadedRenderer threadedRenderer = mAttachInfo.mThreadedRenderer;
2270 if (threadedRenderer != null && threadedRenderer.isEnabled()) {
Alan Viverette50210d92015-05-14 18:05:36 -07002271 if (hwInitialized
Stan Iliev45faba52016-06-28 13:33:15 -04002272 || mWidth != threadedRenderer.getWidth()
2273 || mHeight != threadedRenderer.getHeight()
2274 || mNeedsRendererSetup) {
2275 threadedRenderer.setup(mWidth, mHeight, mAttachInfo,
Alan Viverette50210d92015-05-14 18:05:36 -07002276 mWindowAttributes.surfaceInsets);
Stan Iliev45faba52016-06-28 13:33:15 -04002277 mNeedsRendererSetup = false;
Romain Guy03985752011-07-11 15:33:51 -07002278 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002279 }
2280
Craig Mautner72d6f212015-02-19 16:33:09 -08002281 if (!mStopped || mReportNextDraw) {
Dianne Hackbornce418e62011-03-01 14:31:38 -08002282 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
Jeff Brown98365d72012-08-19 20:30:52 -07002283 (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
Dianne Hackbornce418e62011-03-01 14:31:38 -08002284 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
Chong Zhang75eccbd2016-07-12 19:25:08 -07002285 || mHeight != host.getMeasuredHeight() || contentInsetsChanged ||
Chet Haased86fb2c2016-05-04 07:26:02 -07002286 updatedConfiguration) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002287 int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
2288 int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
Igor Murashkina86ab6402013-08-30 12:58:36 -07002289
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002290 if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed! mWidth="
Dianne Hackbornce418e62011-03-01 14:31:38 -08002291 + mWidth + " measuredWidth=" + host.getMeasuredWidth()
2292 + " mHeight=" + mHeight
2293 + " measuredHeight=" + host.getMeasuredHeight()
Chong Zhang75eccbd2016-07-12 19:25:08 -07002294 + " coveredInsetsChanged=" + contentInsetsChanged);
Igor Murashkina86ab6402013-08-30 12:58:36 -07002295
Dianne Hackbornce418e62011-03-01 14:31:38 -08002296 // Ask host how big it wants to be
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002297 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Igor Murashkina86ab6402013-08-30 12:58:36 -07002298
Dianne Hackbornce418e62011-03-01 14:31:38 -08002299 // Implementation of weights from WindowManager.LayoutParams
2300 // We just grow the dimensions as needed and re-measure if
2301 // needs be
2302 int width = host.getMeasuredWidth();
2303 int height = host.getMeasuredHeight();
2304 boolean measureAgain = false;
Igor Murashkina86ab6402013-08-30 12:58:36 -07002305
Dianne Hackbornce418e62011-03-01 14:31:38 -08002306 if (lp.horizontalWeight > 0.0f) {
2307 width += (int) ((mWidth - width) * lp.horizontalWeight);
2308 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
2309 MeasureSpec.EXACTLY);
2310 measureAgain = true;
2311 }
2312 if (lp.verticalWeight > 0.0f) {
2313 height += (int) ((mHeight - height) * lp.verticalWeight);
2314 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
2315 MeasureSpec.EXACTLY);
2316 measureAgain = true;
2317 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07002318
Dianne Hackbornce418e62011-03-01 14:31:38 -08002319 if (measureAgain) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002320 if (DEBUG_LAYOUT) Log.v(mTag,
Dianne Hackbornce418e62011-03-01 14:31:38 -08002321 "And hey let's measure once more: width=" + width
2322 + " height=" + height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002323 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackbornce418e62011-03-01 14:31:38 -08002324 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07002325
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002326 layoutRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002327 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002328 }
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07002329 } else {
2330 // Not the first pass and no window/insets/visibility change but the window
2331 // may have moved and we need check that and if so to update the left and right
2332 // in the attach info. We translate only the window frame since on window move
2333 // the window manager tells us only for the new frame but the insets are the
2334 // same and we do not want to translate them more than once.
Jorim Jaggi2e95a482016-01-14 17:36:55 -08002335 maybeHandleWindowMove(frame);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002336 }
2337
Craig Mautner72d6f212015-02-19 16:33:09 -08002338 final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002339 boolean triggerGlobalLayoutListener = didLayout
Chris Craikd36a81f2014-07-17 10:16:51 -07002340 || mAttachInfo.mRecomputeGlobalAttributes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002341 if (didLayout) {
Jorim Jaggi26d02d22016-02-24 18:37:51 -05002342 performLayout(lp, mWidth, mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002343
Mathias Agopian54e3d3842013-04-12 15:13:12 -07002344 // By this point all views have been sized and positioned
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002345 // We can compute the transparent area
2346
Dianne Hackborn4702a852012-08-17 15:18:29 -07002347 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002348 // start out transparent
2349 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
2350 host.getLocationInWindow(mTmpLocation);
2351 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
2352 mTmpLocation[0] + host.mRight - host.mLeft,
2353 mTmpLocation[1] + host.mBottom - host.mTop);
2354
2355 host.gatherTransparentRegion(mTransparentRegion);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07002356 if (mTranslator != null) {
2357 mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
2358 }
2359
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002360 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
2361 mPreviousTransparentRegion.set(mTransparentRegion);
Mathias Agopian54e3d3842013-04-12 15:13:12 -07002362 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002363 // reconfigure window manager
2364 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002365 mWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002366 } catch (RemoteException e) {
2367 }
2368 }
2369 }
2370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002371 if (DBG) {
2372 System.out.println("======================================");
Chet Haase4610eef2015-12-03 07:38:11 -08002373 System.out.println("performTraversals -- after setFrame");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002374 host.debug();
2375 }
2376 }
2377
2378 if (triggerGlobalLayoutListener) {
Chris Craikd36a81f2014-07-17 10:16:51 -07002379 mAttachInfo.mRecomputeGlobalAttributes = false;
2380 mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002381 }
2382
2383 if (computesInternalInsets) {
Jeff Brownfbf09772011-01-16 14:06:57 -08002384 // Clear the original insets.
Chris Craikd36a81f2014-07-17 10:16:51 -07002385 final ViewTreeObserver.InternalInsetsInfo insets = mAttachInfo.mGivenInternalInsets;
Jeff Brownfbf09772011-01-16 14:06:57 -08002386 insets.reset();
2387
2388 // Compute new insets in place.
Chris Craikd36a81f2014-07-17 10:16:51 -07002389 mAttachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
2390 mAttachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty();
Jeff Brownfbf09772011-01-16 14:06:57 -08002391
2392 // Tell the window manager.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002393 if (insetsPending || !mLastGivenInsets.equals(insets)) {
2394 mLastGivenInsets.set(insets);
Jeff Brownfbf09772011-01-16 14:06:57 -08002395
2396 // Translate insets to screen coordinates if needed.
2397 final Rect contentInsets;
2398 final Rect visibleInsets;
2399 final Region touchableRegion;
2400 if (mTranslator != null) {
2401 contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
2402 visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
2403 touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
2404 } else {
2405 contentInsets = insets.contentInsets;
2406 visibleInsets = insets.visibleInsets;
2407 touchableRegion = insets.touchableRegion;
2408 }
2409
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002410 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002411 mWindowSession.setInsets(mWindow, insets.mTouchableInsets,
Jeff Brownfbf09772011-01-16 14:06:57 -08002412 contentInsets, visibleInsets, touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002413 } catch (RemoteException e) {
2414 }
2415 }
2416 }
Romain Guy8506ab42009-06-11 17:35:47 -07002417
Evan Roskyadf5bec2017-10-19 10:24:07 -07002418 if (mFirst) {
Evan Roskybdc66cb2017-09-08 14:27:24 -07002419 if (sAlwaysAssignFocus || !isInTouchMode()) {
Evan Roskyadf5bec2017-10-19 10:24:07 -07002420 // handle first focus request
2421 if (DEBUG_INPUT_RESIZE) {
2422 Log.v(mTag, "First: mView.hasFocus()=" + mView.hasFocus());
2423 }
2424 if (mView != null) {
2425 if (!mView.hasFocus()) {
2426 mView.restoreDefaultFocus();
2427 if (DEBUG_INPUT_RESIZE) {
2428 Log.v(mTag, "First: requested focused view=" + mView.findFocus());
2429 }
2430 } else {
2431 if (DEBUG_INPUT_RESIZE) {
2432 Log.v(mTag, "First: existing focused view=" + mView.findFocus());
2433 }
2434 }
2435 }
2436 } else {
2437 // Some views (like ScrollView) won't hand focus to descendants that aren't within
2438 // their viewport. Before layout, there's a good change these views are size 0
2439 // which means no children can get focus. After layout, this view now has size, but
2440 // is not guaranteed to hand-off focus to a focusable child (specifically, the edge-
2441 // case where the child has a size prior to layout and thus won't trigger
2442 // focusableViewAvailable).
2443 View focused = mView.findFocus();
2444 if (focused instanceof ViewGroup
2445 && ((ViewGroup) focused).getDescendantFocusability()
2446 == ViewGroup.FOCUS_AFTER_DESCENDANTS) {
2447 focused.restoreDefaultFocus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002448 }
2449 }
2450 }
2451
Alan Viverette64bf97a2015-09-18 16:42:00 -04002452 final boolean changedVisibility = (viewVisibilityChanged || mFirst) && isViewVisible;
2453 final boolean hasWindowFocus = mAttachInfo.mHasWindowFocus && isViewVisible;
2454 final boolean regainedFocus = hasWindowFocus && mLostWindowFocus;
2455 if (regainedFocus) {
2456 mLostWindowFocus = false;
2457 } else if (!hasWindowFocus && mHadWindowFocus) {
2458 mLostWindowFocus = true;
2459 }
2460
2461 if (changedVisibility || regainedFocus) {
Phil Weaver532c7992016-08-29 15:59:03 -07002462 // Toasts are presented as notifications - don't present them as windows as well
2463 boolean isToast = (mWindowAttributes == null) ? false
2464 : (mWindowAttributes.type == WindowManager.LayoutParams.TYPE_TOAST);
2465 if (!isToast) {
2466 host.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
2467 }
Alan Viverette64bf97a2015-09-18 16:42:00 -04002468 }
2469
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002470 mFirst = false;
2471 mWillDrawSoon = false;
2472 mNewSurfaceNeeded = false;
Jorim Jaggi4846ee32016-01-07 17:39:12 +01002473 mActivityRelaunched = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002474 mViewVisibility = viewVisibility;
Alan Viverette64bf97a2015-09-18 16:42:00 -04002475 mHadWindowFocus = hasWindowFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002476
Alan Viverette64bf97a2015-09-18 16:42:00 -04002477 if (hasWindowFocus && !isInLocalFocusMode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002478 final boolean imTarget = WindowManager.LayoutParams
2479 .mayUseInputMethod(mWindowAttributes.flags);
2480 if (imTarget != mLastWasImTarget) {
2481 mLastWasImTarget = imTarget;
2482 InputMethodManager imm = InputMethodManager.peekInstance();
2483 if (imm != null && imTarget) {
Alan Viverette64bf97a2015-09-18 16:42:00 -04002484 imm.onPreWindowFocus(mView, hasWindowFocus);
Yohei Yukawa5f059652015-05-14 22:16:41 -07002485 imm.onPostWindowFocus(mView, mView.findFocus(),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002486 mWindowAttributes.softInputMode,
2487 !mHasHadWindowFocus, mWindowAttributes.flags);
2488 }
2489 }
2490 }
Romain Guy8506ab42009-06-11 17:35:47 -07002491
Jeff Brown96e942d2011-11-30 19:55:01 -08002492 // Remember if we must report the next draw.
Jeff Brown98365d72012-08-19 20:30:52 -07002493 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
Robert Carr49cd9f82017-05-25 18:24:42 -07002494 reportNextDraw();
Jeff Brown96e942d2011-11-30 19:55:01 -08002495 }
2496
Alan Viverette64bf97a2015-09-18 16:42:00 -04002497 boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002498
Jorim Jaggi75c21ca2016-03-28 19:26:09 -04002499 if (!cancelDraw && !newSurface) {
Chet Haase9c450412015-10-01 13:25:58 -07002500 if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
2501 for (int i = 0; i < mPendingTransitions.size(); ++i) {
2502 mPendingTransitions.get(i).startChangingAnimations();
Chet Haased56c6952011-09-07 08:46:23 -07002503 }
Chet Haase9c450412015-10-01 13:25:58 -07002504 mPendingTransitions.clear();
Chet Haased56c6952011-09-07 08:46:23 -07002505 }
Chet Haase9c450412015-10-01 13:25:58 -07002506
2507 performDraw();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002508 } else {
Alan Viverette64bf97a2015-09-18 16:42:00 -04002509 if (isViewVisible) {
Chris Wren78cb7cf2012-05-15 12:36:44 -04002510 // Try again
2511 scheduleTraversals();
2512 } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
Chet Haased56c6952011-09-07 08:46:23 -07002513 for (int i = 0; i < mPendingTransitions.size(); ++i) {
2514 mPendingTransitions.get(i).endChangingAnimations();
2515 }
2516 mPendingTransitions.clear();
2517 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002518 }
Craig Mautnerdf2390a2012-08-29 20:59:22 -07002519
2520 mIsInTraversal = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002521 }
2522
Jorim Jaggi2e95a482016-01-14 17:36:55 -08002523 private void maybeHandleWindowMove(Rect frame) {
2524
2525 // TODO: Well, we are checking whether the frame has changed similarly
2526 // to how this is done for the insets. This is however incorrect since
2527 // the insets and the frame are translated. For example, the old frame
2528 // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new
2529 // reported frame is (2, 2 - 2, 2) which implies no change but this is not
2530 // true since we are comparing a not translated value to a translated one.
2531 // This scenario is rare but we may want to fix that.
2532
2533 final boolean windowMoved = mAttachInfo.mWindowLeft != frame.left
2534 || mAttachInfo.mWindowTop != frame.top;
2535 if (windowMoved) {
2536 if (mTranslator != null) {
2537 mTranslator.translateRectInScreenToAppWinFrame(frame);
2538 }
2539 mAttachInfo.mWindowLeft = frame.left;
2540 mAttachInfo.mWindowTop = frame.top;
Teng-Hui Zhu27571282016-05-12 15:53:53 -07002541 }
2542 if (windowMoved || mAttachInfo.mNeedsUpdateLightCenter) {
2543 // Update the light position for the new offsets.
Stan Iliev45faba52016-06-28 13:33:15 -04002544 if (mAttachInfo.mThreadedRenderer != null) {
2545 mAttachInfo.mThreadedRenderer.setLightCenter(mAttachInfo);
Jorim Jaggi2e95a482016-01-14 17:36:55 -08002546 }
Teng-Hui Zhu27571282016-05-12 15:53:53 -07002547 mAttachInfo.mNeedsUpdateLightCenter = false;
Jorim Jaggi2e95a482016-01-14 17:36:55 -08002548 }
2549 }
Teng-Hui Zhu27571282016-05-12 15:53:53 -07002550
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08002551 private void handleWindowFocusChanged() {
2552 final boolean hasWindowFocus;
2553 final boolean inTouchMode;
2554 synchronized (this) {
Dianne Hackborn011944c2017-12-15 15:44:55 -08002555 if (!mWindowFocusChanged) {
2556 return;
2557 }
2558 mWindowFocusChanged = false;
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08002559 hasWindowFocus = mUpcomingWindowFocus;
2560 inTouchMode = mUpcomingInTouchMode;
2561 }
2562
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08002563 if (mAdded) {
2564 profileRendering(hasWindowFocus);
2565
2566 if (hasWindowFocus) {
2567 ensureTouchModeLocally(inTouchMode);
2568 if (mAttachInfo.mThreadedRenderer != null && mSurface.isValid()) {
2569 mFullRedrawNeeded = true;
2570 try {
2571 final WindowManager.LayoutParams lp = mWindowAttributes;
2572 final Rect surfaceInsets = lp != null ? lp.surfaceInsets : null;
2573 mAttachInfo.mThreadedRenderer.initializeIfNeeded(
2574 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
2575 } catch (OutOfResourcesException e) {
2576 Log.e(mTag, "OutOfResourcesException locking surface", e);
2577 try {
2578 if (!mWindowSession.outOfMemory(mWindow)) {
2579 Slog.w(mTag, "No processes killed for memory;"
2580 + " killing self");
2581 Process.killProcess(Process.myPid());
2582 }
2583 } catch (RemoteException ex) {
2584 }
2585 // Retry in a bit.
2586 mHandler.sendMessageDelayed(mHandler.obtainMessage(
2587 MSG_WINDOW_FOCUS_CHANGED), 500);
2588 return;
2589 }
2590 }
2591 }
2592
2593 mAttachInfo.mHasWindowFocus = hasWindowFocus;
2594
2595 mLastWasImTarget = WindowManager.LayoutParams
2596 .mayUseInputMethod(mWindowAttributes.flags);
2597
2598 InputMethodManager imm = InputMethodManager.peekInstance();
2599 if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
2600 imm.onPreWindowFocus(mView, hasWindowFocus);
2601 }
2602 if (mView != null) {
2603 mAttachInfo.mKeyDispatchState.reset();
2604 mView.dispatchWindowFocusChanged(hasWindowFocus);
2605 mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
2606
2607 if (mAttachInfo.mTooltipHost != null) {
2608 mAttachInfo.mTooltipHost.hideTooltip();
2609 }
2610 }
2611
2612 // Note: must be done after the focus change callbacks,
2613 // so all of the view state is set up correctly.
2614 if (hasWindowFocus) {
2615 if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
2616 imm.onPostWindowFocus(mView, mView.findFocus(),
2617 mWindowAttributes.softInputMode,
2618 !mHasHadWindowFocus, mWindowAttributes.flags);
2619 }
2620 // Clear the forward bit. We can just do this directly, since
2621 // the window manager doesn't care about it.
2622 mWindowAttributes.softInputMode &=
2623 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
2624 ((WindowManager.LayoutParams) mView.getLayoutParams())
2625 .softInputMode &=
2626 ~WindowManager.LayoutParams
2627 .SOFT_INPUT_IS_FORWARD_NAVIGATION;
2628 mHasHadWindowFocus = true;
Svetoslav Ganov24c90452017-12-27 15:17:14 -08002629
2630 // Refocusing a window that has a focused view should fire a
2631 // focus event for the view since the global focused view changed.
2632 fireAccessibilityFocusEventIfHasFocusedNode();
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08002633 } else {
2634 if (mPointerCapture) {
2635 handlePointerCaptureChanged(false);
2636 }
2637 }
2638 }
2639 mFirstInputStage.onWindowFocusChanged(hasWindowFocus);
2640 }
2641
Svetoslav Ganov24c90452017-12-27 15:17:14 -08002642 private void fireAccessibilityFocusEventIfHasFocusedNode() {
2643 if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
2644 return;
2645 }
2646 final View focusedView = mView.findFocus();
2647 if (focusedView == null) {
2648 return;
2649 }
2650 final AccessibilityNodeProvider provider = focusedView.getAccessibilityNodeProvider();
2651 if (provider == null) {
2652 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
2653 } else {
2654 final AccessibilityNodeInfo focusedNode = findFocusedVirtualNode(provider);
2655 if (focusedNode != null) {
2656 final int virtualId = AccessibilityNodeInfo.getVirtualDescendantId(
2657 focusedNode.getSourceNodeId());
2658 // This is a best effort since clearing and setting the focus via the
2659 // provider APIs could have side effects. We don't have a provider API
2660 // similar to that on View to ask a given event to be fired.
2661 final AccessibilityEvent event = AccessibilityEvent.obtain(
2662 AccessibilityEvent.TYPE_VIEW_FOCUSED);
2663 event.setSource(focusedView, virtualId);
2664 event.setPackageName(focusedNode.getPackageName());
2665 event.setChecked(focusedNode.isChecked());
2666 event.setContentDescription(focusedNode.getContentDescription());
2667 event.setPassword(focusedNode.isPassword());
2668 event.getText().add(focusedNode.getText());
2669 event.setEnabled(focusedNode.isEnabled());
2670 focusedView.getParent().requestSendAccessibilityEvent(focusedView, event);
2671 focusedNode.recycle();
2672 }
2673 }
2674 }
2675
2676 private AccessibilityNodeInfo findFocusedVirtualNode(AccessibilityNodeProvider provider) {
2677 AccessibilityNodeInfo focusedNode = provider.findFocus(
2678 AccessibilityNodeInfo.FOCUS_INPUT);
2679 if (focusedNode != null) {
2680 return focusedNode;
2681 }
2682
2683 if (!mContext.isAutofillCompatibilityEnabled()) {
2684 return null;
2685 }
2686
2687 // Unfortunately some provider implementations don't properly
2688 // implement AccessibilityNodeProvider#findFocus
2689 AccessibilityNodeInfo current = provider.createAccessibilityNodeInfo(
2690 AccessibilityNodeProvider.HOST_VIEW_ID);
2691 if (current.isFocused()) {
2692 return current;
2693 }
2694
2695 final Queue<AccessibilityNodeInfo> fringe = new LinkedList<>();
2696 fringe.offer(current);
2697
2698 while (!fringe.isEmpty()) {
2699 current = fringe.poll();
2700 final LongArray childNodeIds = current.getChildNodeIds();
2701 if (childNodeIds== null || childNodeIds.size() <= 0) {
2702 continue;
2703 }
2704 final int childCount = childNodeIds.size();
2705 for (int i = 0; i < childCount; i++) {
2706 final int virtualId = AccessibilityNodeInfo.getVirtualDescendantId(
2707 childNodeIds.get(i));
2708 final AccessibilityNodeInfo child = provider.createAccessibilityNodeInfo(virtualId);
2709 if (child != null) {
2710 if (child.isFocused()) {
2711 return child;
2712 }
2713 fringe.offer(child);
2714 }
2715 }
2716 current.recycle();
2717 }
2718
2719 return null;
2720 }
2721
Romain Guy3696779b2013-01-28 14:04:07 -08002722 private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002723 Log.e(mTag, "OutOfResourcesException initializing HW surface", e);
Romain Guy3696779b2013-01-28 14:04:07 -08002724 try {
2725 if (!mWindowSession.outOfMemory(mWindow) &&
2726 Process.myUid() != Process.SYSTEM_UID) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002727 Slog.w(mTag, "No processes killed for memory; killing self");
Romain Guy3696779b2013-01-28 14:04:07 -08002728 Process.killProcess(Process.myPid());
2729 }
2730 } catch (RemoteException ex) {
2731 }
2732 mLayoutRequested = true; // ask wm for a new surface next time.
2733 }
2734
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002735 private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
Robert Carr001e55a2017-05-15 17:21:38 -07002736 if (mView == null) {
2737 return;
2738 }
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002739 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
2740 try {
2741 mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
2742 } finally {
2743 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2744 }
2745 }
2746
Chet Haase97140572012-09-13 14:56:47 -07002747 /**
2748 * Called by {@link android.view.View#isInLayout()} to determine whether the view hierarchy
2749 * is currently undergoing a layout pass.
2750 *
2751 * @return whether the view hierarchy is currently undergoing a layout pass
2752 */
2753 boolean isInLayout() {
2754 return mInLayout;
2755 }
2756
2757 /**
Chet Haasecc699b42012-12-13 09:06:55 -08002758 * Called by {@link android.view.View#requestLayout()} if the view hierarchy is currently
2759 * undergoing a layout pass. requestLayout() should not generally be called during layout,
2760 * unless the container hierarchy knows what it is doing (i.e., it is fine as long as
2761 * all children in that container hierarchy are measured and laid out at the end of the layout
2762 * pass for that container). If requestLayout() is called anyway, we handle it correctly
2763 * by registering all requesters during a frame as it proceeds. At the end of the frame,
2764 * we check all of those views to see if any still have pending layout requests, which
2765 * indicates that they were not correctly handled by their container hierarchy. If that is
2766 * the case, we clear all such flags in the tree, to remove the buggy flag state that leads
2767 * to blank containers, and force a second request/measure/layout pass in this frame. If
Chet Haase97140572012-09-13 14:56:47 -07002768 * more requestLayout() calls are received during that second layout pass, we post those
Chet Haasecc699b42012-12-13 09:06:55 -08002769 * requests to the next frame to avoid possible infinite loops.
2770 *
2771 * <p>The return value from this method indicates whether the request should proceed
2772 * (if it is a request during the first layout pass) or should be skipped and posted to the
2773 * next frame (if it is a request during the second layout pass).</p>
Chet Haase97140572012-09-13 14:56:47 -07002774 *
2775 * @param view the view that requested the layout.
Chet Haasecc699b42012-12-13 09:06:55 -08002776 *
2777 * @return true if request should proceed, false otherwise.
Chet Haase97140572012-09-13 14:56:47 -07002778 */
Chet Haasecc699b42012-12-13 09:06:55 -08002779 boolean requestLayoutDuringLayout(final View view) {
2780 if (view.mParent == null || view.mAttachInfo == null) {
2781 // Would not normally trigger another layout, so just let it pass through as usual
2782 return true;
2783 }
Chet Haase107a4822013-03-13 06:46:50 -07002784 if (!mLayoutRequesters.contains(view)) {
2785 mLayoutRequesters.add(view);
2786 }
Chet Haase97140572012-09-13 14:56:47 -07002787 if (!mHandlingLayoutInLayoutRequest) {
Chet Haase107a4822013-03-13 06:46:50 -07002788 // Let the request proceed normally; it will be processed in a second layout pass
2789 // if necessary
Chet Haasecc699b42012-12-13 09:06:55 -08002790 return true;
Chet Haase97140572012-09-13 14:56:47 -07002791 } else {
Chet Haase107a4822013-03-13 06:46:50 -07002792 // Don't let the request proceed during the second layout pass.
2793 // It will post to the next frame instead.
Chet Haasecc699b42012-12-13 09:06:55 -08002794 return false;
Chet Haase97140572012-09-13 14:56:47 -07002795 }
2796 }
2797
Chet Haase3efa7b52012-12-03 08:33:17 -08002798 private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
2799 int desiredWindowHeight) {
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002800 mLayoutRequested = false;
2801 mScrollMayChange = true;
Chet Haase97140572012-09-13 14:56:47 -07002802 mInLayout = true;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002803
2804 final View host = mView;
Robert Carr32f37ab2017-06-15 12:39:34 -07002805 if (host == null) {
2806 return;
2807 }
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002808 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002809 Log.v(mTag, "Laying out " + host + " to (" +
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002810 host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
2811 }
2812
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002813 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
2814 try {
2815 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haasecc699b42012-12-13 09:06:55 -08002816
Chet Haased5a83522012-11-21 16:24:44 -08002817 mInLayout = false;
Chet Haase97140572012-09-13 14:56:47 -07002818 int numViewsRequestingLayout = mLayoutRequesters.size();
2819 if (numViewsRequestingLayout > 0) {
Chet Haasecc699b42012-12-13 09:06:55 -08002820 // requestLayout() was called during layout.
2821 // If no layout-request flags are set on the requesting views, there is no problem.
2822 // If some requests are still pending, then we need to clear those flags and do
2823 // a full request/measure/layout pass to handle this situation.
Chet Haase107a4822013-03-13 06:46:50 -07002824 ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
2825 false);
2826 if (validLayoutRequesters != null) {
2827 // Set this flag to indicate that any further requests are happening during
2828 // the second pass, which may result in posting those requests to the next
2829 // frame instead
Chet Haasecc699b42012-12-13 09:06:55 -08002830 mHandlingLayoutInLayoutRequest = true;
Chet Haase107a4822013-03-13 06:46:50 -07002831
2832 // Process fresh layout requests, then measure and layout
2833 int numValidRequests = validLayoutRequesters.size();
Chet Haasecc699b42012-12-13 09:06:55 -08002834 for (int i = 0; i < numValidRequests; ++i) {
Chet Haase107a4822013-03-13 06:46:50 -07002835 final View view = validLayoutRequesters.get(i);
2836 Log.w("View", "requestLayout() improperly called by " + view +
2837 " during layout: running second layout pass");
2838 view.requestLayout();
Chet Haasecc699b42012-12-13 09:06:55 -08002839 }
2840 measureHierarchy(host, lp, mView.getContext().getResources(),
2841 desiredWindowWidth, desiredWindowHeight);
2842 mInLayout = true;
2843 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haase107a4822013-03-13 06:46:50 -07002844
Chet Haasecc699b42012-12-13 09:06:55 -08002845 mHandlingLayoutInLayoutRequest = false;
Chet Haase107a4822013-03-13 06:46:50 -07002846
2847 // Check the valid requests again, this time without checking/clearing the
2848 // layout flags, since requests happening during the second pass get noop'd
2849 validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);
2850 if (validLayoutRequesters != null) {
2851 final ArrayList<View> finalRequesters = validLayoutRequesters;
2852 // Post second-pass requests to the next frame
2853 getRunQueue().post(new Runnable() {
2854 @Override
2855 public void run() {
2856 int numValidRequests = finalRequesters.size();
2857 for (int i = 0; i < numValidRequests; ++i) {
2858 final View view = finalRequesters.get(i);
2859 Log.w("View", "requestLayout() improperly called by " + view +
2860 " during second layout pass: posting in next frame");
2861 view.requestLayout();
2862 }
2863 }
2864 });
2865 }
Chet Haasecc699b42012-12-13 09:06:55 -08002866 }
Chet Haase107a4822013-03-13 06:46:50 -07002867
Chet Haase97140572012-09-13 14:56:47 -07002868 }
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002869 } finally {
2870 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2871 }
Chet Haase97140572012-09-13 14:56:47 -07002872 mInLayout = false;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002873 }
2874
Chet Haase107a4822013-03-13 06:46:50 -07002875 /**
2876 * This method is called during layout when there have been calls to requestLayout() during
2877 * layout. It walks through the list of views that requested layout to determine which ones
2878 * still need it, based on visibility in the hierarchy and whether they have already been
2879 * handled (as is usually the case with ListView children).
2880 *
2881 * @param layoutRequesters The list of views that requested layout during layout
2882 * @param secondLayoutRequests Whether the requests were issued during the second layout pass.
2883 * If so, the FORCE_LAYOUT flag was not set on requesters.
2884 * @return A list of the actual views that still need to be laid out.
2885 */
2886 private ArrayList<View> getValidLayoutRequesters(ArrayList<View> layoutRequesters,
2887 boolean secondLayoutRequests) {
2888
2889 int numViewsRequestingLayout = layoutRequesters.size();
2890 ArrayList<View> validLayoutRequesters = null;
2891 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2892 View view = layoutRequesters.get(i);
2893 if (view != null && view.mAttachInfo != null && view.mParent != null &&
2894 (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) ==
2895 View.PFLAG_FORCE_LAYOUT)) {
2896 boolean gone = false;
2897 View parent = view;
2898 // Only trigger new requests for views in a non-GONE hierarchy
2899 while (parent != null) {
2900 if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) {
2901 gone = true;
2902 break;
2903 }
2904 if (parent.mParent instanceof View) {
2905 parent = (View) parent.mParent;
2906 } else {
2907 parent = null;
2908 }
2909 }
2910 if (!gone) {
2911 if (validLayoutRequesters == null) {
2912 validLayoutRequesters = new ArrayList<View>();
2913 }
2914 validLayoutRequesters.add(view);
2915 }
2916 }
2917 }
2918 if (!secondLayoutRequests) {
2919 // If we're checking the layout flags, then we need to clean them up also
2920 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2921 View view = layoutRequesters.get(i);
2922 while (view != null &&
2923 (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
2924 view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
2925 if (view.mParent instanceof View) {
2926 view = (View) view.mParent;
2927 } else {
2928 view = null;
2929 }
2930 }
2931 }
2932 }
2933 layoutRequesters.clear();
2934 return validLayoutRequesters;
2935 }
2936
Igor Murashkina86ab6402013-08-30 12:58:36 -07002937 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002938 public void requestTransparentRegion(View child) {
2939 // the test below should not fail unless someone is messing with us
2940 checkThread();
2941 if (mView == child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002942 mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002943 // Need to make sure we re-evaluate the window attributes next
2944 // time around, to ensure the window has the correct format.
2945 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -07002946 mWindowAttributesChangesFlag = 0;
Mathias Agopian1bd80ad2010-11-04 17:13:39 -07002947 requestLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002948 }
2949 }
2950
2951 /**
2952 * Figures out the measure spec for the root view in a window based on it's
2953 * layout params.
2954 *
2955 * @param windowSize
2956 * The available width or height of the window
2957 *
2958 * @param rootDimension
2959 * The layout params for one dimension (width or height) of the
2960 * window.
2961 *
2962 * @return The measure spec to use to measure the root view.
2963 */
Romain Guya998dff2012-03-23 18:58:36 -07002964 private static int getRootMeasureSpec(int windowSize, int rootDimension) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002965 int measureSpec;
2966 switch (rootDimension) {
2967
Romain Guy980a9382010-01-08 15:06:28 -08002968 case ViewGroup.LayoutParams.MATCH_PARENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002969 // Window can't resize. Force root view to be windowSize.
2970 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
2971 break;
2972 case ViewGroup.LayoutParams.WRAP_CONTENT:
2973 // Window can resize. Set max size for root view.
2974 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
2975 break;
2976 default:
2977 // Window wants to be an exact size. Force root view to be that size.
2978 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
2979 break;
2980 }
2981 return measureSpec;
2982 }
2983
Alan Viveretteccb11e12014-07-08 16:04:02 -07002984 int mHardwareXOffset;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002985 int mHardwareYOffset;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002986
Igor Murashkina86ab6402013-08-30 12:58:36 -07002987 @Override
Stan Iliev45faba52016-06-28 13:33:15 -04002988 public void onPreDraw(DisplayListCanvas canvas) {
John Reck3e04f092017-06-02 15:50:09 -07002989 // If mCurScrollY is not 0 then this influences the hardwareYOffset. The end result is we
2990 // can apply offsets that are not handled by anything else, resulting in underdraw as
2991 // the View is shifted (thus shifting the window background) exposing unpainted
2992 // content. To handle this with minimal glitches we just clear to BLACK if the window
2993 // is opaque. If it's not opaque then HWUI already internally does a glClear to
2994 // transparent, so there's no risk of underdraw on non-opaque surfaces.
2995 if (mCurScrollY != 0 && mHardwareYOffset != 0 && mAttachInfo.mThreadedRenderer.isOpaque()) {
2996 canvas.drawColor(Color.BLACK);
2997 }
Alan Viveretteccb11e12014-07-08 16:04:02 -07002998 canvas.translate(-mHardwareXOffset, -mHardwareYOffset);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002999 }
3000
Igor Murashkina86ab6402013-08-30 12:58:36 -07003001 @Override
Stan Iliev45faba52016-06-28 13:33:15 -04003002 public void onPostDraw(DisplayListCanvas canvas) {
Alan Viverette632af842014-10-28 13:45:11 -07003003 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09003004 if (mUseMTRenderer) {
3005 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
3006 mWindowCallbacks.get(i).onPostDraw(canvas);
3007 }
Jorim Jaggic39c7b02016-03-24 10:47:07 -07003008 }
Dianne Hackborn0f761d62010-11-30 22:06:10 -08003009 }
3010
Chet Haaseed30fd82011-04-22 16:18:45 -07003011 /**
3012 * @hide
3013 */
3014 void outputDisplayList(View view) {
Chris Craik356b5fe2015-07-07 10:39:36 -07003015 view.mRenderNode.output();
Stan Iliev45faba52016-06-28 13:33:15 -04003016 if (mAttachInfo.mThreadedRenderer != null) {
John Reck3e04f092017-06-02 15:50:09 -07003017 mAttachInfo.mThreadedRenderer.serializeDisplayListTree();
John Recke248bd12015-08-05 13:53:53 -07003018 }
Romain Guy59a12ca2011-06-09 17:48:21 -07003019 }
3020
3021 /**
3022 * @see #PROPERTY_PROFILE_RENDERING
3023 */
3024 private void profileRendering(boolean enabled) {
3025 if (mProfileRendering) {
3026 mRenderProfilingEnabled = enabled;
Chris Craikae4f32042013-02-07 12:57:10 -08003027
3028 if (mRenderProfiler != null) {
3029 mChoreographer.removeFrameCallback(mRenderProfiler);
3030 }
3031 if (mRenderProfilingEnabled) {
3032 if (mRenderProfiler == null) {
3033 mRenderProfiler = new Choreographer.FrameCallback() {
3034 @Override
3035 public void doFrame(long frameTimeNanos) {
3036 mDirty.set(0, 0, mWidth, mHeight);
3037 scheduleTraversals();
3038 if (mRenderProfilingEnabled) {
3039 mChoreographer.postFrameCallback(mRenderProfiler);
3040 }
Romain Guy59a12ca2011-06-09 17:48:21 -07003041 }
Chris Craikae4f32042013-02-07 12:57:10 -08003042 };
3043 }
Romain Guy5bb3c732012-11-29 17:52:58 -08003044 mChoreographer.postFrameCallback(mRenderProfiler);
Romain Guy59a12ca2011-06-09 17:48:21 -07003045 } else {
Romain Guy59a12ca2011-06-09 17:48:21 -07003046 mRenderProfiler = null;
Chet Haaseed30fd82011-04-22 16:18:45 -07003047 }
3048 }
3049 }
3050
Chet Haase2f2022a2011-10-11 06:41:59 -07003051 /**
3052 * Called from draw() when DEBUG_FPS is enabled
3053 */
3054 private void trackFPS() {
3055 // Tracks frames per second drawn. First value in a series of draws may be bogus
3056 // because it down not account for the intervening idle time
3057 long nowTime = System.currentTimeMillis();
3058 if (mFpsStartTime < 0) {
3059 mFpsStartTime = mFpsPrevTime = nowTime;
3060 mFpsNumFrames = 0;
3061 } else {
3062 ++mFpsNumFrames;
3063 String thisHash = Integer.toHexString(System.identityHashCode(this));
3064 long frameTime = nowTime - mFpsPrevTime;
3065 long totalTime = nowTime - mFpsStartTime;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003066 Log.v(mTag, "0x" + thisHash + "\tFrame time:\t" + frameTime);
Chet Haase2f2022a2011-10-11 06:41:59 -07003067 mFpsPrevTime = nowTime;
3068 if (totalTime > 1000) {
3069 float fps = (float) mFpsNumFrames * 1000 / totalTime;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003070 Log.v(mTag, "0x" + thisHash + "\tFPS:\t" + fps);
Chet Haase2f2022a2011-10-11 06:41:59 -07003071 mFpsStartTime = nowTime;
3072 mFpsNumFrames = 0;
3073 }
3074 }
3075 }
3076
Robert Carr8508bb22017-03-27 15:46:27 -07003077 /**
3078 * A count of the number of calls to pendingDrawFinished we
3079 * require to notify the WM drawing is complete.
Robert Carr8508bb22017-03-27 15:46:27 -07003080 */
Robert Carr49cd9f82017-05-25 18:24:42 -07003081 int mDrawsNeededToReport = 0;
Robert Carr8508bb22017-03-27 15:46:27 -07003082
3083 /**
3084 * Delay notifying WM of draw finished until
3085 * a balanced call to pendingDrawFinished.
3086 */
3087 void drawPending() {
3088 mDrawsNeededToReport++;
3089 }
3090
3091 void pendingDrawFinished() {
3092 if (mDrawsNeededToReport == 0) {
3093 throw new RuntimeException("Unbalanced drawPending/pendingDrawFinished calls");
3094 }
3095 mDrawsNeededToReport--;
3096 if (mDrawsNeededToReport == 0) {
3097 reportDrawFinished();
3098 }
3099 }
3100
3101 private void postDrawFinished() {
3102 mHandler.sendEmptyMessage(MSG_DRAW_FINISHED);
3103 }
3104
3105 private void reportDrawFinished() {
Robert Carrd5c7dd62017-03-08 10:39:30 -08003106 try {
Robert Carr49cd9f82017-05-25 18:24:42 -07003107 mDrawsNeededToReport = 0;
Robert Carrd5c7dd62017-03-08 10:39:30 -08003108 mWindowSession.finishDrawing(mWindow);
3109 } catch (RemoteException e) {
3110 // Have fun!
3111 }
3112 }
3113
Jeff Brown96e942d2011-11-30 19:55:01 -08003114 private void performDraw() {
Jeff Brownd912e1f2014-04-11 18:46:22 -07003115 if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
Craig Mautner006f0e42012-03-21 11:00:32 -07003116 return;
Robert Carr32f37ab2017-06-15 12:39:34 -07003117 } else if (mView == null) {
3118 return;
Craig Mautner006f0e42012-03-21 11:00:32 -07003119 }
Romain Guy7e4e5612012-03-05 14:37:29 -08003120
John Reck5b02c622018-05-17 10:44:00 -07003121 final boolean fullRedrawNeeded = mFullRedrawNeeded || mReportNextDraw;
Jeff Brown96e942d2011-11-30 19:55:01 -08003122 mFullRedrawNeeded = false;
Jeff Brown481c1572012-03-09 14:41:15 -08003123
Romain Guy1f59e5c2012-05-06 14:11:16 -07003124 mIsDrawing = true;
Jeff Brown481c1572012-03-09 14:41:15 -08003125 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
John Reck5b02c622018-05-17 10:44:00 -07003126
3127 boolean usingAsyncReport = false;
3128 if (mReportNextDraw && mAttachInfo.mThreadedRenderer != null
3129 && mAttachInfo.mThreadedRenderer.isEnabled()) {
3130 usingAsyncReport = true;
3131 mAttachInfo.mThreadedRenderer.setFrameCompleteCallback((long frameNr) -> {
3132 // TODO: Use the frame number
3133 pendingDrawFinished();
3134 });
3135 }
3136
Jeff Brown481c1572012-03-09 14:41:15 -08003137 try {
John Reck5b02c622018-05-17 10:44:00 -07003138 boolean canUseAsync = draw(fullRedrawNeeded);
3139 if (usingAsyncReport && !canUseAsync) {
3140 mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(null);
3141 usingAsyncReport = false;
3142 }
Jeff Brown481c1572012-03-09 14:41:15 -08003143 } finally {
Romain Guy1f59e5c2012-05-06 14:11:16 -07003144 mIsDrawing = false;
Jeff Brown481c1572012-03-09 14:41:15 -08003145 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
3146 }
Jeff Brown96e942d2011-11-30 19:55:01 -08003147
John Reck119907c2014-08-14 09:02:01 -07003148 // For whatever reason we didn't create a HardwareRenderer, end any
3149 // hardware animations that are now dangling
3150 if (mAttachInfo.mPendingAnimatingRenderNodes != null) {
3151 final int count = mAttachInfo.mPendingAnimatingRenderNodes.size();
3152 for (int i = 0; i < count; i++) {
3153 mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators();
3154 }
3155 mAttachInfo.mPendingAnimatingRenderNodes.clear();
3156 }
3157
Jeff Brown96e942d2011-11-30 19:55:01 -08003158 if (mReportNextDraw) {
3159 mReportNextDraw = false;
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07003160
3161 // if we're using multi-thread renderer, wait for the window frame draws
3162 if (mWindowDrawCountDown != null) {
3163 try {
3164 mWindowDrawCountDown.await();
3165 } catch (InterruptedException e) {
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07003166 Log.e(mTag, "Window redraw count down interrupted!");
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07003167 }
3168 mWindowDrawCountDown = null;
3169 }
3170
Stan Iliev45faba52016-06-28 13:33:15 -04003171 if (mAttachInfo.mThreadedRenderer != null) {
Stan Iliev45faba52016-06-28 13:33:15 -04003172 mAttachInfo.mThreadedRenderer.setStopped(mStopped);
John Reck28ad7b52014-04-07 16:59:25 -07003173 }
Jeff Brown96e942d2011-11-30 19:55:01 -08003174
3175 if (LOCAL_LOGV) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003176 Log.v(mTag, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
Jeff Brown96e942d2011-11-30 19:55:01 -08003177 }
Robert Carr25cfa132016-11-16 13:24:09 -08003178
Jeff Brown96e942d2011-11-30 19:55:01 -08003179 if (mSurfaceHolder != null && mSurface.isValid()) {
Robert Carr8508bb22017-03-27 15:46:27 -07003180 SurfaceCallbackHelper sch = new SurfaceCallbackHelper(this::postDrawFinished);
Jeff Brown96e942d2011-11-30 19:55:01 -08003181 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
Robert Carr25cfa132016-11-16 13:24:09 -08003182
3183 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
John Reck5b02c622018-05-17 10:44:00 -07003184 } else if (!usingAsyncReport) {
3185 if (mAttachInfo.mThreadedRenderer != null) {
3186 mAttachInfo.mThreadedRenderer.fence();
3187 }
Robert Carr8508bb22017-03-27 15:46:27 -07003188 pendingDrawFinished();
Jeff Brown96e942d2011-11-30 19:55:01 -08003189 }
Jeff Brown96e942d2011-11-30 19:55:01 -08003190 }
3191 }
3192
John Reck5b02c622018-05-17 10:44:00 -07003193 private boolean draw(boolean fullRedrawNeeded) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003194 Surface surface = mSurface;
Romain Guyfbb93fa2012-12-03 18:50:35 -08003195 if (!surface.isValid()) {
John Reck5b02c622018-05-17 10:44:00 -07003196 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003197 }
3198
Chet Haase2f2022a2011-10-11 06:41:59 -07003199 if (DEBUG_FPS) {
3200 trackFPS();
3201 }
3202
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08003203 if (!sFirstDrawComplete) {
3204 synchronized (sFirstDrawHandlers) {
3205 sFirstDrawComplete = true;
Romain Guy812ccbe2010-06-01 14:07:24 -07003206 final int count = sFirstDrawHandlers.size();
3207 for (int i = 0; i< count; i++) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003208 mHandler.post(sFirstDrawHandlers.get(i));
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08003209 }
3210 }
3211 }
Romain Guy59a12ca2011-06-09 17:48:21 -07003212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003213 scrollToRectOrFocus(null, false);
3214
Chris Craikd36a81f2014-07-17 10:16:51 -07003215 if (mAttachInfo.mViewScrollChanged) {
3216 mAttachInfo.mViewScrollChanged = false;
3217 mAttachInfo.mTreeObserver.dispatchOnScrollChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003218 }
Romain Guy8506ab42009-06-11 17:35:47 -07003219
Dianne Hackborn0f761d62010-11-30 22:06:10 -08003220 boolean animating = mScroller != null && mScroller.computeScrollOffset();
Alan Viveretteccb11e12014-07-08 16:04:02 -07003221 final int curScrollY;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08003222 if (animating) {
Alan Viveretteccb11e12014-07-08 16:04:02 -07003223 curScrollY = mScroller.getCurrY();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003224 } else {
Alan Viveretteccb11e12014-07-08 16:04:02 -07003225 curScrollY = mScrollY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003226 }
Alan Viveretteccb11e12014-07-08 16:04:02 -07003227 if (mCurScrollY != curScrollY) {
3228 mCurScrollY = curScrollY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003229 fullRedrawNeeded = true;
Adrian Roos0e7ae4e2014-10-01 15:33:22 +02003230 if (mView instanceof RootViewSurfaceTaker) {
3231 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
3232 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003233 }
Jeff Brown96e942d2011-11-30 19:55:01 -08003234
Chris Craikd36a81f2014-07-17 10:16:51 -07003235 final float appScale = mAttachInfo.mApplicationScale;
3236 final boolean scalingRequired = mAttachInfo.mScalingRequired;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003237
Jeff Brown96e942d2011-11-30 19:55:01 -08003238 final Rect dirty = mDirty;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07003239 if (mSurfaceHolder != null) {
3240 // The app owns the surface, we won't draw.
3241 dirty.setEmpty();
Derek Sollenberger8d948352015-07-16 09:27:59 -04003242 if (animating && mScroller != null) {
3243 mScroller.abortAnimation();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08003244 }
John Reck5b02c622018-05-17 10:44:00 -07003245 return false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07003246 }
Romain Guy58ef7fb2010-09-13 12:52:37 -07003247
3248 if (fullRedrawNeeded) {
Chris Craikd36a81f2014-07-17 10:16:51 -07003249 mAttachInfo.mIgnoreDirtyState = true;
Romain Guyc3166e12011-08-08 15:00:03 -07003250 dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
Romain Guy58ef7fb2010-09-13 12:52:37 -07003251 }
Chet Haasead4f7032011-06-22 09:18:31 -07003252
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003253 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003254 Log.v(mTag, "Draw " + mView + "/"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003255 + mWindowAttributes.getTitle()
3256 + ": dirty={" + dirty.left + "," + dirty.top
3257 + "," + dirty.right + "," + dirty.bottom + "} surface="
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07003258 + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
3259 appScale + ", width=" + mWidth + ", height=" + mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003260 }
3261
Chris Craikd36a81f2014-07-17 10:16:51 -07003262 mAttachInfo.mTreeObserver.dispatchOnDraw();
Romain Guy25eba5c2012-04-04 17:29:03 -07003263
Chong Zhang0275e392015-09-17 10:41:44 -07003264 int xOffset = -mCanvasOffsetX;
3265 int yOffset = -mCanvasOffsetY + curScrollY;
Alan Viverettea51cab92014-07-16 15:15:49 -07003266 final WindowManager.LayoutParams params = mWindowAttributes;
3267 final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
3268 if (surfaceInsets != null) {
3269 xOffset -= surfaceInsets.left;
3270 yOffset -= surfaceInsets.top;
3271
3272 // Offset dirty rect for surface insets.
3273 dirty.offset(surfaceInsets.left, surfaceInsets.right);
3274 }
3275
Alan Viverette632af842014-10-28 13:45:11 -07003276 boolean accessibilityFocusDirty = false;
3277 final Drawable drawable = mAttachInfo.mAccessibilityFocusDrawable;
3278 if (drawable != null) {
3279 final Rect bounds = mAttachInfo.mTmpInvalRect;
3280 final boolean hasFocus = getAccessibilityFocusedRect(bounds);
3281 if (!hasFocus) {
3282 bounds.setEmpty();
3283 }
3284 if (!bounds.equals(drawable.getBounds())) {
3285 accessibilityFocusDirty = true;
3286 }
3287 }
3288
John Reckba6adf62015-02-19 14:36:50 -08003289 mAttachInfo.mDrawingTime =
3290 mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
3291
John Reck5b02c622018-05-17 10:44:00 -07003292 boolean useAsyncReport = false;
Alan Viverette632af842014-10-28 13:45:11 -07003293 if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
Stan Iliev45faba52016-06-28 13:33:15 -04003294 if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {
Alan Viverette632af842014-10-28 13:45:11 -07003295 // If accessibility focus moved, always invalidate the root.
Jorim Jaggic39c7b02016-03-24 10:47:07 -07003296 boolean invalidateRoot = accessibilityFocusDirty || mInvalidateRootRequested;
3297 mInvalidateRootRequested = false;
Alan Viverette632af842014-10-28 13:45:11 -07003298
Jeff Brown96e942d2011-11-30 19:55:01 -08003299 // Draw with hardware renderer.
3300 mIsAnimating = false;
Alan Viverette632af842014-10-28 13:45:11 -07003301
John Reck0a973302014-07-16 13:29:45 -07003302 if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
3303 mHardwareYOffset = yOffset;
3304 mHardwareXOffset = xOffset;
Alan Viverette632af842014-10-28 13:45:11 -07003305 invalidateRoot = true;
Alan Viverettef6cf1a02014-08-11 14:13:02 -07003306 }
3307
Alan Viverette632af842014-10-28 13:45:11 -07003308 if (invalidateRoot) {
Stan Iliev45faba52016-06-28 13:33:15 -04003309 mAttachInfo.mThreadedRenderer.invalidateRoot();
Alan Viverette632af842014-10-28 13:45:11 -07003310 }
3311
Jeff Brown96e942d2011-11-30 19:55:01 -08003312 dirty.setEmpty();
3313
Skuhne980ee472015-10-06 11:31:31 -07003314 // Stage the content drawn size now. It will be transferred to the renderer
3315 // shortly before the draw commands get send to the renderer.
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07003316 final boolean updated = updateContentDrawBounds();
3317
John Reck8afcc762016-04-13 10:24:06 -07003318 if (mReportNextDraw) {
3319 // report next draw overrides setStopped()
3320 // This value is re-sync'd to the value of mStopped
3321 // in the handling of mReportNextDraw post-draw.
Stan Iliev45faba52016-06-28 13:33:15 -04003322 mAttachInfo.mThreadedRenderer.setStopped(false);
John Reck8afcc762016-04-13 10:24:06 -07003323 }
3324
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07003325 if (updated) {
3326 requestDrawWindow();
3327 }
Jorim Jaggi0d6222d2016-04-18 20:42:10 -07003328
John Reck5b02c622018-05-17 10:44:00 -07003329 useAsyncReport = true;
Jorim Jaggie6a026b2018-06-06 18:42:16 +02003330
3331 // draw(...) might invoke post-draw, which might register the next callback already.
3332 final FrameDrawingCallback callback = mNextRtFrameCallback;
Jorim Jaggi64be98d2018-04-26 23:23:29 +02003333 mNextRtFrameCallback = null;
Jorim Jaggie6a026b2018-06-06 18:42:16 +02003334 mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this, callback);
Romain Guy3696779b2013-01-28 14:04:07 -08003335 } else {
3336 // If we get here with a disabled & requested hardware renderer, something went
3337 // wrong (an invalidate posted right before we destroyed the hardware surface
3338 // for instance) so we should just bail out. Locking the surface with software
3339 // rendering at this point would lock it forever and prevent hardware renderer
3340 // from doing its job when it comes back.
3341 // Before we request a new frame we must however attempt to reinitiliaze the
3342 // hardware renderer if it's in requested state. This would happen after an
3343 // eglTerminate() for instance.
Stan Iliev45faba52016-06-28 13:33:15 -04003344 if (mAttachInfo.mThreadedRenderer != null &&
3345 !mAttachInfo.mThreadedRenderer.isEnabled() &&
Robert Carr80923d52018-04-19 13:05:08 -07003346 mAttachInfo.mThreadedRenderer.isRequested() &&
3347 mSurface.isValid()) {
Romain Guy3696779b2013-01-28 14:04:07 -08003348
3349 try {
Stan Iliev45faba52016-06-28 13:33:15 -04003350 mAttachInfo.mThreadedRenderer.initializeIfNeeded(
Alan Viverette50210d92015-05-14 18:05:36 -07003351 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
Igor Murashkina86ab6402013-08-30 12:58:36 -07003352 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08003353 handleOutOfResourcesException(e);
John Reck5b02c622018-05-17 10:44:00 -07003354 return false;
Romain Guy3696779b2013-01-28 14:04:07 -08003355 }
3356
3357 mFullRedrawNeeded = true;
3358 scheduleTraversals();
John Reck5b02c622018-05-17 10:44:00 -07003359 return false;
Romain Guy3696779b2013-01-28 14:04:07 -08003360 }
3361
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09003362 if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
3363 scalingRequired, dirty, surfaceInsets)) {
John Reck5b02c622018-05-17 10:44:00 -07003364 return false;
Romain Guy3696779b2013-01-28 14:04:07 -08003365 }
Jeff Brown95db2b22011-11-30 19:54:41 -08003366 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003367 }
Romain Guy8506ab42009-06-11 17:35:47 -07003368
Dianne Hackborn0f761d62010-11-30 22:06:10 -08003369 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003370 mFullRedrawNeeded = true;
3371 scheduleTraversals();
3372 }
John Reck5b02c622018-05-17 10:44:00 -07003373 return useAsyncReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003374 }
3375
Romain Guy25eba5c2012-04-04 17:29:03 -07003376 /**
Alan Viveretteccb11e12014-07-08 16:04:02 -07003377 * @return true if drawing was successful, false if an error occurred
Romain Guy25eba5c2012-04-04 17:29:03 -07003378 */
Alan Viveretteccb11e12014-07-08 16:04:02 -07003379 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09003380 boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
Romain Guy25eba5c2012-04-04 17:29:03 -07003381
3382 // Draw with software renderer.
Alan Viverettea51cab92014-07-16 15:15:49 -07003383 final Canvas canvas;
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09003384
3385 // We already have the offset of surfaceInsets in xoff, yoff and dirty region,
3386 // therefore we need to add it back when moving the dirty region.
3387 int dirtyXOffset = xoff;
3388 int dirtyYOffset = yoff;
3389 if (surfaceInsets != null) {
3390 dirtyXOffset += surfaceInsets.left;
3391 dirtyYOffset += surfaceInsets.top;
3392 }
3393
Romain Guy25eba5c2012-04-04 17:29:03 -07003394 try {
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09003395 dirty.offset(-dirtyXOffset, -dirtyYOffset);
Alan Viverettea51cab92014-07-16 15:15:49 -07003396 final int left = dirty.left;
3397 final int top = dirty.top;
3398 final int right = dirty.right;
3399 final int bottom = dirty.bottom;
Romain Guy25eba5c2012-04-04 17:29:03 -07003400
Romain Guy25eba5c2012-04-04 17:29:03 -07003401 canvas = mSurface.lockCanvas(dirty);
3402
Romain Guye55945e2013-04-04 15:26:04 -07003403 // The dirty rectangle can be modified by Surface.lockCanvas()
3404 //noinspection ConstantConditions
Alan Viverettea51cab92014-07-16 15:15:49 -07003405 if (left != dirty.left || top != dirty.top || right != dirty.right
3406 || bottom != dirty.bottom) {
Romain Guy25eba5c2012-04-04 17:29:03 -07003407 attachInfo.mIgnoreDirtyState = true;
3408 }
3409
3410 // TODO: Do this in native
3411 canvas.setDensity(mDensity);
3412 } catch (Surface.OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08003413 handleOutOfResourcesException(e);
Romain Guy25eba5c2012-04-04 17:29:03 -07003414 return false;
3415 } catch (IllegalArgumentException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003416 Log.e(mTag, "Could not lock surface", e);
Romain Guy25eba5c2012-04-04 17:29:03 -07003417 // Don't assume this is due to out of memory, it could be
3418 // something else, and if it is something else then we could
3419 // kill stuff (or ourself) for no reason.
3420 mLayoutRequested = true; // ask wm for a new surface next time.
3421 return false;
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09003422 } finally {
3423 dirty.offset(dirtyXOffset, dirtyYOffset); // Reset to the original value.
Romain Guy25eba5c2012-04-04 17:29:03 -07003424 }
3425
3426 try {
3427 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003428 Log.v(mTag, "Surface " + surface + " drawing to bitmap w="
Romain Guy25eba5c2012-04-04 17:29:03 -07003429 + canvas.getWidth() + ", h=" + canvas.getHeight());
3430 //canvas.drawARGB(255, 255, 0, 0);
3431 }
3432
Romain Guy25eba5c2012-04-04 17:29:03 -07003433 // If this bitmap's format includes an alpha channel, we
3434 // need to clear it before drawing so that the child will
3435 // properly re-composite its drawing on a transparent
3436 // background. This automatically respects the clip/dirty region
3437 // or
3438 // If we are applying an offset, we need to clear the area
3439 // where the offset doesn't appear to avoid having garbage
3440 // left in the blank areas.
Alan Viveretteccb11e12014-07-08 16:04:02 -07003441 if (!canvas.isOpaque() || yoff != 0 || xoff != 0) {
Romain Guy25eba5c2012-04-04 17:29:03 -07003442 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
3443 }
3444
3445 dirty.setEmpty();
3446 mIsAnimating = false;
Dianne Hackborn4702a852012-08-17 15:18:29 -07003447 mView.mPrivateFlags |= View.PFLAG_DRAWN;
Romain Guy25eba5c2012-04-04 17:29:03 -07003448
3449 if (DEBUG_DRAW) {
3450 Context cxt = mView.getContext();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003451 Log.i(mTag, "Drawing: package:" + cxt.getPackageName() +
Romain Guy25eba5c2012-04-04 17:29:03 -07003452 ", metrics=" + cxt.getResources().getDisplayMetrics() +
3453 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
3454 }
3455 try {
Alan Viveretteccb11e12014-07-08 16:04:02 -07003456 canvas.translate(-xoff, -yoff);
Romain Guy25eba5c2012-04-04 17:29:03 -07003457 if (mTranslator != null) {
3458 mTranslator.translateCanvas(canvas);
3459 }
Dianne Hackborn908aecc2012-07-31 16:37:34 -07003460 canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
Romain Guy25eba5c2012-04-04 17:29:03 -07003461 attachInfo.mSetIgnoreDirtyState = false;
3462
Romain Guy25eba5c2012-04-04 17:29:03 -07003463 mView.draw(canvas);
Alan Viverette632af842014-10-28 13:45:11 -07003464
3465 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Romain Guy25eba5c2012-04-04 17:29:03 -07003466 } finally {
3467 if (!attachInfo.mSetIgnoreDirtyState) {
3468 // Only clear the flag if it was not set during the mView.draw() call
3469 attachInfo.mIgnoreDirtyState = false;
3470 }
3471 }
Romain Guy25eba5c2012-04-04 17:29:03 -07003472 } finally {
Romain Guydddcd222012-05-18 15:33:57 -07003473 try {
3474 surface.unlockCanvasAndPost(canvas);
3475 } catch (IllegalArgumentException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003476 Log.e(mTag, "Could not unlock surface", e);
Romain Guydddcd222012-05-18 15:33:57 -07003477 mLayoutRequested = true; // ask wm for a new surface next time.
3478 //noinspection ReturnInsideFinallyBlock
3479 return false;
3480 }
Romain Guy25eba5c2012-04-04 17:29:03 -07003481
Romain Guy25eba5c2012-04-04 17:29:03 -07003482 if (LOCAL_LOGV) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003483 Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost");
Romain Guy25eba5c2012-04-04 17:29:03 -07003484 }
3485 }
3486 return true;
3487 }
3488
Alan Viverette632af842014-10-28 13:45:11 -07003489 /**
3490 * We want to draw a highlight around the current accessibility focused.
3491 * Since adding a style for all possible view is not a viable option we
3492 * have this specialized drawing method.
3493 *
3494 * Note: We are doing this here to be able to draw the highlight for
3495 * virtual views in addition to real ones.
3496 *
3497 * @param canvas The canvas on which to draw.
3498 */
3499 private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
3500 final Rect bounds = mAttachInfo.mTmpInvalRect;
3501 if (getAccessibilityFocusedRect(bounds)) {
3502 final Drawable drawable = getAccessibilityFocusedDrawable();
3503 if (drawable != null) {
3504 drawable.setBounds(bounds);
3505 drawable.draw(canvas);
3506 }
3507 } else if (mAttachInfo.mAccessibilityFocusDrawable != null) {
3508 mAttachInfo.mAccessibilityFocusDrawable.setBounds(0, 0, 0, 0);
3509 }
3510 }
3511
3512 private boolean getAccessibilityFocusedRect(Rect bounds) {
3513 final AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
3514 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
3515 return false;
3516 }
3517
3518 final View host = mAccessibilityFocusedHost;
3519 if (host == null || host.mAttachInfo == null) {
3520 return false;
3521 }
3522
3523 final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
3524 if (provider == null) {
Svetoslavded133c2015-01-30 20:28:41 -08003525 host.getBoundsOnScreen(bounds, true);
Alan Viverette632af842014-10-28 13:45:11 -07003526 } else if (mAccessibilityFocusedVirtualView != null) {
3527 mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
3528 } else {
3529 return false;
3530 }
3531
Alan Viverette2232add2015-05-26 15:24:18 -07003532 // Transform the rect into window-relative coordinates.
Alan Viverette632af842014-10-28 13:45:11 -07003533 final AttachInfo attachInfo = mAttachInfo;
Alan Viverette2232add2015-05-26 15:24:18 -07003534 bounds.offset(0, attachInfo.mViewRootImpl.mScrollY);
Alan Viverette632af842014-10-28 13:45:11 -07003535 bounds.offset(-attachInfo.mWindowLeft, -attachInfo.mWindowTop);
Doris Liu9607fbe2015-05-28 17:17:28 -07003536 if (!bounds.intersect(0, 0, attachInfo.mViewRootImpl.mWidth,
3537 attachInfo.mViewRootImpl.mHeight)) {
3538 // If no intersection, set bounds to empty.
3539 bounds.setEmpty();
3540 }
Alan Viverette632af842014-10-28 13:45:11 -07003541 return !bounds.isEmpty();
3542 }
3543
3544 private Drawable getAccessibilityFocusedDrawable() {
Chris Craikd36a81f2014-07-17 10:16:51 -07003545 // Lazily load the accessibility focus drawable.
3546 if (mAttachInfo.mAccessibilityFocusDrawable == null) {
Alan Viverettef6cf1a02014-08-11 14:13:02 -07003547 final TypedValue value = new TypedValue();
Chris Craikd36a81f2014-07-17 10:16:51 -07003548 final boolean resolved = mView.mContext.getTheme().resolveAttribute(
3549 R.attr.accessibilityFocusedDrawable, value, true);
3550 if (resolved) {
3551 mAttachInfo.mAccessibilityFocusDrawable =
Alan Viverette8eea3ea2014-02-03 18:40:20 -08003552 mView.mContext.getDrawable(value.resourceId);
Svetoslav Ganov42138042012-03-20 11:51:39 -07003553 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07003554 }
Chris Craikd36a81f2014-07-17 10:16:51 -07003555 return mAttachInfo.mAccessibilityFocusDrawable;
Svetoslav Ganov42138042012-03-20 11:51:39 -07003556 }
3557
Jorim Jaggic39c7b02016-03-24 10:47:07 -07003558 /**
3559 * Requests that the root render node is invalidated next time we perform a draw, such that
3560 * {@link WindowCallbacks#onPostDraw} gets called.
3561 */
3562 public void requestInvalidateRootRenderNode() {
3563 mInvalidateRootRequested = true;
3564 }
3565
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003566 boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
Chris Craikd36a81f2014-07-17 10:16:51 -07003567 final Rect ci = mAttachInfo.mContentInsets;
3568 final Rect vi = mAttachInfo.mVisibleInsets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003569 int scrollY = 0;
3570 boolean handled = false;
Romain Guy8506ab42009-06-11 17:35:47 -07003571
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003572 if (vi.left > ci.left || vi.top > ci.top
3573 || vi.right > ci.right || vi.bottom > ci.bottom) {
3574 // We'll assume that we aren't going to change the scroll
3575 // offset, since we want to avoid that unless it is actually
3576 // going to make the focus visible... otherwise we scroll
3577 // all over the place.
3578 scrollY = mScrollY;
3579 // We can be called for two different situations: during a draw,
3580 // to update the scroll position if the focus has changed (in which
3581 // case 'rectangle' is null), or in response to a
3582 // requestChildRectangleOnScreen() call (in which case 'rectangle'
3583 // is non-null and we just want to scroll to whatever that
3584 // rectangle is).
Craig Mautner26a84df2013-04-11 19:09:05 -07003585 final View focus = mView.findFocus();
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003586 if (focus == null) {
Romain Guye8b16522009-07-14 13:06:42 -07003587 return false;
3588 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003589 View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null;
Craig Mautner26a84df2013-04-11 19:09:05 -07003590 if (focus != lastScrolledFocus) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003591 // If the focus has changed, then ignore any requests to scroll
3592 // to a rectangle; first we want to make sure the entire focus
3593 // view is visible.
3594 rectangle = null;
3595 }
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003596 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Eval scroll: focus=" + focus
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003597 + " rectangle=" + rectangle + " ci=" + ci
3598 + " vi=" + vi);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003599 if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003600 // Optimization: if the focus hasn't changed since last
3601 // time, and no layout has happened, then just leave things
3602 // as they are.
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003603 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Keeping scroll y="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003604 + mScrollY + " vi=" + vi.toShortString());
Craig Mautner26a84df2013-04-11 19:09:05 -07003605 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003606 // We need to determine if the currently focused view is
3607 // within the visible part of the window and, if not, apply
3608 // a pan so it can be seen.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003609 mLastScrolledFocus = new WeakReference<View>(focus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003610 mScrollMayChange = false;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003611 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Need to scroll?");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003612 // Try to find the rectangle from the focus view.
3613 if (focus.getGlobalVisibleRect(mVisRect, null)) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003614 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Root w="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003615 + mView.getWidth() + " h=" + mView.getHeight()
3616 + " ci=" + ci.toShortString()
3617 + " vi=" + vi.toShortString());
3618 if (rectangle == null) {
3619 focus.getFocusedRect(mTempRect);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003620 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Focus " + focus
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003621 + ": focusRect=" + mTempRect.toShortString());
Dianne Hackborn1c6a8942010-03-23 16:34:20 -07003622 if (mView instanceof ViewGroup) {
3623 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
3624 focus, mTempRect);
3625 }
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003626 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003627 "Focus in window: focusRect="
3628 + mTempRect.toShortString()
3629 + " visRect=" + mVisRect.toShortString());
3630 } else {
3631 mTempRect.set(rectangle);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003632 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003633 "Request scroll to rect: "
3634 + mTempRect.toShortString()
3635 + " visRect=" + mVisRect.toShortString());
3636 }
3637 if (mTempRect.intersect(mVisRect)) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003638 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003639 "Focus window visible rect: "
3640 + mTempRect.toShortString());
3641 if (mTempRect.height() >
3642 (mView.getHeight()-vi.top-vi.bottom)) {
3643 // If the focus simply is not going to fit, then
3644 // best is probably just to leave things as-is.
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 "Too tall; leaving scrollY=" + scrollY);
Chong Zhang67254722016-06-02 12:56:54 -07003647 }
3648 // Next, check whether top or bottom is covered based on the non-scrolled
3649 // position, and calculate new scrollY (or set it to 0).
3650 // We can't keep using mScrollY here. For example mScrollY is non-zero
3651 // due to IME, then IME goes away. The current value of mScrollY leaves top
3652 // and bottom both visible, but we still need to scroll it back to 0.
3653 else if (mTempRect.top < vi.top) {
3654 scrollY = mTempRect.top - vi.top;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003655 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003656 "Top covered; scrollY=" + scrollY);
Chong Zhang67254722016-06-02 12:56:54 -07003657 } else if (mTempRect.bottom > (mView.getHeight()-vi.bottom)) {
3658 scrollY = mTempRect.bottom - (mView.getHeight()-vi.bottom);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003659 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003660 "Bottom covered; scrollY=" + scrollY);
Chong Zhang67254722016-06-02 12:56:54 -07003661 } else {
3662 scrollY = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003663 }
3664 handled = true;
3665 }
3666 }
3667 }
3668 }
Romain Guy8506ab42009-06-11 17:35:47 -07003669
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003670 if (scrollY != mScrollY) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003671 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Pan scroll changed: old="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003672 + mScrollY + " , new=" + scrollY);
Derek Sollenberger8d948352015-07-16 09:27:59 -04003673 if (!immediate) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003674 if (mScroller == null) {
3675 mScroller = new Scroller(mView.getContext());
3676 }
3677 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
3678 } else if (mScroller != null) {
3679 mScroller.abortAnimation();
3680 }
3681 mScrollY = scrollY;
3682 }
Romain Guy8506ab42009-06-11 17:35:47 -07003683
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003684 return handled;
3685 }
Romain Guy8506ab42009-06-11 17:35:47 -07003686
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07003687 /**
3688 * @hide
3689 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +01003690 @UnsupportedAppUsage
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07003691 public View getAccessibilityFocusedHost() {
3692 return mAccessibilityFocusedHost;
3693 }
3694
3695 /**
3696 * @hide
3697 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +01003698 @UnsupportedAppUsage
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07003699 public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
3700 return mAccessibilityFocusedVirtualView;
3701 }
3702
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003703 void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003704 // If we have a virtual view with accessibility focus we need
3705 // to clear the focus and invalidate the virtual view bounds.
3706 if (mAccessibilityFocusedVirtualView != null) {
3707
3708 AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
3709 View focusHost = mAccessibilityFocusedHost;
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003710
3711 // Wipe the state of the current accessibility focus since
3712 // the call into the provider to clear accessibility focus
3713 // will fire an accessibility event which will end up calling
3714 // this method and we want to have clean state when this
3715 // invocation happens.
3716 mAccessibilityFocusedHost = null;
3717 mAccessibilityFocusedVirtualView = null;
3718
Alan Viverette239a0c02013-05-07 17:17:35 -07003719 // Clear accessibility focus on the host after clearing state since
3720 // this method may be reentrant.
Phil Weavere37cfab2016-04-07 21:01:57 -07003721 focusHost.clearAccessibilityFocusNoCallbacks(
3722 AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
Alan Viverette239a0c02013-05-07 17:17:35 -07003723
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003724 AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
3725 if (provider != null) {
3726 // Invalidate the area of the cleared accessibility focus.
3727 focusNode.getBoundsInParent(mTempRect);
3728 focusHost.invalidate(mTempRect);
3729 // Clear accessibility focus in the virtual node.
3730 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
3731 focusNode.getSourceNodeId());
3732 provider.performAction(virtualNodeId,
3733 AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
3734 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003735 focusNode.recycle();
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003736 }
Phil Weaverda469272016-06-24 18:17:21 -07003737 if ((mAccessibilityFocusedHost != null) && (mAccessibilityFocusedHost != view)) {
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003738 // Clear accessibility focus in the view.
Phil Weavere37cfab2016-04-07 21:01:57 -07003739 mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks(
3740 AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
Svetoslav Ganov42138042012-03-20 11:51:39 -07003741 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003742
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003743 // Set the new focus host and node.
3744 mAccessibilityFocusedHost = view;
3745 mAccessibilityFocusedVirtualView = node;
John Reck0a973302014-07-16 13:29:45 -07003746
Stan Iliev45faba52016-06-28 13:33:15 -04003747 if (mAttachInfo.mThreadedRenderer != null) {
3748 mAttachInfo.mThreadedRenderer.invalidateRoot();
John Reck0a973302014-07-16 13:29:45 -07003749 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07003750 }
3751
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08003752 boolean hasPointerCapture() {
3753 return mPointerCapture;
3754 }
3755
3756 void requestPointerCapture(boolean enabled) {
3757 if (mPointerCapture == enabled) {
3758 return;
3759 }
3760 InputManager.getInstance().requestPointerCapture(mAttachInfo.mWindowToken, enabled);
3761 }
3762
3763 private void handlePointerCaptureChanged(boolean hasCapture) {
3764 if (mPointerCapture == hasCapture) {
3765 return;
3766 }
3767 mPointerCapture = hasCapture;
3768 if (mView != null) {
3769 mView.dispatchPointerCaptureChanged(hasCapture);
3770 }
3771 }
3772
Igor Murashkina86ab6402013-08-30 12:58:36 -07003773 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003774 public void requestChildFocus(View child, View focused) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003775 if (DEBUG_INPUT_RESIZE) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003776 Log.v(mTag, "Request child focus: focus now " + focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003777 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003778 checkThread();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003779 scheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003780 }
3781
Igor Murashkina86ab6402013-08-30 12:58:36 -07003782 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003783 public void clearChildFocus(View child) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003784 if (DEBUG_INPUT_RESIZE) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003785 Log.v(mTag, "Clearing child focus");
Amith Yamasani73eb97f2012-02-14 15:45:15 -08003786 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003787 checkThread();
3788 scheduleTraversals();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003789 }
Amith Yamasani73eb97f2012-02-14 15:45:15 -08003790
Svetoslav Ganov42138042012-03-20 11:51:39 -07003791 @Override
3792 public ViewParent getParentForAccessibility() {
3793 return null;
3794 }
3795
Igor Murashkina86ab6402013-08-30 12:58:36 -07003796 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003797 public void focusableViewAvailable(View v) {
3798 checkThread();
Romain Guy1c90f032011-05-24 14:59:50 -07003799 if (mView != null) {
3800 if (!mView.hasFocus()) {
Evan Rosky28884042018-04-03 13:21:55 -07003801 if (sAlwaysAssignFocus || !mAttachInfo.mInTouchMode) {
Evan Rosky37df2db2017-01-24 16:35:52 -08003802 v.requestFocus();
3803 }
Romain Guy1c90f032011-05-24 14:59:50 -07003804 } else {
3805 // the one case where will transfer focus away from the current one
3806 // is if the current view is a view group that prefers to give focus
3807 // to its children first AND the view is a descendant of it.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003808 View focused = mView.findFocus();
3809 if (focused instanceof ViewGroup) {
3810 ViewGroup group = (ViewGroup) focused;
3811 if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
3812 && isViewDescendantOf(v, focused)) {
3813 v.requestFocus();
3814 }
Romain Guy1c90f032011-05-24 14:59:50 -07003815 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003816 }
3817 }
3818 }
3819
Igor Murashkina86ab6402013-08-30 12:58:36 -07003820 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003821 public void recomputeViewAttributes(View child) {
3822 checkThread();
3823 if (mView == child) {
3824 mAttachInfo.mRecomputeGlobalAttributes = true;
3825 if (!mWillDrawSoon) {
3826 scheduleTraversals();
3827 }
3828 }
3829 }
3830
3831 void dispatchDetachedFromWindow() {
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07003832 mFirstInputStage.onDetachedFromWindow();
Romain Guy90fc03b2011-01-16 13:07:15 -08003833 if (mView != null && mView.mAttachInfo != null) {
Dianne Hackborn961cae92013-03-20 14:59:43 -07003834 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003835 mView.dispatchDetachedFromWindow();
3836 }
3837
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003838 mAccessibilityInteractionConnectionManager.ensureNoConnection();
3839 mAccessibilityManager.removeAccessibilityStateChangeListener(
3840 mAccessibilityInteractionConnectionManager);
Chris Craikcce47eb2014-07-16 15:12:15 -07003841 mAccessibilityManager.removeHighTextContrastStateChangeListener(
3842 mHighContrastTextManager);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07003843 removeSendWindowContentChangedCallback();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003844
Romain Guya998dff2012-03-23 18:58:36 -07003845 destroyHardwareRenderer();
3846
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003847 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003848
Craig Mautner8f303ad2013-06-14 11:32:22 -07003849 mView.assignParent(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003850 mView = null;
3851 mAttachInfo.mRootView = null;
3852
Dianne Hackborn0586a1b2009-09-06 21:08:27 -07003853 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003854
Jeff Browncc4f7db2011-08-30 20:34:48 -07003855 if (mInputQueueCallback != null && mInputQueue != null) {
3856 mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
Michael Wrighta44dd262013-04-10 21:12:00 -07003857 mInputQueue.dispose();
Jeff Browncc4f7db2011-08-30 20:34:48 -07003858 mInputQueueCallback = null;
3859 mInputQueue = null;
Michael Wrighta44dd262013-04-10 21:12:00 -07003860 }
3861 if (mInputEventReceiver != null) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08003862 mInputEventReceiver.dispose();
3863 mInputEventReceiver = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -07003864 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003865 try {
Jeff Brown98365d72012-08-19 20:30:52 -07003866 mWindowSession.remove(mWindow);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003867 } catch (RemoteException e) {
3868 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003869
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003870 // Dispose the input channel after removing the window so the Window Manager
3871 // doesn't interpret the input channel being closed as an abnormal termination.
3872 if (mInputChannel != null) {
3873 mInputChannel.dispose();
3874 mInputChannel = null;
Jeff Brown349703e2010-06-22 01:27:15 -07003875 }
Jeff Brown96e942d2011-11-30 19:55:01 -08003876
Jeff Brownd912e1f2014-04-11 18:46:22 -07003877 mDisplayManager.unregisterDisplayListener(mDisplayListener);
3878
Jeff Brownebb2d8d2012-03-23 17:14:34 -07003879 unscheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003880 }
Romain Guy8506ab42009-06-11 17:35:47 -07003881
Andrii Kulian44607962017-03-16 11:06:24 -07003882 /**
3883 * Notifies all callbacks that configuration and/or display has changed and updates internal
3884 * state.
3885 * @param mergedConfiguration New global and override config in {@link MergedConfiguration}
3886 * container.
3887 * @param force Flag indicating if we should force apply the config.
3888 * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} if not
3889 * changed.
3890 */
3891 private void performConfigurationChange(MergedConfiguration mergedConfiguration, boolean force,
3892 int newDisplayId) {
3893 if (mergedConfiguration == null) {
3894 throw new IllegalArgumentException("No merged config provided.");
3895 }
Dianne Hackborn5fd21692011-06-07 14:09:47 -07003896
Andrii Kulian44607962017-03-16 11:06:24 -07003897 Configuration globalConfig = mergedConfiguration.getGlobalConfiguration();
3898 final Configuration overrideConfig = mergedConfiguration.getOverrideConfiguration();
3899 if (DEBUG_CONFIGURATION) Log.v(mTag,
3900 "Applying new config to window " + mWindowAttributes.getTitle()
3901 + ", globalConfig: " + globalConfig
3902 + ", overrideConfig: " + overrideConfig);
3903
3904 final CompatibilityInfo ci = mDisplay.getDisplayAdjustments().getCompatibilityInfo();
Craig Mautner48d0d182013-06-11 07:53:06 -07003905 if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
Andrii Kulian44607962017-03-16 11:06:24 -07003906 globalConfig = new Configuration(globalConfig);
3907 ci.applyToConfiguration(mNoncompatDensity, globalConfig);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07003908 }
3909
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003910 synchronized (sConfigCallbacks) {
3911 for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
Andrii Kulian44607962017-03-16 11:06:24 -07003912 sConfigCallbacks.get(i).onConfigurationChanged(globalConfig);
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003913 }
3914 }
Adam Lesinski4ece3d62016-06-16 18:05:41 -07003915
Andrii Kulian44607962017-03-16 11:06:24 -07003916 mLastReportedMergedConfiguration.setConfiguration(globalConfig, overrideConfig);
3917
3918 mForceNextConfigUpdate = force;
3919 if (mActivityConfigCallback != null) {
3920 // An activity callback is set - notify it about override configuration update.
3921 // This basically initiates a round trip to ActivityThread and back, which will ensure
3922 // that corresponding activity and resources are updated before updating inner state of
3923 // ViewRootImpl. Eventually it will call #updateConfiguration().
3924 mActivityConfigCallback.onConfigurationChanged(overrideConfig, newDisplayId);
3925 } else {
3926 // There is no activity callback - update the configuration right away.
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07003927 updateConfiguration(newDisplayId);
Andrii Kulian44607962017-03-16 11:06:24 -07003928 }
3929 mForceNextConfigUpdate = false;
3930 }
3931
3932 /**
3933 * Update display and views if last applied merged configuration changed.
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07003934 * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} otherwise.
Andrii Kulian44607962017-03-16 11:06:24 -07003935 */
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07003936 public void updateConfiguration(int newDisplayId) {
Andrii Kulian44607962017-03-16 11:06:24 -07003937 if (mView == null) {
3938 return;
3939 }
3940
3941 // At this point the resources have been updated to
3942 // have the most recent config, whatever that is. Use
3943 // the one in them which may be newer.
3944 final Resources localResources = mView.getResources();
3945 final Configuration config = localResources.getConfiguration();
Andrii Kuliane5c58ee2017-03-27 19:25:24 -07003946
3947 // Handle move to display.
3948 if (newDisplayId != INVALID_DISPLAY) {
3949 onMovedToDisplay(newDisplayId, config);
3950 }
3951
3952 // Handle configuration change.
Andrii Kulian44607962017-03-16 11:06:24 -07003953 if (mForceNextConfigUpdate || mLastConfigurationFromResources.diff(config) != 0) {
3954 // Update the display with new DisplayAdjustments.
3955 mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(
3956 mDisplay.getDisplayId(), localResources);
3957
3958 final int lastLayoutDirection = mLastConfigurationFromResources.getLayoutDirection();
3959 final int currentLayoutDirection = config.getLayoutDirection();
3960 mLastConfigurationFromResources.setTo(config);
3961 if (lastLayoutDirection != currentLayoutDirection
3962 && mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
3963 mView.setLayoutDirection(currentLayoutDirection);
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003964 }
Andrii Kulian44607962017-03-16 11:06:24 -07003965 mView.dispatchConfigurationChanged(config);
Bryce Leef858b572017-06-29 14:03:33 -07003966
3967 // We could have gotten this {@link Configuration} update after we called
3968 // {@link #performTraversals} with an older {@link Configuration}. As a result, our
3969 // window frame may be stale. We must ensure the next pass of {@link #performTraversals}
3970 // catches this.
3971 mForceNextWindowRelayout = true;
3972 requestLayout();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003973 }
3974 }
John Reck05e85842014-04-23 14:48:28 -07003975
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003976 /**
3977 * Return true if child is an ancestor of parent, (or equal to the parent).
3978 */
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07003979 public static boolean isViewDescendantOf(View child, View parent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003980 if (child == parent) {
3981 return true;
3982 }
3983
3984 final ViewParent theParent = child.getParent();
3985 return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
3986 }
3987
Yohei Yukawad2e56472015-07-28 17:00:33 -07003988 private static void forceLayout(View view) {
3989 view.forceLayout();
3990 if (view instanceof ViewGroup) {
3991 ViewGroup group = (ViewGroup) view;
3992 final int count = group.getChildCount();
3993 for (int i = 0; i < count; i++) {
3994 forceLayout(group.getChildAt(i));
3995 }
3996 }
3997 }
3998
Jeff Browna175a5b2012-02-15 19:18:31 -08003999 private final static int MSG_INVALIDATE = 1;
4000 private final static int MSG_INVALIDATE_RECT = 2;
4001 private final static int MSG_DIE = 3;
4002 private final static int MSG_RESIZED = 4;
4003 private final static int MSG_RESIZED_REPORT = 5;
4004 private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
keunyoung30f420f2013-08-02 14:23:10 -07004005 private final static int MSG_DISPATCH_INPUT_EVENT = 7;
Jeff Browna175a5b2012-02-15 19:18:31 -08004006 private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
4007 private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
Jeff Browna175a5b2012-02-15 19:18:31 -08004008 private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
Dake Gu6a20a192018-02-08 12:09:30 -08004009 private final static int MSG_DISPATCH_KEY_FROM_AUTOFILL = 12;
Jeff Browna175a5b2012-02-15 19:18:31 -08004010 private final static int MSG_CHECK_FOCUS = 13;
4011 private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
4012 private final static int MSG_DISPATCH_DRAG_EVENT = 15;
4013 private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
4014 private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
4015 private final static int MSG_UPDATE_CONFIGURATION = 18;
Svetoslav Ganov42138042012-03-20 11:51:39 -07004016 private final static int MSG_PROCESS_INPUT_EVENTS = 19;
Romain Guyfbb93fa2012-12-03 18:50:35 -08004017 private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
Jorim Jaggi827e0fa2015-05-07 11:41:41 -07004018 private final static int MSG_INVALIDATE_WORLD = 22;
4019 private final static int MSG_WINDOW_MOVED = 23;
4020 private final static int MSG_SYNTHESIZE_INPUT_EVENT = 24;
4021 private final static int MSG_DISPATCH_WINDOW_SHOWN = 25;
Clara Bayarri75e09792015-07-29 16:20:40 +01004022 private final static int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26;
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08004023 private final static int MSG_UPDATE_POINTER_ICON = 27;
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08004024 private final static int MSG_POINTER_CAPTURE_CHANGED = 28;
Robert Carr8508bb22017-03-27 15:46:27 -07004025 private final static int MSG_DRAW_FINISHED = 29;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004026
Jeff Browna175a5b2012-02-15 19:18:31 -08004027 final class ViewRootHandler extends Handler {
4028 @Override
4029 public String getMessageName(Message message) {
4030 switch (message.what) {
4031 case MSG_INVALIDATE:
4032 return "MSG_INVALIDATE";
4033 case MSG_INVALIDATE_RECT:
4034 return "MSG_INVALIDATE_RECT";
4035 case MSG_DIE:
4036 return "MSG_DIE";
4037 case MSG_RESIZED:
4038 return "MSG_RESIZED";
4039 case MSG_RESIZED_REPORT:
4040 return "MSG_RESIZED_REPORT";
4041 case MSG_WINDOW_FOCUS_CHANGED:
4042 return "MSG_WINDOW_FOCUS_CHANGED";
keunyoung30f420f2013-08-02 14:23:10 -07004043 case MSG_DISPATCH_INPUT_EVENT:
4044 return "MSG_DISPATCH_INPUT_EVENT";
Jeff Browna175a5b2012-02-15 19:18:31 -08004045 case MSG_DISPATCH_APP_VISIBILITY:
4046 return "MSG_DISPATCH_APP_VISIBILITY";
4047 case MSG_DISPATCH_GET_NEW_SURFACE:
4048 return "MSG_DISPATCH_GET_NEW_SURFACE";
Jeff Browna175a5b2012-02-15 19:18:31 -08004049 case MSG_DISPATCH_KEY_FROM_IME:
4050 return "MSG_DISPATCH_KEY_FROM_IME";
Dake Gu6a20a192018-02-08 12:09:30 -08004051 case MSG_DISPATCH_KEY_FROM_AUTOFILL:
4052 return "MSG_DISPATCH_KEY_FROM_AUTOFILL";
Jeff Browna175a5b2012-02-15 19:18:31 -08004053 case MSG_CHECK_FOCUS:
4054 return "MSG_CHECK_FOCUS";
4055 case MSG_CLOSE_SYSTEM_DIALOGS:
4056 return "MSG_CLOSE_SYSTEM_DIALOGS";
4057 case MSG_DISPATCH_DRAG_EVENT:
4058 return "MSG_DISPATCH_DRAG_EVENT";
4059 case MSG_DISPATCH_DRAG_LOCATION_EVENT:
4060 return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
4061 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
4062 return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
4063 case MSG_UPDATE_CONFIGURATION:
4064 return "MSG_UPDATE_CONFIGURATION";
Jeff Browna175a5b2012-02-15 19:18:31 -08004065 case MSG_PROCESS_INPUT_EVENTS:
4066 return "MSG_PROCESS_INPUT_EVENTS";
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07004067 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
4068 return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
Craig Mautner5702d4d2012-06-30 14:10:16 -07004069 case MSG_WINDOW_MOVED:
4070 return "MSG_WINDOW_MOVED";
Michael Wright899d7052014-04-23 17:23:39 -07004071 case MSG_SYNTHESIZE_INPUT_EVENT:
4072 return "MSG_SYNTHESIZE_INPUT_EVENT";
Craig Mautner9c795042014-10-28 19:59:59 -07004073 case MSG_DISPATCH_WINDOW_SHOWN:
4074 return "MSG_DISPATCH_WINDOW_SHOWN";
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08004075 case MSG_UPDATE_POINTER_ICON:
4076 return "MSG_UPDATE_POINTER_ICON";
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08004077 case MSG_POINTER_CAPTURE_CHANGED:
4078 return "MSG_POINTER_CAPTURE_CHANGED";
Robert Carr8508bb22017-03-27 15:46:27 -07004079 case MSG_DRAW_FINISHED:
4080 return "MSG_DRAW_FINISHED";
Jeff Browna175a5b2012-02-15 19:18:31 -08004081 }
4082 return super.getMessageName(message);
Romain Guyf9284692011-07-13 18:46:21 -07004083 }
Romain Guyf9284692011-07-13 18:46:21 -07004084
Jeff Browna175a5b2012-02-15 19:18:31 -08004085 @Override
Michael Wright53b854a2016-04-12 19:22:41 -04004086 public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
4087 if (msg.what == MSG_REQUEST_KEYBOARD_SHORTCUTS && msg.obj == null) {
4088 // Debugging for b/27963013
4089 throw new NullPointerException(
4090 "Attempted to call MSG_REQUEST_KEYBOARD_SHORTCUTS with null receiver:");
4091 }
4092 return super.sendMessageAtTime(msg, uptimeMillis);
4093 }
4094
4095 @Override
Jeff Browna175a5b2012-02-15 19:18:31 -08004096 public void handleMessage(Message msg) {
4097 switch (msg.what) {
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004098 case MSG_INVALIDATE:
4099 ((View) msg.obj).invalidate();
Jeff Browna175a5b2012-02-15 19:18:31 -08004100 break;
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004101 case MSG_INVALIDATE_RECT:
4102 final View.AttachInfo.InvalidateInfo info =
4103 (View.AttachInfo.InvalidateInfo) msg.obj;
4104 info.target.invalidate(info.left, info.top, info.right, info.bottom);
4105 info.recycle();
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07004106 break;
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004107 case MSG_PROCESS_INPUT_EVENTS:
4108 mProcessInputEventsScheduled = false;
4109 doProcessInputEvents();
4110 break;
4111 case MSG_DISPATCH_APP_VISIBILITY:
4112 handleAppVisibility(msg.arg1 != 0);
4113 break;
4114 case MSG_DISPATCH_GET_NEW_SURFACE:
4115 handleGetNewSurface();
4116 break;
4117 case MSG_RESIZED: {
4118 // Recycled in the fall through...
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004119 SomeArgs args = (SomeArgs) msg.obj;
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004120 if (mWinFrame.equals(args.arg1)
4121 && mPendingOverscanInsets.equals(args.arg5)
4122 && mPendingContentInsets.equals(args.arg2)
4123 && mPendingStableInsets.equals(args.arg6)
Adrian Roos5c6b6222017-11-07 17:36:10 +01004124 && mPendingDisplayCutout.get().equals(args.arg9)
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004125 && mPendingVisibleInsets.equals(args.arg3)
4126 && mPendingOutsets.equals(args.arg7)
4127 && mPendingBackDropFrame.equals(args.arg8)
4128 && args.arg4 == null
4129 && args.argi1 == 0
4130 && mDisplay.getDisplayId() == args.argi3) {
4131 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08004132 }
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004133 } // fall through...
4134 case MSG_RESIZED_REPORT:
4135 if (mAdded) {
4136 SomeArgs args = (SomeArgs) msg.obj;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004137
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004138 final int displayId = args.argi3;
4139 MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg4;
4140 final boolean displayChanged = mDisplay.getDisplayId() != displayId;
Jorim Jaggi26952d72016-04-01 17:43:14 -07004141
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004142 if (!mLastReportedMergedConfiguration.equals(mergedConfiguration)) {
4143 // If configuration changed - notify about that and, maybe,
4144 // about move to display.
4145 performConfigurationChange(mergedConfiguration, false /* force */,
4146 displayChanged
4147 ? displayId : INVALID_DISPLAY /* same display */);
4148 } else if (displayChanged) {
4149 // Moved to display without config change - report last applied one.
4150 onMovedToDisplay(displayId, mLastConfigurationFromResources);
4151 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004152
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004153 final boolean framesChanged = !mWinFrame.equals(args.arg1)
4154 || !mPendingOverscanInsets.equals(args.arg5)
4155 || !mPendingContentInsets.equals(args.arg2)
4156 || !mPendingStableInsets.equals(args.arg6)
Adrian Roos5c6b6222017-11-07 17:36:10 +01004157 || !mPendingDisplayCutout.get().equals(args.arg9)
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004158 || !mPendingVisibleInsets.equals(args.arg3)
4159 || !mPendingOutsets.equals(args.arg7);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004160
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004161 mWinFrame.set((Rect) args.arg1);
4162 mPendingOverscanInsets.set((Rect) args.arg5);
4163 mPendingContentInsets.set((Rect) args.arg2);
4164 mPendingStableInsets.set((Rect) args.arg6);
Adrian Roos5c6b6222017-11-07 17:36:10 +01004165 mPendingDisplayCutout.set((DisplayCutout) args.arg9);
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004166 mPendingVisibleInsets.set((Rect) args.arg3);
4167 mPendingOutsets.set((Rect) args.arg7);
4168 mPendingBackDropFrame.set((Rect) args.arg8);
4169 mForceNextWindowRelayout = args.argi1 != 0;
4170 mPendingAlwaysConsumeNavBar = args.argi2 != 0;
4171
4172 args.recycle();
4173
4174 if (msg.what == MSG_RESIZED_REPORT) {
4175 reportNextDraw();
4176 }
4177
4178 if (mView != null && framesChanged) {
4179 forceLayout(mView);
4180 }
4181 requestLayout();
Jeff Browna175a5b2012-02-15 19:18:31 -08004182 }
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004183 break;
4184 case MSG_WINDOW_MOVED:
4185 if (mAdded) {
4186 final int w = mWinFrame.width();
4187 final int h = mWinFrame.height();
4188 final int l = msg.arg1;
4189 final int t = msg.arg2;
4190 mWinFrame.left = l;
4191 mWinFrame.right = l + w;
4192 mWinFrame.top = t;
4193 mWinFrame.bottom = t + h;
Romain Guy59a12ca2011-06-09 17:48:21 -07004194
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004195 mPendingBackDropFrame.set(mWinFrame);
4196 maybeHandleWindowMove(mWinFrame);
Yohei Yukawad2e56472015-07-28 17:00:33 -07004197 }
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004198 break;
4199 case MSG_WINDOW_FOCUS_CHANGED: {
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08004200 handleWindowFocusChanged();
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004201 } break;
4202 case MSG_DIE:
4203 doDie();
4204 break;
4205 case MSG_DISPATCH_INPUT_EVENT: {
4206 SomeArgs args = (SomeArgs) msg.obj;
4207 InputEvent event = (InputEvent) args.arg1;
4208 InputEventReceiver receiver = (InputEventReceiver) args.arg2;
4209 enqueueInputEvent(event, receiver, 0, true);
4210 args.recycle();
4211 } break;
4212 case MSG_SYNTHESIZE_INPUT_EVENT: {
4213 InputEvent event = (InputEvent) msg.obj;
4214 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_UNHANDLED, true);
4215 } break;
4216 case MSG_DISPATCH_KEY_FROM_IME: {
4217 if (LOCAL_LOGV) {
4218 Log.v(TAG, "Dispatching key " + msg.obj + " from IME to " + mView);
4219 }
4220 KeyEvent event = (KeyEvent) msg.obj;
4221 if ((event.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) != 0) {
4222 // The IME is trying to say this event is from the
4223 // system! Bad bad bad!
4224 //noinspection UnusedAssignment
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07004225 event = KeyEvent.changeFlags(event,
4226 event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004227 }
4228 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
4229 } break;
Dake Gu6a20a192018-02-08 12:09:30 -08004230 case MSG_DISPATCH_KEY_FROM_AUTOFILL: {
4231 if (LOCAL_LOGV) {
4232 Log.v(TAG, "Dispatching key " + msg.obj + " from Autofill to " + mView);
4233 }
4234 KeyEvent event = (KeyEvent) msg.obj;
Dake Gud9dbd272018-03-13 11:38:42 -07004235 enqueueInputEvent(event, null, 0, true);
Dake Gu6a20a192018-02-08 12:09:30 -08004236 } break;
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004237 case MSG_CHECK_FOCUS: {
Jeff Browna175a5b2012-02-15 19:18:31 -08004238 InputMethodManager imm = InputMethodManager.peekInstance();
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004239 if (imm != null) {
4240 imm.checkFocus();
Yohei Yukawa5f059652015-05-14 22:16:41 -07004241 }
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004242 } break;
4243 case MSG_CLOSE_SYSTEM_DIALOGS: {
Jeff Browna175a5b2012-02-15 19:18:31 -08004244 if (mView != null) {
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004245 mView.onCloseSystemDialogs((String) msg.obj);
4246 }
4247 } break;
4248 case MSG_DISPATCH_DRAG_EVENT: {
4249 } // fall through
4250 case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
4251 DragEvent event = (DragEvent) msg.obj;
4252 // only present when this app called startDrag()
4253 event.mLocalState = mLocalDragState;
4254 handleDragEvent(event);
4255 } break;
4256 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
4257 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj);
4258 } break;
4259 case MSG_UPDATE_CONFIGURATION: {
4260 Configuration config = (Configuration) msg.obj;
4261 if (config.isOtherSeqNewer(
4262 mLastReportedMergedConfiguration.getMergedConfiguration())) {
4263 // If we already have a newer merged config applied - use its global part.
4264 config = mLastReportedMergedConfiguration.getGlobalConfiguration();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004265 }
svetoslavganov75986cf2009-05-14 22:28:01 -07004266
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004267 // Use the newer global config and last reported override config.
4268 mPendingMergedConfiguration.setConfiguration(config,
4269 mLastReportedMergedConfiguration.getOverrideConfiguration());
4270
4271 performConfigurationChange(mPendingMergedConfiguration, false /* force */,
4272 INVALID_DISPLAY /* same display */);
4273 } break;
4274 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
4275 setAccessibilityFocus(null, null);
4276 } break;
4277 case MSG_INVALIDATE_WORLD: {
4278 if (mView != null) {
4279 invalidateWorld(mView);
Jeff Browna175a5b2012-02-15 19:18:31 -08004280 }
Siarhei Vishniakou27358ef2017-10-12 11:00:35 -07004281 } break;
4282 case MSG_DISPATCH_WINDOW_SHOWN: {
4283 handleDispatchWindowShown();
4284 } break;
4285 case MSG_REQUEST_KEYBOARD_SHORTCUTS: {
4286 final IResultReceiver receiver = (IResultReceiver) msg.obj;
4287 final int deviceId = msg.arg1;
4288 handleRequestKeyboardShortcuts(receiver, deviceId);
4289 } break;
4290 case MSG_UPDATE_POINTER_ICON: {
4291 MotionEvent event = (MotionEvent) msg.obj;
4292 resetPointerIcon(event);
4293 } break;
4294 case MSG_POINTER_CAPTURE_CHANGED: {
4295 final boolean hasCapture = msg.arg1 != 0;
4296 handlePointerCaptureChanged(hasCapture);
4297 } break;
4298 case MSG_DRAW_FINISHED: {
4299 pendingDrawFinished();
4300 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004301 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004302 }
4303 }
Romain Guy51e4d4d2012-03-15 18:30:47 -07004304
Jeff Browna175a5b2012-02-15 19:18:31 -08004305 final ViewRootHandler mHandler = new ViewRootHandler();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004306
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004307 /**
4308 * Something in the current window tells us we need to change the touch mode. For
4309 * example, we are not in touch mode, and the user touches the screen.
4310 *
4311 * If the touch mode has changed, tell the window manager, and handle it locally.
4312 *
4313 * @param inTouchMode Whether we want to be in touch mode.
4314 * @return True if the touch mode changed and focus changed was changed as a result
4315 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +01004316 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004317 boolean ensureTouchMode(boolean inTouchMode) {
4318 if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
4319 + "touch mode is " + mAttachInfo.mInTouchMode);
4320 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
4321
4322 // tell the window manager
4323 try {
Matt Wud6bc96d2016-01-14 12:59:24 -08004324 mWindowSession.setInTouchMode(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004325 } catch (RemoteException e) {
4326 throw new RuntimeException(e);
4327 }
4328
4329 // handle the change
Romain Guy2d4cff62010-04-09 15:39:00 -07004330 return ensureTouchModeLocally(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004331 }
4332
4333 /**
4334 * Ensure that the touch mode for this window is set, and if it is changing,
4335 * take the appropriate action.
4336 * @param inTouchMode Whether we want to be in touch mode.
4337 * @return True if the touch mode changed and focus changed was changed as a result
4338 */
Romain Guy2d4cff62010-04-09 15:39:00 -07004339 private boolean ensureTouchModeLocally(boolean inTouchMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004340 if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
4341 + "touch mode is " + mAttachInfo.mInTouchMode);
4342
4343 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
4344
4345 mAttachInfo.mInTouchMode = inTouchMode;
4346 mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
4347
Romain Guy2d4cff62010-04-09 15:39:00 -07004348 return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004349 }
4350
4351 private boolean enterTouchMode() {
Alan Viveretteed7821a2013-07-24 15:49:23 -07004352 if (mView != null && mView.hasFocus()) {
4353 // note: not relying on mFocusedView here because this could
4354 // be when the window is first being added, and mFocused isn't
4355 // set yet.
4356 final View focused = mView.findFocus();
4357 if (focused != null && !focused.isFocusableInTouchMode()) {
4358 final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
4359 if (ancestorToTakeFocus != null) {
4360 // there is an ancestor that wants focus after its
4361 // descendants that is focusable in touch mode.. give it
4362 // focus
4363 return ancestorToTakeFocus.requestFocus();
4364 } else {
Alan Viverette973f3b42013-08-13 16:57:28 -07004365 // There's nothing to focus. Clear and propagate through the
4366 // hierarchy, but don't attempt to place new focus.
Alan Viverette223622a2013-12-17 13:29:02 -08004367 focused.clearFocusInternal(null, true, false);
Alan Viveretteed7821a2013-07-24 15:49:23 -07004368 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004369 }
4370 }
4371 }
4372 return false;
4373 }
4374
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004375 /**
4376 * Find an ancestor of focused that wants focus after its descendants and is
4377 * focusable in touch mode.
4378 * @param focused The currently focused view.
4379 * @return An appropriate view, or null if no such view exists.
4380 */
Romain Guya998dff2012-03-23 18:58:36 -07004381 private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004382 ViewParent parent = focused.getParent();
4383 while (parent instanceof ViewGroup) {
4384 final ViewGroup vgParent = (ViewGroup) parent;
4385 if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
4386 && vgParent.isFocusableInTouchMode()) {
4387 return vgParent;
4388 }
4389 if (vgParent.isRootNamespace()) {
4390 return null;
4391 } else {
4392 parent = vgParent.getParent();
4393 }
4394 }
4395 return null;
4396 }
4397
4398 private boolean leaveTouchMode() {
4399 if (mView != null) {
4400 if (mView.hasFocus()) {
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004401 View focusedView = mView.findFocus();
4402 if (!(focusedView instanceof ViewGroup)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004403 // some view has focus, let it keep it
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07004404 return false;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004405 } else if (((ViewGroup) focusedView).getDescendantFocusability() !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004406 ViewGroup.FOCUS_AFTER_DESCENDANTS) {
4407 // some view group has focus, and doesn't prefer its children
4408 // over itself for focus, so let them keep it.
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07004409 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004410 }
4411 }
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07004412
4413 // find the best view to give focus to in this brave new non-touch-mode
4414 // world
Evan Roskybdc66cb2017-09-08 14:27:24 -07004415 return mView.restoreDefaultFocus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004416 }
4417 return false;
4418 }
4419
Jeff Brownf9e989d2013-04-04 23:04:03 -07004420 /**
4421 * Base class for implementing a stage in the chain of responsibility
4422 * for processing input events.
4423 * <p>
4424 * Events are delivered to the stage by the {@link #deliver} method. The stage
4425 * then has the choice of finishing the event or forwarding it to the next stage.
4426 * </p>
4427 */
4428 abstract class InputStage {
4429 private final InputStage mNext;
4430
4431 protected static final int FORWARD = 0;
4432 protected static final int FINISH_HANDLED = 1;
4433 protected static final int FINISH_NOT_HANDLED = 2;
4434
4435 /**
4436 * Creates an input stage.
4437 * @param next The next stage to which events should be forwarded.
4438 */
4439 public InputStage(InputStage next) {
4440 mNext = next;
4441 }
4442
4443 /**
4444 * Delivers an event to be processed.
4445 */
4446 public final void deliver(QueuedInputEvent q) {
4447 if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
4448 forward(q);
Michael Wright17d28ca2013-10-31 17:47:45 -07004449 } else if (shouldDropInputEvent(q)) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004450 finish(q, false);
4451 } else {
4452 apply(q, onProcess(q));
4453 }
4454 }
4455
4456 /**
4457 * Marks the the input event as finished then forwards it to the next stage.
4458 */
4459 protected void finish(QueuedInputEvent q, boolean handled) {
4460 q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
4461 if (handled) {
4462 q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
4463 }
4464 forward(q);
4465 }
4466
4467 /**
4468 * Forwards the event to the next stage.
4469 */
4470 protected void forward(QueuedInputEvent q) {
4471 onDeliverToNext(q);
4472 }
4473
4474 /**
4475 * Applies a result code from {@link #onProcess} to the specified event.
4476 */
4477 protected void apply(QueuedInputEvent q, int result) {
4478 if (result == FORWARD) {
4479 forward(q);
4480 } else if (result == FINISH_HANDLED) {
4481 finish(q, true);
4482 } else if (result == FINISH_NOT_HANDLED) {
4483 finish(q, false);
4484 } else {
4485 throw new IllegalArgumentException("Invalid result: " + result);
4486 }
4487 }
4488
4489 /**
4490 * Called when an event is ready to be processed.
4491 * @return A result code indicating how the event was handled.
4492 */
4493 protected int onProcess(QueuedInputEvent q) {
4494 return FORWARD;
4495 }
4496
4497 /**
4498 * Called when an event is being delivered to the next stage.
4499 */
4500 protected void onDeliverToNext(QueuedInputEvent q) {
Michael Wright06a79252014-05-05 17:45:29 -07004501 if (DEBUG_INPUT_STAGES) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004502 Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);
Michael Wright06a79252014-05-05 17:45:29 -07004503 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004504 if (mNext != null) {
4505 mNext.deliver(q);
4506 } else {
4507 finishInputEvent(q);
4508 }
4509 }
Jeff Brown5182c782013-10-15 20:31:52 -07004510
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07004511 protected void onWindowFocusChanged(boolean hasWindowFocus) {
4512 if (mNext != null) {
4513 mNext.onWindowFocusChanged(hasWindowFocus);
4514 }
4515 }
4516
4517 protected void onDetachedFromWindow() {
4518 if (mNext != null) {
4519 mNext.onDetachedFromWindow();
4520 }
4521 }
4522
Michael Wright17d28ca2013-10-31 17:47:45 -07004523 protected boolean shouldDropInputEvent(QueuedInputEvent q) {
4524 if (mView == null || !mAdded) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004525 Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent);
Michael Wright17d28ca2013-10-31 17:47:45 -07004526 return true;
George Mount41725de2015-04-09 08:23:05 -07004527 } else if ((!mAttachInfo.mHasWindowFocus
Dake Gu6a20a192018-02-08 12:09:30 -08004528 && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
Dake Gud9dbd272018-03-13 11:38:42 -07004529 && !isAutofillUiShowing()) || mStopped
Joe LaPenna90776de2016-01-22 07:11:49 -08004530 || (mIsAmbientMode && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON))
4531 || (mPausedForTransition && !isBack(q.mEvent))) {
Wale Ogunwalec3672cd2014-11-05 15:17:35 -08004532 // This is a focus event and the window doesn't currently have input focus or
4533 // has stopped. This could be an event that came back from the previous stage
4534 // but the window has lost focus or stopped in the meantime.
4535 if (isTerminalInputEvent(q.mEvent)) {
4536 // Don't drop terminal input events, however mark them as canceled.
4537 q.mEvent.cancel();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004538 Slog.w(mTag, "Cancelling event due to no window focus: " + q.mEvent);
Wale Ogunwalec3672cd2014-11-05 15:17:35 -08004539 return false;
4540 }
4541
4542 // Drop non-terminal input events.
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004543 Slog.w(mTag, "Dropping event due to no window focus: " + q.mEvent);
Michael Wright17d28ca2013-10-31 17:47:45 -07004544 return true;
4545 }
4546 return false;
4547 }
4548
Jeff Brown5182c782013-10-15 20:31:52 -07004549 void dump(String prefix, PrintWriter writer) {
4550 if (mNext != null) {
4551 mNext.dump(prefix, writer);
4552 }
4553 }
George Mount41725de2015-04-09 08:23:05 -07004554
4555 private boolean isBack(InputEvent event) {
4556 if (event instanceof KeyEvent) {
4557 return ((KeyEvent) event).getKeyCode() == KeyEvent.KEYCODE_BACK;
4558 } else {
4559 return false;
4560 }
4561 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004562 }
4563
4564 /**
4565 * Base class for implementing an input pipeline stage that supports
4566 * asynchronous and out-of-order processing of input events.
4567 * <p>
4568 * In addition to what a normal input stage can do, an asynchronous
4569 * input stage may also defer an input event that has been delivered to it
4570 * and finish or forward it later.
4571 * </p>
4572 */
4573 abstract class AsyncInputStage extends InputStage {
4574 private final String mTraceCounter;
4575
4576 private QueuedInputEvent mQueueHead;
4577 private QueuedInputEvent mQueueTail;
4578 private int mQueueLength;
4579
4580 protected static final int DEFER = 3;
4581
4582 /**
4583 * Creates an asynchronous input stage.
4584 * @param next The next stage to which events should be forwarded.
4585 * @param traceCounter The name of a counter to record the size of
4586 * the queue of pending events.
4587 */
4588 public AsyncInputStage(InputStage next, String traceCounter) {
4589 super(next);
4590 mTraceCounter = traceCounter;
4591 }
4592
4593 /**
4594 * Marks the event as deferred, which is to say that it will be handled
4595 * asynchronously. The caller is responsible for calling {@link #forward}
4596 * or {@link #finish} later when it is done handling the event.
4597 */
4598 protected void defer(QueuedInputEvent q) {
4599 q.mFlags |= QueuedInputEvent.FLAG_DEFERRED;
4600 enqueue(q);
4601 }
4602
4603 @Override
4604 protected void forward(QueuedInputEvent q) {
4605 // Clear the deferred flag.
4606 q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED;
4607
4608 // Fast path if the queue is empty.
4609 QueuedInputEvent curr = mQueueHead;
4610 if (curr == null) {
4611 super.forward(q);
4612 return;
4613 }
4614
4615 // Determine whether the event must be serialized behind any others
4616 // before it can be delivered to the next stage. This is done because
4617 // deferred events might be handled out of order by the stage.
4618 final int deviceId = q.mEvent.getDeviceId();
4619 QueuedInputEvent prev = null;
4620 boolean blocked = false;
4621 while (curr != null && curr != q) {
4622 if (!blocked && deviceId == curr.mEvent.getDeviceId()) {
4623 blocked = true;
4624 }
4625 prev = curr;
4626 curr = curr.mNext;
4627 }
4628
4629 // If the event is blocked, then leave it in the queue to be delivered later.
4630 // Note that the event might not yet be in the queue if it was not previously
4631 // deferred so we will enqueue it if needed.
4632 if (blocked) {
4633 if (curr == null) {
4634 enqueue(q);
4635 }
4636 return;
4637 }
4638
4639 // The event is not blocked. Deliver it immediately.
4640 if (curr != null) {
4641 curr = curr.mNext;
4642 dequeue(q, prev);
4643 }
4644 super.forward(q);
4645
4646 // Dequeuing this event may have unblocked successors. Deliver them.
4647 while (curr != null) {
4648 if (deviceId == curr.mEvent.getDeviceId()) {
4649 if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) {
4650 break;
4651 }
4652 QueuedInputEvent next = curr.mNext;
4653 dequeue(curr, prev);
4654 super.forward(curr);
4655 curr = next;
4656 } else {
4657 prev = curr;
4658 curr = curr.mNext;
4659 }
4660 }
4661 }
4662
4663 @Override
4664 protected void apply(QueuedInputEvent q, int result) {
4665 if (result == DEFER) {
4666 defer(q);
4667 } else {
4668 super.apply(q, result);
4669 }
4670 }
4671
4672 private void enqueue(QueuedInputEvent q) {
4673 if (mQueueTail == null) {
4674 mQueueHead = q;
4675 mQueueTail = q;
4676 } else {
4677 mQueueTail.mNext = q;
4678 mQueueTail = q;
4679 }
4680
4681 mQueueLength += 1;
4682 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
4683 }
4684
4685 private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) {
4686 if (prev == null) {
4687 mQueueHead = q.mNext;
4688 } else {
4689 prev.mNext = q.mNext;
4690 }
4691 if (mQueueTail == q) {
4692 mQueueTail = prev;
4693 }
4694 q.mNext = null;
4695
4696 mQueueLength -= 1;
4697 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
4698 }
Jeff Brown5182c782013-10-15 20:31:52 -07004699
4700 @Override
4701 void dump(String prefix, PrintWriter writer) {
4702 writer.print(prefix);
4703 writer.print(getClass().getName());
4704 writer.print(": mQueueLength=");
4705 writer.println(mQueueLength);
4706
4707 super.dump(prefix, writer);
4708 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004709 }
4710
4711 /**
4712 * Delivers pre-ime input events to a native activity.
4713 * Does not support pointer events.
4714 */
Michael Wrighta44dd262013-04-10 21:12:00 -07004715 final class NativePreImeInputStage extends AsyncInputStage
4716 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004717 public NativePreImeInputStage(InputStage next, String traceCounter) {
4718 super(next, traceCounter);
4719 }
4720
4721 @Override
4722 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07004723 if (mInputQueue != null && q.mEvent instanceof KeyEvent) {
4724 mInputQueue.sendInputEvent(q.mEvent, q, true, this);
4725 return DEFER;
4726 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004727 return FORWARD;
4728 }
Michael Wrighta44dd262013-04-10 21:12:00 -07004729
4730 @Override
4731 public void onFinishedInputEvent(Object token, boolean handled) {
4732 QueuedInputEvent q = (QueuedInputEvent)token;
4733 if (handled) {
4734 finish(q, true);
4735 return;
4736 }
4737 forward(q);
4738 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004739 }
4740
4741 /**
4742 * Delivers pre-ime input events to the view hierarchy.
4743 * Does not support pointer events.
4744 */
4745 final class ViewPreImeInputStage extends InputStage {
4746 public ViewPreImeInputStage(InputStage next) {
4747 super(next);
4748 }
4749
4750 @Override
4751 protected int onProcess(QueuedInputEvent q) {
Jeff Brown481c1572012-03-09 14:41:15 -08004752 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004753 return processKeyEvent(q);
4754 }
4755 return FORWARD;
4756 }
4757
4758 private int processKeyEvent(QueuedInputEvent q) {
4759 final KeyEvent event = (KeyEvent)q.mEvent;
4760 if (mView.dispatchKeyEventPreIme(event)) {
4761 return FINISH_HANDLED;
4762 }
4763 return FORWARD;
4764 }
4765 }
4766
4767 /**
4768 * Delivers input events to the ime.
4769 * Does not support pointer events.
4770 */
4771 final class ImeInputStage extends AsyncInputStage
4772 implements InputMethodManager.FinishedInputEventCallback {
4773 public ImeInputStage(InputStage next, String traceCounter) {
4774 super(next, traceCounter);
4775 }
4776
4777 @Override
4778 protected int onProcess(QueuedInputEvent q) {
keunyoung30f420f2013-08-02 14:23:10 -07004779 if (mLastWasImTarget && !isInLocalFocusMode()) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004780 InputMethodManager imm = InputMethodManager.peekInstance();
4781 if (imm != null) {
4782 final InputEvent event = q.mEvent;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004783 if (DEBUG_IMF) Log.v(mTag, "Sending input event to IME: " + event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004784 int result = imm.dispatchInputEvent(event, q, this, mHandler);
4785 if (result == InputMethodManager.DISPATCH_HANDLED) {
4786 return FINISH_HANDLED;
4787 } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
Adam Lesinskic0f6eed2013-10-28 16:03:19 -07004788 // The IME could not handle it, so skip along to the next InputStage
4789 return FORWARD;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004790 } else {
4791 return DEFER; // callback will be invoked later
4792 }
4793 }
4794 }
4795 return FORWARD;
4796 }
4797
4798 @Override
4799 public void onFinishedInputEvent(Object token, boolean handled) {
4800 QueuedInputEvent q = (QueuedInputEvent)token;
4801 if (handled) {
4802 finish(q, true);
4803 return;
4804 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004805 forward(q);
4806 }
4807 }
4808
4809 /**
4810 * Performs early processing of post-ime input events.
4811 */
4812 final class EarlyPostImeInputStage extends InputStage {
4813 public EarlyPostImeInputStage(InputStage next) {
4814 super(next);
4815 }
4816
4817 @Override
4818 protected int onProcess(QueuedInputEvent q) {
4819 if (q.mEvent instanceof KeyEvent) {
4820 return processKeyEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08004821 } else {
Jeff Brown481c1572012-03-09 14:41:15 -08004822 final int source = q.mEvent.getSource();
4823 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004824 return processPointerEvent(q);
Jeff Brown481c1572012-03-09 14:41:15 -08004825 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08004826 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004827 return FORWARD;
4828 }
4829
4830 private int processKeyEvent(QueuedInputEvent q) {
4831 final KeyEvent event = (KeyEvent)q.mEvent;
4832
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08004833 if (mAttachInfo.mTooltipHost != null) {
4834 mAttachInfo.mTooltipHost.handleTooltipKey(event);
4835 }
4836
Jeff Brownf9e989d2013-04-04 23:04:03 -07004837 // If the key's purpose is to exit touch mode then we consume it
4838 // and consider it handled.
4839 if (checkForLeavingTouchModeAndConsume(event)) {
4840 return FINISH_HANDLED;
4841 }
4842
4843 // Make sure the fallback event policy sees all keys that will be
4844 // delivered to the view hierarchy.
4845 mFallbackEventHandler.preDispatchKeyEvent(event);
4846 return FORWARD;
4847 }
4848
4849 private int processPointerEvent(QueuedInputEvent q) {
4850 final MotionEvent event = (MotionEvent)q.mEvent;
4851
4852 // Translate the pointer event for compatibility, if needed.
4853 if (mTranslator != null) {
4854 mTranslator.translateEventInScreenToAppWindow(event);
4855 }
4856
Vladislav Kaznacheev7614cdf2017-02-21 11:57:59 -08004857 // Enter touch mode on down or scroll, if it is coming from a touch screen device,
4858 // exit otherwise.
Jeff Brownf9e989d2013-04-04 23:04:03 -07004859 final int action = event.getAction();
Vladislav Kaznacheev7614cdf2017-02-21 11:57:59 -08004860 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
4861 ensureTouchMode(event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN));
Jeff Brownf9e989d2013-04-04 23:04:03 -07004862 }
4863
Dake Gud9dbd272018-03-13 11:38:42 -07004864 if (action == MotionEvent.ACTION_DOWN) {
Dake Gub0fa3782018-02-26 12:25:14 -08004865 // Upon motion event within app window, close autofill ui.
Dake Gud9dbd272018-03-13 11:38:42 -07004866 AutofillManager afm = getAutofillManager();
4867 if (afm != null) {
4868 afm.requestHideFillUi();
Dake Gub0fa3782018-02-26 12:25:14 -08004869 }
4870 }
4871
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08004872 if (action == MotionEvent.ACTION_DOWN && mAttachInfo.mTooltipHost != null) {
4873 mAttachInfo.mTooltipHost.hideTooltip();
4874 }
4875
Jeff Brownf9e989d2013-04-04 23:04:03 -07004876 // Offset the scroll position.
4877 if (mCurScrollY != 0) {
4878 event.offsetLocation(0, mCurScrollY);
4879 }
4880
4881 // Remember the touch position for possible drag-initiation.
4882 if (event.isTouchEvent()) {
4883 mLastTouchPoint.x = event.getRawX();
4884 mLastTouchPoint.y = event.getRawY();
Vladislav Kaznacheevba761122016-01-22 12:09:45 -08004885 mLastTouchSource = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004886 }
4887 return FORWARD;
Jeff Brown4952dfd2011-11-30 19:23:22 -08004888 }
4889 }
4890
Jeff Brownf9e989d2013-04-04 23:04:03 -07004891 /**
4892 * Delivers post-ime input events to a native activity.
4893 */
Michael Wrighta44dd262013-04-10 21:12:00 -07004894 final class NativePostImeInputStage extends AsyncInputStage
4895 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004896 public NativePostImeInputStage(InputStage next, String traceCounter) {
4897 super(next, traceCounter);
4898 }
4899
4900 @Override
4901 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07004902 if (mInputQueue != null) {
4903 mInputQueue.sendInputEvent(q.mEvent, q, false, this);
4904 return DEFER;
4905 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004906 return FORWARD;
4907 }
Michael Wrighta44dd262013-04-10 21:12:00 -07004908
4909 @Override
4910 public void onFinishedInputEvent(Object token, boolean handled) {
4911 QueuedInputEvent q = (QueuedInputEvent)token;
4912 if (handled) {
4913 finish(q, true);
4914 return;
4915 }
4916 forward(q);
4917 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004918 }
4919
4920 /**
4921 * Delivers post-ime input events to the view hierarchy.
4922 */
4923 final class ViewPostImeInputStage extends InputStage {
4924 public ViewPostImeInputStage(InputStage next) {
4925 super(next);
4926 }
4927
4928 @Override
4929 protected int onProcess(QueuedInputEvent q) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08004930 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004931 return processKeyEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08004932 } else {
4933 final int source = q.mEvent.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004934 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
4935 return processPointerEvent(q);
4936 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
4937 return processTrackballEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08004938 } else {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004939 return processGenericMotionEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08004940 }
4941 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08004942 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08004943
Michael Wright9d744c72014-02-18 21:27:42 -08004944 @Override
4945 protected void onDeliverToNext(QueuedInputEvent q) {
4946 if (mUnbufferedInputDispatch
4947 && q.mEvent instanceof MotionEvent
4948 && ((MotionEvent)q.mEvent).isTouchEvent()
4949 && isTerminalInputEvent(q.mEvent)) {
4950 mUnbufferedInputDispatch = false;
4951 scheduleConsumeBatchedInput();
4952 }
4953 super.onDeliverToNext(q);
4954 }
4955
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08004956 private boolean performFocusNavigation(KeyEvent event) {
4957 int direction = 0;
4958 switch (event.getKeyCode()) {
4959 case KeyEvent.KEYCODE_DPAD_LEFT:
4960 if (event.hasNoModifiers()) {
4961 direction = View.FOCUS_LEFT;
4962 }
4963 break;
4964 case KeyEvent.KEYCODE_DPAD_RIGHT:
4965 if (event.hasNoModifiers()) {
4966 direction = View.FOCUS_RIGHT;
4967 }
4968 break;
4969 case KeyEvent.KEYCODE_DPAD_UP:
4970 if (event.hasNoModifiers()) {
4971 direction = View.FOCUS_UP;
4972 }
4973 break;
4974 case KeyEvent.KEYCODE_DPAD_DOWN:
4975 if (event.hasNoModifiers()) {
4976 direction = View.FOCUS_DOWN;
4977 }
4978 break;
4979 case KeyEvent.KEYCODE_TAB:
4980 if (event.hasNoModifiers()) {
4981 direction = View.FOCUS_FORWARD;
4982 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
4983 direction = View.FOCUS_BACKWARD;
4984 }
4985 break;
4986 }
4987 if (direction != 0) {
4988 View focused = mView.findFocus();
4989 if (focused != null) {
4990 View v = focused.focusSearch(direction);
4991 if (v != null && v != focused) {
4992 // do the math the get the interesting rect
4993 // of previous focused into the coord system of
4994 // newly focused view
4995 focused.getFocusedRect(mTempRect);
4996 if (mView instanceof ViewGroup) {
4997 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
4998 focused, mTempRect);
4999 ((ViewGroup) mView).offsetRectIntoDescendantCoords(
5000 v, mTempRect);
5001 }
5002 if (v.requestFocus(direction, mTempRect)) {
5003 playSoundEffect(SoundEffectConstants
5004 .getContantForFocusDirection(direction));
5005 return true;
5006 }
5007 }
5008
5009 // Give the focused view a last chance to handle the dpad key.
5010 if (mView.dispatchUnhandledMove(focused, direction)) {
5011 return true;
5012 }
5013 } else {
Evan Rosky37df2db2017-01-24 16:35:52 -08005014 if (mView.restoreDefaultFocus()) {
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08005015 return true;
5016 }
5017 }
5018 }
5019 return false;
5020 }
5021
Vadim Tryshevb5ced222017-01-17 19:31:35 -08005022 private boolean performKeyboardGroupNavigation(int direction) {
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08005023 final View focused = mView.findFocus();
Evan Rosky37df2db2017-01-24 16:35:52 -08005024 if (focused == null && mView.restoreDefaultFocus()) {
5025 return true;
5026 }
Evan Rosky5b860712017-04-17 16:40:16 -07005027 View cluster = focused == null ? keyboardNavigationClusterSearch(null, direction)
5028 : focused.keyboardNavigationClusterSearch(null, direction);
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08005029
Evan Rosky53fcf112017-01-26 14:37:55 -08005030 // Since requestFocus only takes "real" focus directions (and therefore also
5031 // restoreFocusInCluster), convert forward/backward focus into FOCUS_DOWN.
5032 int realDirection = direction;
5033 if (direction == View.FOCUS_FORWARD || direction == View.FOCUS_BACKWARD) {
5034 realDirection = View.FOCUS_DOWN;
5035 }
5036
Evan Rosky3ac64632017-02-13 18:04:43 -08005037 if (cluster != null && cluster.isRootNamespace()) {
5038 // the default cluster. Try to find a non-clustered view to focus.
5039 if (cluster.restoreFocusNotInCluster()) {
Evan Roskybd10c522017-03-27 15:50:38 -07005040 playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
Evan Rosky3ac64632017-02-13 18:04:43 -08005041 return true;
5042 }
5043 // otherwise skip to next actual cluster
5044 cluster = keyboardNavigationClusterSearch(null, direction);
5045 }
5046
Evan Rosky53fcf112017-01-26 14:37:55 -08005047 if (cluster != null && cluster.restoreFocusInCluster(realDirection)) {
Evan Roskybd10c522017-03-27 15:50:38 -07005048 playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08005049 return true;
5050 }
5051
5052 return false;
5053 }
5054
Jeff Brownf9e989d2013-04-04 23:04:03 -07005055 private int processKeyEvent(QueuedInputEvent q) {
5056 final KeyEvent event = (KeyEvent)q.mEvent;
5057
Evan Roskycd80e612018-05-17 17:46:09 -07005058 if (mUnhandledKeyManager.preViewDispatch(event)) {
Evan Rosky5e29c072017-06-02 17:31:22 -07005059 return FINISH_HANDLED;
5060 }
5061
Jeff Brownf9e989d2013-04-04 23:04:03 -07005062 // Deliver the key to the view hierarchy.
5063 if (mView.dispatchKeyEvent(event)) {
5064 return FINISH_HANDLED;
Jeff Brown21bc5c92011-02-28 18:27:14 -08005065 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005066
Michael Wright17d28ca2013-10-31 17:47:45 -07005067 if (shouldDropInputEvent(q)) {
5068 return FINISH_NOT_HANDLED;
5069 }
5070
Evan Roskycd80e612018-05-17 17:46:09 -07005071 // This dispatch is for windows that don't have a Window.Callback. Otherwise,
5072 // the Window.Callback usually will have already called this (see
5073 // DecorView.superDispatchKeyEvent) leaving this call a no-op.
5074 if (mUnhandledKeyManager.dispatch(mView, event)) {
Evan Rosky5e29c072017-06-02 17:31:22 -07005075 return FINISH_HANDLED;
5076 }
5077
Vadim Tryshev311a5b52017-01-05 18:54:11 -08005078 int groupNavigationDirection = 0;
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08005079
Evan Rosky516f9e62017-01-23 16:43:52 -08005080 if (event.getAction() == KeyEvent.ACTION_DOWN
5081 && event.getKeyCode() == KeyEvent.KEYCODE_TAB) {
5082 if (KeyEvent.metaStateHasModifiers(event.getMetaState(), KeyEvent.META_META_ON)) {
Vadim Tryshev311a5b52017-01-05 18:54:11 -08005083 groupNavigationDirection = View.FOCUS_FORWARD;
Evan Rosky516f9e62017-01-23 16:43:52 -08005084 } else if (KeyEvent.metaStateHasModifiers(event.getMetaState(),
5085 KeyEvent.META_META_ON | KeyEvent.META_SHIFT_ON)) {
Vadim Tryshev311a5b52017-01-05 18:54:11 -08005086 groupNavigationDirection = View.FOCUS_BACKWARD;
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08005087 }
5088 }
5089
Peeyush Agarwale631e322016-10-19 11:41:42 +01005090 // If a modifier is held, try to interpret the key as a shortcut.
Jeff Brownf9e989d2013-04-04 23:04:03 -07005091 if (event.getAction() == KeyEvent.ACTION_DOWN
Peeyush Agarwale631e322016-10-19 11:41:42 +01005092 && !KeyEvent.metaStateHasNoModifiers(event.getMetaState())
Jeff Brownf9e989d2013-04-04 23:04:03 -07005093 && event.getRepeatCount() == 0
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08005094 && !KeyEvent.isModifierKey(event.getKeyCode())
Vadim Tryshev311a5b52017-01-05 18:54:11 -08005095 && groupNavigationDirection == 0) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005096 if (mView.dispatchKeyShortcutEvent(event)) {
5097 return FINISH_HANDLED;
5098 }
Michael Wright17d28ca2013-10-31 17:47:45 -07005099 if (shouldDropInputEvent(q)) {
5100 return FINISH_NOT_HANDLED;
5101 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005102 }
5103
5104 // Apply the fallback event policy.
5105 if (mFallbackEventHandler.dispatchKeyEvent(event)) {
5106 return FINISH_HANDLED;
5107 }
Michael Wright17d28ca2013-10-31 17:47:45 -07005108 if (shouldDropInputEvent(q)) {
5109 return FINISH_NOT_HANDLED;
5110 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005111
5112 // Handle automatic focus changes.
5113 if (event.getAction() == KeyEvent.ACTION_DOWN) {
Vadim Tryshev311a5b52017-01-05 18:54:11 -08005114 if (groupNavigationDirection != 0) {
Vadim Tryshevb5ced222017-01-17 19:31:35 -08005115 if (performKeyboardGroupNavigation(groupNavigationDirection)) {
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08005116 return FINISH_HANDLED;
5117 }
5118 } else {
5119 if (performFocusNavigation(event)) {
5120 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005121 }
5122 }
5123 }
5124 return FORWARD;
Jeff Brown21bc5c92011-02-28 18:27:14 -08005125 }
5126
Jeff Brownf9e989d2013-04-04 23:04:03 -07005127 private int processPointerEvent(QueuedInputEvent q) {
5128 final MotionEvent event = (MotionEvent)q.mEvent;
5129
Vladislav Kaznacheev527905e2016-02-16 16:20:56 -08005130 mAttachInfo.mUnbufferedDispatchRequested = false;
Vladislav Kaznacheev527905e2016-02-16 16:20:56 -08005131 mAttachInfo.mHandlingPointerEvent = true;
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08005132 boolean handled = mView.dispatchPointerEvent(event);
Vladislav Kaznacheev527905e2016-02-16 16:20:56 -08005133 maybeUpdatePointerIcon(event);
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08005134 maybeUpdateTooltip(event);
Vladislav Kaznacheev527905e2016-02-16 16:20:56 -08005135 mAttachInfo.mHandlingPointerEvent = false;
5136 if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
5137 mUnbufferedInputDispatch = true;
5138 if (mConsumeBatchedInputScheduled) {
5139 scheduleConsumeBatchedInputImmediately();
5140 }
5141 }
5142 return handled ? FINISH_HANDLED : FORWARD;
5143 }
5144
5145 private void maybeUpdatePointerIcon(MotionEvent event) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005146 if (event.getPointerCount() == 1 && event.isFromSource(InputDevice.SOURCE_MOUSE)) {
Jun Mukai1db53972015-09-11 18:08:31 -07005147 if (event.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER
5148 || event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005149 // Other apps or the window manager may change the icon type outside of
5150 // this app, therefore the icon type has to be reset on enter/exit event.
5151 mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
Jun Mukai1db53972015-09-11 18:08:31 -07005152 }
5153
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005154 if (event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT) {
5155 if (!updatePointerIcon(event) &&
5156 event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005157 mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
Jun Mukai1db53972015-09-11 18:08:31 -07005158 }
5159 }
5160 }
Jeff Brown3915bb82010-11-05 15:02:16 -07005161 }
5162
Jeff Brownf9e989d2013-04-04 23:04:03 -07005163 private int processTrackballEvent(QueuedInputEvent q) {
5164 final MotionEvent event = (MotionEvent)q.mEvent;
5165
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08005166 if (event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) {
5167 if (!hasPointerCapture() || mView.dispatchCapturedPointerEvent(event)) {
5168 return FINISH_HANDLED;
5169 }
5170 }
5171
Jeff Brownf9e989d2013-04-04 23:04:03 -07005172 if (mView.dispatchTrackballEvent(event)) {
5173 return FINISH_HANDLED;
5174 }
5175 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005176 }
5177
Jeff Brownf9e989d2013-04-04 23:04:03 -07005178 private int processGenericMotionEvent(QueuedInputEvent q) {
5179 final MotionEvent event = (MotionEvent)q.mEvent;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07005180
Jeff Brownf9e989d2013-04-04 23:04:03 -07005181 // Deliver the event to the view.
5182 if (mView.dispatchGenericMotionEvent(event)) {
5183 return FINISH_HANDLED;
5184 }
5185 return FORWARD;
Jeff Brown3915bb82010-11-05 15:02:16 -07005186 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07005187 }
5188
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005189 private void resetPointerIcon(MotionEvent event) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005190 mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005191 updatePointerIcon(event);
5192 }
5193
5194 private boolean updatePointerIcon(MotionEvent event) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005195 final int pointerIndex = 0;
5196 final float x = event.getX(pointerIndex);
5197 final float y = event.getY(pointerIndex);
Andrii Kulian33c1bc52016-02-29 10:38:59 -08005198 if (mView == null) {
5199 // E.g. click outside a popup to dismiss it
5200 Slog.d(mTag, "updatePointerIcon called after view was removed");
5201 return false;
5202 }
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005203 if (x < 0 || x >= mView.getWidth() || y < 0 || y >= mView.getHeight()) {
Andrii Kulian33c1bc52016-02-29 10:38:59 -08005204 // E.g. when moving window divider with mouse
5205 Slog.d(mTag, "updatePointerIcon called with position out of bounds");
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005206 return false;
5207 }
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005208 final PointerIcon pointerIcon = mView.onResolvePointerIcon(event, pointerIndex);
5209 final int pointerType = (pointerIcon != null) ?
5210 pointerIcon.getType() : PointerIcon.TYPE_DEFAULT;
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005211
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005212 if (mPointerIconType != pointerType) {
5213 mPointerIconType = pointerType;
Vladislav Kaznacheeve40fb272017-01-03 16:45:42 -08005214 mCustomPointerIcon = null;
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005215 if (mPointerIconType != PointerIcon.TYPE_CUSTOM) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005216 InputManager.getInstance().setPointerIconType(pointerType);
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005217 return true;
5218 }
5219 }
Michael Wrightf9d9ce772016-05-13 17:44:16 +01005220 if (mPointerIconType == PointerIcon.TYPE_CUSTOM &&
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08005221 !pointerIcon.equals(mCustomPointerIcon)) {
5222 mCustomPointerIcon = pointerIcon;
5223 InputManager.getInstance().setCustomPointerIcon(mCustomPointerIcon);
5224 }
5225 return true;
5226 }
5227
Vladislav Kaznacheevf847ee32016-11-21 14:11:00 -08005228 private void maybeUpdateTooltip(MotionEvent event) {
5229 if (event.getPointerCount() != 1) {
5230 return;
5231 }
5232 final int action = event.getActionMasked();
5233 if (action != MotionEvent.ACTION_HOVER_ENTER
5234 && action != MotionEvent.ACTION_HOVER_MOVE
5235 && action != MotionEvent.ACTION_HOVER_EXIT) {
5236 return;
5237 }
5238 AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
5239 if (manager.isEnabled() && manager.isTouchExplorationEnabled()) {
5240 return;
5241 }
5242 if (mView == null) {
5243 Slog.d(mTag, "maybeUpdateTooltip called after view was removed");
5244 return;
5245 }
5246 mView.dispatchTooltipHoverEvent(event);
5247 }
5248
Jeff Brownf9e989d2013-04-04 23:04:03 -07005249 /**
Jeff Brown678a1252013-04-09 17:46:25 -07005250 * Performs synthesis of new input events from unhandled input events.
Jeff Brownf9e989d2013-04-04 23:04:03 -07005251 */
5252 final class SyntheticInputStage extends InputStage {
Jeff Brown678a1252013-04-09 17:46:25 -07005253 private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler();
5254 private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
5255 private final SyntheticTouchNavigationHandler mTouchNavigation =
5256 new SyntheticTouchNavigationHandler();
Michael Wright899d7052014-04-23 17:23:39 -07005257 private final SyntheticKeyboardHandler mKeyboard = new SyntheticKeyboardHandler();
Jeff Brownf9e989d2013-04-04 23:04:03 -07005258
5259 public SyntheticInputStage() {
5260 super(null);
Jeff Brown21bc5c92011-02-28 18:27:14 -08005261 }
5262
Jeff Brownf9e989d2013-04-04 23:04:03 -07005263 @Override
5264 protected int onProcess(QueuedInputEvent q) {
5265 q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED;
5266 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07005267 final MotionEvent event = (MotionEvent)q.mEvent;
5268 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07005269 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07005270 mTrackball.process(event);
5271 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005272 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07005273 mJoystick.process(event);
5274 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005275 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
5276 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07005277 mTouchNavigation.process(event);
5278 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005279 }
Michael Wright899d7052014-04-23 17:23:39 -07005280 } else if ((q.mFlags & QueuedInputEvent.FLAG_UNHANDLED) != 0) {
5281 mKeyboard.process((KeyEvent)q.mEvent);
5282 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005283 }
Michael Wright899d7052014-04-23 17:23:39 -07005284
Jeff Brownf9e989d2013-04-04 23:04:03 -07005285 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005286 }
5287
Jeff Brownf9e989d2013-04-04 23:04:03 -07005288 @Override
5289 protected void onDeliverToNext(QueuedInputEvent q) {
5290 if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) {
5291 // Cancel related synthetic events if any prior stage has handled the event.
5292 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07005293 final MotionEvent event = (MotionEvent)q.mEvent;
5294 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07005295 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005296 mTrackball.cancel();
Jeff Brownf9e989d2013-04-04 23:04:03 -07005297 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005298 mJoystick.cancel();
Jeff Brownf9e989d2013-04-04 23:04:03 -07005299 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
5300 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07005301 mTouchNavigation.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07005302 }
5303 }
5304 }
5305 super.onDeliverToNext(q);
5306 }
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005307
5308 @Override
5309 protected void onWindowFocusChanged(boolean hasWindowFocus) {
5310 if (!hasWindowFocus) {
5311 mJoystick.cancel();
5312 }
5313 }
5314
5315 @Override
5316 protected void onDetachedFromWindow() {
5317 mJoystick.cancel();
5318 }
Jeff Brown678a1252013-04-09 17:46:25 -07005319 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005320
Jeff Brown678a1252013-04-09 17:46:25 -07005321 /**
5322 * Creates dpad events from unhandled trackball movements.
5323 */
5324 final class SyntheticTrackballHandler {
5325 private final TrackballAxis mX = new TrackballAxis();
5326 private final TrackballAxis mY = new TrackballAxis();
5327 private long mLastTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005328
Jeff Brown678a1252013-04-09 17:46:25 -07005329 public void process(MotionEvent event) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005330 // Translate the trackball event into DPAD keys and try to deliver those.
Jeff Brownf9e989d2013-04-04 23:04:03 -07005331 long curTime = SystemClock.uptimeMillis();
Jeff Brown678a1252013-04-09 17:46:25 -07005332 if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005333 // It has been too long since the last movement,
5334 // so restart at the beginning.
Jeff Brown678a1252013-04-09 17:46:25 -07005335 mX.reset(0);
5336 mY.reset(0);
5337 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005338 }
5339
5340 final int action = event.getAction();
5341 final int metaState = event.getMetaState();
5342 switch (action) {
5343 case MotionEvent.ACTION_DOWN:
Jeff Brown678a1252013-04-09 17:46:25 -07005344 mX.reset(2);
5345 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07005346 enqueueInputEvent(new KeyEvent(curTime, curTime,
5347 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
5348 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
5349 InputDevice.SOURCE_KEYBOARD));
5350 break;
5351 case MotionEvent.ACTION_UP:
Jeff Brown678a1252013-04-09 17:46:25 -07005352 mX.reset(2);
5353 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07005354 enqueueInputEvent(new KeyEvent(curTime, curTime,
5355 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
5356 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
5357 InputDevice.SOURCE_KEYBOARD));
5358 break;
5359 }
5360
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005361 if (DEBUG_TRACKBALL) Log.v(mTag, "TB X=" + mX.position + " step="
Jeff Brown678a1252013-04-09 17:46:25 -07005362 + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07005363 + " move=" + event.getX()
Jeff Brown678a1252013-04-09 17:46:25 -07005364 + " / Y=" + mY.position + " step="
5365 + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07005366 + " move=" + event.getY());
Jeff Brown678a1252013-04-09 17:46:25 -07005367 final float xOff = mX.collect(event.getX(), event.getEventTime(), "X");
5368 final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y");
Jeff Brownf9e989d2013-04-04 23:04:03 -07005369
5370 // Generate DPAD events based on the trackball movement.
5371 // We pick the axis that has moved the most as the direction of
5372 // the DPAD. When we generate DPAD events for one axis, then the
5373 // other axis is reset -- we don't want to perform DPAD jumps due
5374 // to slight movements in the trackball when making major movements
5375 // along the other axis.
5376 int keycode = 0;
5377 int movement = 0;
5378 float accel = 1;
5379 if (xOff > yOff) {
Jeff Brown678a1252013-04-09 17:46:25 -07005380 movement = mX.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07005381 if (movement != 0) {
5382 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
5383 : KeyEvent.KEYCODE_DPAD_LEFT;
Jeff Brown678a1252013-04-09 17:46:25 -07005384 accel = mX.acceleration;
5385 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07005386 }
5387 } else if (yOff > 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07005388 movement = mY.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07005389 if (movement != 0) {
5390 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
5391 : KeyEvent.KEYCODE_DPAD_UP;
Jeff Brown678a1252013-04-09 17:46:25 -07005392 accel = mY.acceleration;
5393 mX.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07005394 }
5395 }
5396
5397 if (keycode != 0) {
5398 if (movement < 0) movement = -movement;
5399 int accelMovement = (int)(movement * accel);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005400 if (DEBUG_TRACKBALL) Log.v(mTag, "Move: movement=" + movement
Jeff Brownf9e989d2013-04-04 23:04:03 -07005401 + " accelMovement=" + accelMovement
5402 + " accel=" + accel);
5403 if (accelMovement > movement) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005404 if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
Jeff Brownf9e989d2013-04-04 23:04:03 -07005405 + keycode);
5406 movement--;
5407 int repeatCount = accelMovement - movement;
5408 enqueueInputEvent(new KeyEvent(curTime, curTime,
5409 KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
5410 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
5411 InputDevice.SOURCE_KEYBOARD));
5412 }
5413 while (movement > 0) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005414 if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
Jeff Brownf9e989d2013-04-04 23:04:03 -07005415 + keycode);
5416 movement--;
5417 curTime = SystemClock.uptimeMillis();
5418 enqueueInputEvent(new KeyEvent(curTime, curTime,
5419 KeyEvent.ACTION_DOWN, keycode, 0, metaState,
5420 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
5421 InputDevice.SOURCE_KEYBOARD));
5422 enqueueInputEvent(new KeyEvent(curTime, curTime,
5423 KeyEvent.ACTION_UP, keycode, 0, metaState,
5424 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
5425 InputDevice.SOURCE_KEYBOARD));
5426 }
Jeff Brown678a1252013-04-09 17:46:25 -07005427 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005428 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005429 }
5430
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005431 public void cancel() {
Jeff Brown678a1252013-04-09 17:46:25 -07005432 mLastTime = Integer.MIN_VALUE;
Jeff Brown3915bb82010-11-05 15:02:16 -07005433
Jeff Brownf9e989d2013-04-04 23:04:03 -07005434 // If we reach this, we consumed a trackball event.
5435 // Because we will not translate the trackball event into a key event,
5436 // touch mode will not exit, so we exit touch mode here.
5437 if (mView != null && mAdded) {
5438 ensureTouchMode(false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07005439 }
5440 }
Jeff Brown678a1252013-04-09 17:46:25 -07005441 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005442
Jeff Brown678a1252013-04-09 17:46:25 -07005443 /**
5444 * Maintains state information for a single trackball axis, generating
5445 * discrete (DPAD) movements based on raw trackball motion.
5446 */
5447 static final class TrackballAxis {
5448 /**
5449 * The maximum amount of acceleration we will apply.
5450 */
5451 static final float MAX_ACCELERATION = 20;
5452
5453 /**
5454 * The maximum amount of time (in milliseconds) between events in order
5455 * for us to consider the user to be doing fast trackball movements,
5456 * and thus apply an acceleration.
5457 */
5458 static final long FAST_MOVE_TIME = 150;
5459
5460 /**
5461 * Scaling factor to the time (in milliseconds) between events to how
5462 * much to multiple/divide the current acceleration. When movement
5463 * is < FAST_MOVE_TIME this multiplies the acceleration; when >
5464 * FAST_MOVE_TIME it divides it.
5465 */
5466 static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
5467
5468 static final float FIRST_MOVEMENT_THRESHOLD = 0.5f;
5469 static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f;
5470 static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f;
5471
5472 float position;
5473 float acceleration = 1;
5474 long lastMoveTime = 0;
5475 int step;
5476 int dir;
5477 int nonAccelMovement;
5478
5479 void reset(int _step) {
5480 position = 0;
5481 acceleration = 1;
5482 lastMoveTime = 0;
5483 step = _step;
5484 dir = 0;
Jeff Brown6f2fba42011-02-19 01:08:02 -08005485 }
5486
Jeff Brown678a1252013-04-09 17:46:25 -07005487 /**
5488 * Add trackball movement into the state. If the direction of movement
5489 * has been reversed, the state is reset before adding the
5490 * movement (so that you don't have to compensate for any previously
5491 * collected movement before see the result of the movement in the
5492 * new direction).
5493 *
5494 * @return Returns the absolute value of the amount of movement
5495 * collected so far.
5496 */
5497 float collect(float off, long time, String axis) {
5498 long normTime;
5499 if (off > 0) {
5500 normTime = (long)(off * FAST_MOVE_TIME);
5501 if (dir < 0) {
5502 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
5503 position = 0;
5504 step = 0;
5505 acceleration = 1;
5506 lastMoveTime = 0;
5507 }
5508 dir = 1;
5509 } else if (off < 0) {
5510 normTime = (long)((-off) * FAST_MOVE_TIME);
5511 if (dir > 0) {
5512 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
5513 position = 0;
5514 step = 0;
5515 acceleration = 1;
5516 lastMoveTime = 0;
5517 }
5518 dir = -1;
5519 } else {
5520 normTime = 0;
5521 }
5522
5523 // The number of milliseconds between each movement that is
5524 // considered "normal" and will not result in any acceleration
5525 // or deceleration, scaled by the offset we have here.
5526 if (normTime > 0) {
5527 long delta = time - lastMoveTime;
5528 lastMoveTime = time;
5529 float acc = acceleration;
5530 if (delta < normTime) {
5531 // The user is scrolling rapidly, so increase acceleration.
5532 float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
5533 if (scale > 1) acc *= scale;
5534 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
5535 + off + " normTime=" + normTime + " delta=" + delta
5536 + " scale=" + scale + " acc=" + acc);
5537 acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
5538 } else {
5539 // The user is scrolling slowly, so decrease acceleration.
5540 float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
5541 if (scale > 1) acc /= scale;
5542 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
5543 + off + " normTime=" + normTime + " delta=" + delta
5544 + " scale=" + scale + " acc=" + acc);
5545 acceleration = acc > 1 ? acc : 1;
5546 }
5547 }
5548 position += off;
5549 return Math.abs(position);
Jeff Brown6f2fba42011-02-19 01:08:02 -08005550 }
Jeff Browncb1404e2011-01-15 18:14:15 -08005551
Jeff Brown678a1252013-04-09 17:46:25 -07005552 /**
5553 * Generate the number of discrete movement events appropriate for
5554 * the currently collected trackball movement.
5555 *
5556 * @return Returns the number of discrete movements, either positive
5557 * or negative, or 0 if there is not enough trackball movement yet
5558 * for a discrete movement.
5559 */
5560 int generate() {
5561 int movement = 0;
5562 nonAccelMovement = 0;
5563 do {
5564 final int dir = position >= 0 ? 1 : -1;
5565 switch (step) {
5566 // If we are going to execute the first step, then we want
5567 // to do this as soon as possible instead of waiting for
5568 // a full movement, in order to make things look responsive.
5569 case 0:
5570 if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) {
5571 return movement;
5572 }
5573 movement += dir;
5574 nonAccelMovement += dir;
5575 step = 1;
5576 break;
5577 // If we have generated the first movement, then we need
5578 // to wait for the second complete trackball motion before
5579 // generating the second discrete movement.
5580 case 1:
5581 if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) {
5582 return movement;
5583 }
5584 movement += dir;
5585 nonAccelMovement += dir;
5586 position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir;
5587 step = 2;
5588 break;
5589 // After the first two, we generate discrete movements
5590 // consistently with the trackball, applying an acceleration
5591 // if the trackball is moving quickly. This is a simple
5592 // acceleration on top of what we already compute based
5593 // on how quickly the wheel is being turned, to apply
5594 // a longer increasing acceleration to continuous movement
5595 // in one direction.
5596 default:
5597 if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) {
5598 return movement;
5599 }
5600 movement += dir;
5601 position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD;
5602 float acc = acceleration;
5603 acc *= 1.1f;
5604 acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
5605 break;
5606 }
5607 } while (true);
5608 }
5609 }
5610
5611 /**
5612 * Creates dpad events from unhandled joystick movements.
5613 */
5614 final class SyntheticJoystickHandler extends Handler {
5615 private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
5616 private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
5617
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005618 private final JoystickAxesState mJoystickAxesState = new JoystickAxesState();
5619 private final SparseArray<KeyEvent> mDeviceKeyEvents = new SparseArray<>();
Jeff Brown678a1252013-04-09 17:46:25 -07005620
5621 public SyntheticJoystickHandler() {
5622 super(true);
5623 }
5624
5625 @Override
5626 public void handleMessage(Message msg) {
5627 switch (msg.what) {
5628 case MSG_ENQUEUE_X_AXIS_KEY_REPEAT:
5629 case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: {
Jeff Brown678a1252013-04-09 17:46:25 -07005630 if (mAttachInfo.mHasWindowFocus) {
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005631 KeyEvent oldEvent = (KeyEvent) msg.obj;
5632 KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent,
5633 SystemClock.uptimeMillis(), oldEvent.getRepeatCount() + 1);
Jeff Brown678a1252013-04-09 17:46:25 -07005634 enqueueInputEvent(e);
5635 Message m = obtainMessage(msg.what, e);
5636 m.setAsynchronous(true);
5637 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay());
5638 }
5639 } break;
5640 }
5641 }
5642
5643 public void process(MotionEvent event) {
Michael Wright9adca062014-03-19 11:51:26 -07005644 switch(event.getActionMasked()) {
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005645 case MotionEvent.ACTION_CANCEL:
5646 cancel();
5647 break;
5648 case MotionEvent.ACTION_MOVE:
5649 update(event);
5650 break;
5651 default:
5652 Log.w(mTag, "Unexpected action: " + event.getActionMasked());
Michael Wright9adca062014-03-19 11:51:26 -07005653 }
Jeff Brown678a1252013-04-09 17:46:25 -07005654 }
5655
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005656 private void cancel() {
Michael Wright9adca062014-03-19 11:51:26 -07005657 removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
5658 removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005659 for (int i = 0; i < mDeviceKeyEvents.size(); i++) {
5660 final KeyEvent keyEvent = mDeviceKeyEvents.valueAt(i);
5661 if (keyEvent != null) {
5662 enqueueInputEvent(KeyEvent.changeTimeRepeat(keyEvent,
5663 SystemClock.uptimeMillis(), 0));
5664 }
5665 }
5666 mDeviceKeyEvents.clear();
5667 mJoystickAxesState.resetState();
Jeff Brown678a1252013-04-09 17:46:25 -07005668 }
5669
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005670 private void update(MotionEvent event) {
5671 final int historySize = event.getHistorySize();
5672 for (int h = 0; h < historySize; h++) {
5673 final long time = event.getHistoricalEventTime(h);
5674 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X,
5675 event.getHistoricalAxisValue(MotionEvent.AXIS_X, 0, h));
5676 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y,
5677 event.getHistoricalAxisValue(MotionEvent.AXIS_Y, 0, h));
5678 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X,
5679 event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_X, 0, h));
5680 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y,
5681 event.getHistoricalAxisValue(MotionEvent.AXIS_HAT_Y, 0, h));
5682 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07005683 final long time = event.getEventTime();
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005684 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_X,
5685 event.getAxisValue(MotionEvent.AXIS_X));
5686 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_Y,
5687 event.getAxisValue(MotionEvent.AXIS_Y));
5688 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_X,
Jeff Brownf9e989d2013-04-04 23:04:03 -07005689 event.getAxisValue(MotionEvent.AXIS_HAT_X));
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005690 mJoystickAxesState.updateStateForAxis(event, time, MotionEvent.AXIS_HAT_Y,
Jeff Brownf9e989d2013-04-04 23:04:03 -07005691 event.getAxisValue(MotionEvent.AXIS_HAT_Y));
Jeff Browncb1404e2011-01-15 18:14:15 -08005692 }
5693
Siarhei Vishniakou461faf92017-06-26 11:24:25 -07005694 final class JoystickAxesState {
5695 // State machine: from neutral state (no button press) can go into
5696 // button STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state, emitting an ACTION_DOWN event.
5697 // From STATE_UP_OR_LEFT or STATE_DOWN_OR_RIGHT state can go into neutral state,
5698 // emitting an ACTION_UP event.
5699 private static final int STATE_UP_OR_LEFT = -1;
5700 private static final int STATE_NEUTRAL = 0;
5701 private static final int STATE_DOWN_OR_RIGHT = 1;
5702
5703 final int[] mAxisStatesHat = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_HAT_X, AXIS_HAT_Y}
5704 final int[] mAxisStatesStick = {STATE_NEUTRAL, STATE_NEUTRAL}; // {AXIS_X, AXIS_Y}
5705
5706 void resetState() {
5707 mAxisStatesHat[0] = STATE_NEUTRAL;
5708 mAxisStatesHat[1] = STATE_NEUTRAL;
5709 mAxisStatesStick[0] = STATE_NEUTRAL;
5710 mAxisStatesStick[1] = STATE_NEUTRAL;
5711 }
5712
5713 void updateStateForAxis(MotionEvent event, long time, int axis, float value) {
5714 // Emit KeyEvent if necessary
5715 // axis can be AXIS_X, AXIS_Y, AXIS_HAT_X, AXIS_HAT_Y
5716 final int axisStateIndex;
5717 final int repeatMessage;
5718 if (isXAxis(axis)) {
5719 axisStateIndex = 0;
5720 repeatMessage = MSG_ENQUEUE_X_AXIS_KEY_REPEAT;
5721 } else if (isYAxis(axis)) {
5722 axisStateIndex = 1;
5723 repeatMessage = MSG_ENQUEUE_Y_AXIS_KEY_REPEAT;
5724 } else {
5725 Log.e(mTag, "Unexpected axis " + axis + " in updateStateForAxis!");
5726 return;
5727 }
5728 final int newState = joystickAxisValueToState(value);
5729
5730 final int currentState;
5731 if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) {
5732 currentState = mAxisStatesStick[axisStateIndex];
5733 } else {
5734 currentState = mAxisStatesHat[axisStateIndex];
5735 }
5736
5737 if (currentState == newState) {
5738 return;
5739 }
5740
5741 final int metaState = event.getMetaState();
5742 final int deviceId = event.getDeviceId();
5743 final int source = event.getSource();
5744
5745 if (currentState == STATE_DOWN_OR_RIGHT || currentState == STATE_UP_OR_LEFT) {
5746 // send a button release event
5747 final int keyCode = joystickAxisAndStateToKeycode(axis, currentState);
5748 if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
5749 enqueueInputEvent(new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode,
5750 0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
5751 // remove the corresponding pending UP event if focus lost/view detached
5752 mDeviceKeyEvents.put(deviceId, null);
5753 }
5754 removeMessages(repeatMessage);
5755 }
5756
5757 if (newState == STATE_DOWN_OR_RIGHT || newState == STATE_UP_OR_LEFT) {
5758 // send a button down event
5759 final int keyCode = joystickAxisAndStateToKeycode(axis, newState);
5760 if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
5761 KeyEvent keyEvent = new KeyEvent(time, time, KeyEvent.ACTION_DOWN, keyCode,
5762 0, metaState, deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
5763 enqueueInputEvent(keyEvent);
5764 Message m = obtainMessage(repeatMessage, keyEvent);
5765 m.setAsynchronous(true);
5766 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
5767 // store the corresponding ACTION_UP event so that it can be sent
5768 // if focus is lost or root view is removed
5769 mDeviceKeyEvents.put(deviceId,
5770 new KeyEvent(time, time, KeyEvent.ACTION_UP, keyCode,
5771 0, metaState, deviceId, 0,
5772 KeyEvent.FLAG_FALLBACK | KeyEvent.FLAG_CANCELED,
5773 source));
5774 }
5775 }
5776 if (axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y) {
5777 mAxisStatesStick[axisStateIndex] = newState;
5778 } else {
5779 mAxisStatesHat[axisStateIndex] = newState;
5780 }
5781 }
5782
5783 private boolean isXAxis(int axis) {
5784 return axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_HAT_X;
5785 }
5786 private boolean isYAxis(int axis) {
5787 return axis == MotionEvent.AXIS_Y || axis == MotionEvent.AXIS_HAT_Y;
5788 }
5789
5790 private int joystickAxisAndStateToKeycode(int axis, int state) {
5791 if (isXAxis(axis) && state == STATE_UP_OR_LEFT) {
5792 return KeyEvent.KEYCODE_DPAD_LEFT;
5793 }
5794 if (isXAxis(axis) && state == STATE_DOWN_OR_RIGHT) {
5795 return KeyEvent.KEYCODE_DPAD_RIGHT;
5796 }
5797 if (isYAxis(axis) && state == STATE_UP_OR_LEFT) {
5798 return KeyEvent.KEYCODE_DPAD_UP;
5799 }
5800 if (isYAxis(axis) && state == STATE_DOWN_OR_RIGHT) {
5801 return KeyEvent.KEYCODE_DPAD_DOWN;
5802 }
5803 Log.e(mTag, "Unknown axis " + axis + " or direction " + state);
5804 return KeyEvent.KEYCODE_UNKNOWN; // should never happen
5805 }
5806
5807 private int joystickAxisValueToState(float value) {
5808 if (value >= 0.5f) {
5809 return STATE_DOWN_OR_RIGHT;
5810 } else if (value <= -0.5f) {
5811 return STATE_UP_OR_LEFT;
5812 } else {
5813 return STATE_NEUTRAL;
5814 }
Jeff Browncb1404e2011-01-15 18:14:15 -08005815 }
5816 }
Jeff Brown678a1252013-04-09 17:46:25 -07005817 }
Jeff Browncb1404e2011-01-15 18:14:15 -08005818
Jeff Brown678a1252013-04-09 17:46:25 -07005819 /**
5820 * Creates dpad events from unhandled touch navigation movements.
5821 */
5822 final class SyntheticTouchNavigationHandler extends Handler {
Jeff Brown4dac9012013-04-10 01:03:19 -07005823 private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler";
5824 private static final boolean LOCAL_DEBUG = false;
Jeff Brown678a1252013-04-09 17:46:25 -07005825
Jeff Brown4dac9012013-04-10 01:03:19 -07005826 // Assumed nominal width and height in millimeters of a touch navigation pad,
5827 // if no resolution information is available from the input system.
5828 private static final float DEFAULT_WIDTH_MILLIMETERS = 48;
5829 private static final float DEFAULT_HEIGHT_MILLIMETERS = 48;
Jeff Brown678a1252013-04-09 17:46:25 -07005830
Jeff Brown4dac9012013-04-10 01:03:19 -07005831 /* TODO: These constants should eventually be moved to ViewConfiguration. */
Jeff Brown678a1252013-04-09 17:46:25 -07005832
Jeff Brown4dac9012013-04-10 01:03:19 -07005833 // The nominal distance traveled to move by one unit.
5834 private static final int TICK_DISTANCE_MILLIMETERS = 12;
5835
5836 // Minimum and maximum fling velocity in ticks per second.
5837 // The minimum velocity should be set such that we perform enough ticks per
5838 // second that the fling appears to be fluid. For example, if we set the minimum
5839 // to 2 ticks per second, then there may be up to half a second delay between the next
5840 // to last and last ticks which is noticeably discrete and jerky. This value should
5841 // probably not be set to anything less than about 4.
5842 // If fling accuracy is a problem then consider tuning the tick distance instead.
5843 private static final float MIN_FLING_VELOCITY_TICKS_PER_SECOND = 6f;
5844 private static final float MAX_FLING_VELOCITY_TICKS_PER_SECOND = 20f;
5845
5846 // Fling velocity decay factor applied after each new key is emitted.
5847 // This parameter controls the deceleration and overall duration of the fling.
5848 // The fling stops automatically when its velocity drops below the minimum
5849 // fling velocity defined above.
5850 private static final float FLING_TICK_DECAY = 0.8f;
5851
5852 /* The input device that we are tracking. */
5853
5854 private int mCurrentDeviceId = -1;
5855 private int mCurrentSource;
5856 private boolean mCurrentDeviceSupported;
5857
5858 /* Configuration for the current input device. */
5859
Jeff Brown4dac9012013-04-10 01:03:19 -07005860 // The scaled tick distance. A movement of this amount should generally translate
5861 // into a single dpad event in a given direction.
5862 private float mConfigTickDistance;
5863
5864 // The minimum and maximum scaled fling velocity.
5865 private float mConfigMinFlingVelocity;
5866 private float mConfigMaxFlingVelocity;
5867
5868 /* Tracking state. */
5869
5870 // The velocity tracker for detecting flings.
5871 private VelocityTracker mVelocityTracker;
5872
5873 // The active pointer id, or -1 if none.
5874 private int mActivePointerId = -1;
5875
John Reck79d81e62013-11-05 13:26:57 -08005876 // Location where tracking started.
Jeff Brown4dac9012013-04-10 01:03:19 -07005877 private float mStartX;
5878 private float mStartY;
5879
5880 // Most recently observed position.
5881 private float mLastX;
5882 private float mLastY;
5883
5884 // Accumulated movement delta since the last direction key was sent.
Jeff Brown678a1252013-04-09 17:46:25 -07005885 private float mAccumulatedX;
5886 private float mAccumulatedY;
5887
Jeff Brown4dac9012013-04-10 01:03:19 -07005888 // Set to true if any movement was delivered to the app.
5889 // Implies that tap slop was exceeded.
5890 private boolean mConsumedMovement;
Jeff Brown678a1252013-04-09 17:46:25 -07005891
Jeff Brown4dac9012013-04-10 01:03:19 -07005892 // The most recently sent key down event.
5893 // The keycode remains set until the direction changes or a fling ends
5894 // so that repeated key events may be generated as required.
5895 private long mPendingKeyDownTime;
5896 private int mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
5897 private int mPendingKeyRepeatCount;
5898 private int mPendingKeyMetaState;
Jeff Brown678a1252013-04-09 17:46:25 -07005899
Jeff Brown4dac9012013-04-10 01:03:19 -07005900 // The current fling velocity while a fling is in progress.
5901 private boolean mFlinging;
5902 private float mFlingVelocity;
Jeff Brown678a1252013-04-09 17:46:25 -07005903
5904 public SyntheticTouchNavigationHandler() {
5905 super(true);
Jeff Brown678a1252013-04-09 17:46:25 -07005906 }
5907
5908 public void process(MotionEvent event) {
Jeff Brown4dac9012013-04-10 01:03:19 -07005909 // Update the current device information.
5910 final long time = event.getEventTime();
5911 final int deviceId = event.getDeviceId();
5912 final int source = event.getSource();
5913 if (mCurrentDeviceId != deviceId || mCurrentSource != source) {
5914 finishKeys(time);
5915 finishTracking(time);
5916 mCurrentDeviceId = deviceId;
5917 mCurrentSource = source;
5918 mCurrentDeviceSupported = false;
5919 InputDevice device = event.getDevice();
5920 if (device != null) {
5921 // In order to support an input device, we must know certain
5922 // characteristics about it, such as its size and resolution.
5923 InputDevice.MotionRange xRange = device.getMotionRange(MotionEvent.AXIS_X);
5924 InputDevice.MotionRange yRange = device.getMotionRange(MotionEvent.AXIS_Y);
5925 if (xRange != null && yRange != null) {
5926 mCurrentDeviceSupported = true;
Jeff Brown678a1252013-04-09 17:46:25 -07005927
Jeff Brown4dac9012013-04-10 01:03:19 -07005928 // Infer the resolution if it not actually known.
5929 float xRes = xRange.getResolution();
5930 if (xRes <= 0) {
5931 xRes = xRange.getRange() / DEFAULT_WIDTH_MILLIMETERS;
5932 }
5933 float yRes = yRange.getResolution();
5934 if (yRes <= 0) {
5935 yRes = yRange.getRange() / DEFAULT_HEIGHT_MILLIMETERS;
5936 }
5937 float nominalRes = (xRes + yRes) * 0.5f;
Jeff Brown678a1252013-04-09 17:46:25 -07005938
Jeff Brown4dac9012013-04-10 01:03:19 -07005939 // Precompute all of the configuration thresholds we will need.
Jeff Brown4dac9012013-04-10 01:03:19 -07005940 mConfigTickDistance = TICK_DISTANCE_MILLIMETERS * nominalRes;
5941 mConfigMinFlingVelocity =
5942 MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
5943 mConfigMaxFlingVelocity =
5944 MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
5945
5946 if (LOCAL_DEBUG) {
5947 Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId
5948 + " (" + Integer.toHexString(mCurrentSource) + "): "
Jeff Brown4dac9012013-04-10 01:03:19 -07005949 + ", mConfigTickDistance=" + mConfigTickDistance
5950 + ", mConfigMinFlingVelocity=" + mConfigMinFlingVelocity
5951 + ", mConfigMaxFlingVelocity=" + mConfigMaxFlingVelocity);
5952 }
5953 }
5954 }
Jeff Brown678a1252013-04-09 17:46:25 -07005955 }
Jeff Brown4dac9012013-04-10 01:03:19 -07005956 if (!mCurrentDeviceSupported) {
Jeff Brown678a1252013-04-09 17:46:25 -07005957 return;
5958 }
5959
Jeff Brown4dac9012013-04-10 01:03:19 -07005960 // Handle the event.
5961 final int action = event.getActionMasked();
5962 switch (action) {
Jeff Brown678a1252013-04-09 17:46:25 -07005963 case MotionEvent.ACTION_DOWN: {
Jeff Brown4dac9012013-04-10 01:03:19 -07005964 boolean caughtFling = mFlinging;
5965 finishKeys(time);
5966 finishTracking(time);
5967 mActivePointerId = event.getPointerId(0);
5968 mVelocityTracker = VelocityTracker.obtain();
5969 mVelocityTracker.addMovement(event);
Jeff Brown4dac9012013-04-10 01:03:19 -07005970 mStartX = event.getX();
5971 mStartY = event.getY();
5972 mLastX = mStartX;
5973 mLastY = mStartY;
Jeff Brown678a1252013-04-09 17:46:25 -07005974 mAccumulatedX = 0;
5975 mAccumulatedY = 0;
Jeff Brown4dac9012013-04-10 01:03:19 -07005976
5977 // If we caught a fling, then pretend that the tap slop has already
5978 // been exceeded to suppress taps whose only purpose is to stop the fling.
5979 mConsumedMovement = caughtFling;
Jeff Brown678a1252013-04-09 17:46:25 -07005980 break;
5981 }
5982
Jeff Brown4dac9012013-04-10 01:03:19 -07005983 case MotionEvent.ACTION_MOVE:
Jeff Brown678a1252013-04-09 17:46:25 -07005984 case MotionEvent.ACTION_UP: {
Jeff Brown4dac9012013-04-10 01:03:19 -07005985 if (mActivePointerId < 0) {
5986 break;
5987 }
5988 final int index = event.findPointerIndex(mActivePointerId);
5989 if (index < 0) {
5990 finishKeys(time);
5991 finishTracking(time);
5992 break;
5993 }
Jeff Brown678a1252013-04-09 17:46:25 -07005994
Jeff Brown4dac9012013-04-10 01:03:19 -07005995 mVelocityTracker.addMovement(event);
5996 final float x = event.getX(index);
5997 final float y = event.getY(index);
5998 mAccumulatedX += x - mLastX;
5999 mAccumulatedY += y - mLastY;
6000 mLastX = x;
6001 mLastY = y;
6002
6003 // Consume any accumulated movement so far.
6004 final int metaState = event.getMetaState();
6005 consumeAccumulatedMovement(time, metaState);
6006
6007 // Detect taps and flings.
6008 if (action == MotionEvent.ACTION_UP) {
Michael Wright88d7f792013-08-27 15:45:42 -07006009 if (mConsumedMovement && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
Jeff Brown4dac9012013-04-10 01:03:19 -07006010 // It might be a fling.
6011 mVelocityTracker.computeCurrentVelocity(1000, mConfigMaxFlingVelocity);
6012 final float vx = mVelocityTracker.getXVelocity(mActivePointerId);
6013 final float vy = mVelocityTracker.getYVelocity(mActivePointerId);
6014 if (!startFling(time, vx, vy)) {
6015 finishKeys(time);
Jeff Brown678a1252013-04-09 17:46:25 -07006016 }
6017 }
Jeff Brown4dac9012013-04-10 01:03:19 -07006018 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07006019 }
Jeff Brown4dac9012013-04-10 01:03:19 -07006020 break;
6021 }
6022
6023 case MotionEvent.ACTION_CANCEL: {
6024 finishKeys(time);
6025 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07006026 break;
6027 }
6028 }
Jeff Browncb1404e2011-01-15 18:14:15 -08006029 }
Jeff Brown4dac9012013-04-10 01:03:19 -07006030
6031 public void cancel(MotionEvent event) {
6032 if (mCurrentDeviceId == event.getDeviceId()
6033 && mCurrentSource == event.getSource()) {
6034 final long time = event.getEventTime();
6035 finishKeys(time);
6036 finishTracking(time);
6037 }
6038 }
6039
6040 private void finishKeys(long time) {
6041 cancelFling();
6042 sendKeyUp(time);
6043 }
6044
6045 private void finishTracking(long time) {
6046 if (mActivePointerId >= 0) {
6047 mActivePointerId = -1;
6048 mVelocityTracker.recycle();
6049 mVelocityTracker = null;
6050 }
6051 }
6052
6053 private void consumeAccumulatedMovement(long time, int metaState) {
6054 final float absX = Math.abs(mAccumulatedX);
6055 final float absY = Math.abs(mAccumulatedY);
6056 if (absX >= absY) {
6057 if (absX >= mConfigTickDistance) {
6058 mAccumulatedX = consumeAccumulatedMovement(time, metaState, mAccumulatedX,
6059 KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT);
6060 mAccumulatedY = 0;
6061 mConsumedMovement = true;
6062 }
6063 } else {
6064 if (absY >= mConfigTickDistance) {
6065 mAccumulatedY = consumeAccumulatedMovement(time, metaState, mAccumulatedY,
6066 KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN);
6067 mAccumulatedX = 0;
6068 mConsumedMovement = true;
6069 }
6070 }
6071 }
6072
6073 private float consumeAccumulatedMovement(long time, int metaState,
6074 float accumulator, int negativeKeyCode, int positiveKeyCode) {
6075 while (accumulator <= -mConfigTickDistance) {
6076 sendKeyDownOrRepeat(time, negativeKeyCode, metaState);
6077 accumulator += mConfigTickDistance;
6078 }
6079 while (accumulator >= mConfigTickDistance) {
6080 sendKeyDownOrRepeat(time, positiveKeyCode, metaState);
6081 accumulator -= mConfigTickDistance;
6082 }
6083 return accumulator;
6084 }
6085
6086 private void sendKeyDownOrRepeat(long time, int keyCode, int metaState) {
6087 if (mPendingKeyCode != keyCode) {
6088 sendKeyUp(time);
6089 mPendingKeyDownTime = time;
6090 mPendingKeyCode = keyCode;
6091 mPendingKeyRepeatCount = 0;
6092 } else {
6093 mPendingKeyRepeatCount += 1;
6094 }
6095 mPendingKeyMetaState = metaState;
6096
6097 // Note: Normally we would pass FLAG_LONG_PRESS when the repeat count is 1
6098 // but it doesn't quite make sense when simulating the events in this way.
6099 if (LOCAL_DEBUG) {
6100 Log.d(LOCAL_TAG, "Sending key down: keyCode=" + mPendingKeyCode
6101 + ", repeatCount=" + mPendingKeyRepeatCount
6102 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
6103 }
6104 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
6105 KeyEvent.ACTION_DOWN, mPendingKeyCode, mPendingKeyRepeatCount,
6106 mPendingKeyMetaState, mCurrentDeviceId,
6107 KeyEvent.FLAG_FALLBACK, mCurrentSource));
6108 }
6109
6110 private void sendKeyUp(long time) {
6111 if (mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
6112 if (LOCAL_DEBUG) {
6113 Log.d(LOCAL_TAG, "Sending key up: keyCode=" + mPendingKeyCode
6114 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
6115 }
6116 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
6117 KeyEvent.ACTION_UP, mPendingKeyCode, 0, mPendingKeyMetaState,
6118 mCurrentDeviceId, 0, KeyEvent.FLAG_FALLBACK,
6119 mCurrentSource));
6120 mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
6121 }
6122 }
6123
6124 private boolean startFling(long time, float vx, float vy) {
6125 if (LOCAL_DEBUG) {
6126 Log.d(LOCAL_TAG, "Considering fling: vx=" + vx + ", vy=" + vy
6127 + ", min=" + mConfigMinFlingVelocity);
6128 }
6129
6130 // Flings must be oriented in the same direction as the preceding movements.
6131 switch (mPendingKeyCode) {
6132 case KeyEvent.KEYCODE_DPAD_LEFT:
6133 if (-vx >= mConfigMinFlingVelocity
6134 && Math.abs(vy) < mConfigMinFlingVelocity) {
6135 mFlingVelocity = -vx;
6136 break;
6137 }
6138 return false;
6139
6140 case KeyEvent.KEYCODE_DPAD_RIGHT:
6141 if (vx >= mConfigMinFlingVelocity
6142 && Math.abs(vy) < mConfigMinFlingVelocity) {
6143 mFlingVelocity = vx;
6144 break;
6145 }
6146 return false;
6147
6148 case KeyEvent.KEYCODE_DPAD_UP:
6149 if (-vy >= mConfigMinFlingVelocity
6150 && Math.abs(vx) < mConfigMinFlingVelocity) {
6151 mFlingVelocity = -vy;
6152 break;
6153 }
6154 return false;
6155
6156 case KeyEvent.KEYCODE_DPAD_DOWN:
6157 if (vy >= mConfigMinFlingVelocity
6158 && Math.abs(vx) < mConfigMinFlingVelocity) {
6159 mFlingVelocity = vy;
6160 break;
6161 }
6162 return false;
6163 }
6164
6165 // Post the first fling event.
6166 mFlinging = postFling(time);
6167 return mFlinging;
6168 }
6169
6170 private boolean postFling(long time) {
6171 // The idea here is to estimate the time when the pointer would have
6172 // traveled one tick distance unit given the current fling velocity.
6173 // This effect creates continuity of motion.
6174 if (mFlingVelocity >= mConfigMinFlingVelocity) {
6175 long delay = (long)(mConfigTickDistance / mFlingVelocity * 1000);
6176 postAtTime(mFlingRunnable, time + delay);
6177 if (LOCAL_DEBUG) {
6178 Log.d(LOCAL_TAG, "Posted fling: velocity="
6179 + mFlingVelocity + ", delay=" + delay
6180 + ", keyCode=" + mPendingKeyCode);
6181 }
6182 return true;
6183 }
6184 return false;
6185 }
6186
6187 private void cancelFling() {
6188 if (mFlinging) {
6189 removeCallbacks(mFlingRunnable);
6190 mFlinging = false;
6191 }
6192 }
6193
6194 private final Runnable mFlingRunnable = new Runnable() {
6195 @Override
6196 public void run() {
6197 final long time = SystemClock.uptimeMillis();
6198 sendKeyDownOrRepeat(time, mPendingKeyCode, mPendingKeyMetaState);
6199 mFlingVelocity *= FLING_TICK_DECAY;
6200 if (!postFling(time)) {
6201 mFlinging = false;
6202 finishKeys(time);
6203 }
6204 }
6205 };
Jeff Browncb1404e2011-01-15 18:14:15 -08006206 }
6207
Michael Wright899d7052014-04-23 17:23:39 -07006208 final class SyntheticKeyboardHandler {
6209 public void process(KeyEvent event) {
6210 if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
6211 return;
6212 }
6213
6214 final KeyCharacterMap kcm = event.getKeyCharacterMap();
6215 final int keyCode = event.getKeyCode();
6216 final int metaState = event.getMetaState();
6217
6218 // Check for fallback actions specified by the key character map.
6219 KeyCharacterMap.FallbackAction fallbackAction =
6220 kcm.getFallbackAction(keyCode, metaState);
6221 if (fallbackAction != null) {
6222 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
6223 KeyEvent fallbackEvent = KeyEvent.obtain(
6224 event.getDownTime(), event.getEventTime(),
6225 event.getAction(), fallbackAction.keyCode,
6226 event.getRepeatCount(), fallbackAction.metaState,
6227 event.getDeviceId(), event.getScanCode(),
6228 flags, event.getSource(), null);
6229 fallbackAction.recycle();
6230 enqueueInputEvent(fallbackEvent);
6231 }
6232 }
6233 }
6234
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006235 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08006236 * Returns true if the key is used for keyboard navigation.
6237 * @param keyEvent The key event.
6238 * @return True if the key is used for keyboard navigation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006239 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08006240 private static boolean isNavigationKey(KeyEvent keyEvent) {
6241 switch (keyEvent.getKeyCode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006242 case KeyEvent.KEYCODE_DPAD_LEFT:
6243 case KeyEvent.KEYCODE_DPAD_RIGHT:
6244 case KeyEvent.KEYCODE_DPAD_UP:
6245 case KeyEvent.KEYCODE_DPAD_DOWN:
Jeff Brown4e6319b2010-12-13 10:36:51 -08006246 case KeyEvent.KEYCODE_DPAD_CENTER:
6247 case KeyEvent.KEYCODE_PAGE_UP:
6248 case KeyEvent.KEYCODE_PAGE_DOWN:
6249 case KeyEvent.KEYCODE_MOVE_HOME:
6250 case KeyEvent.KEYCODE_MOVE_END:
6251 case KeyEvent.KEYCODE_TAB:
6252 case KeyEvent.KEYCODE_SPACE:
6253 case KeyEvent.KEYCODE_ENTER:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006254 return true;
6255 }
6256 return false;
6257 }
6258
6259 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08006260 * Returns true if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006261 * @param keyEvent The key event.
Jeff Brown4e6319b2010-12-13 10:36:51 -08006262 * @return True if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006263 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08006264 private static boolean isTypingKey(KeyEvent keyEvent) {
6265 return keyEvent.getUnicodeChar() > 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006266 }
6267
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006268 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08006269 * 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 -08006270 * @param event The key event.
6271 * @return Whether this key event should be consumed (meaning the act of
6272 * leaving touch mode alone is considered the event).
6273 */
6274 private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08006275 // Only relevant in touch mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006276 if (!mAttachInfo.mInTouchMode) {
6277 return false;
6278 }
6279
Jeff Brown4e6319b2010-12-13 10:36:51 -08006280 // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
6281 final int action = event.getAction();
6282 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006283 return false;
6284 }
6285
Jeff Brown4e6319b2010-12-13 10:36:51 -08006286 // Don't leave touch mode if the IME told us not to.
6287 if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
6288 return false;
6289 }
6290
6291 // If the key can be used for keyboard navigation then leave touch mode
6292 // and select a focused view if needed (in ensureTouchMode).
6293 // When a new focused view is selected, we consume the navigation key because
6294 // navigation doesn't make much sense unless a view already has focus so
6295 // the key's purpose is to set focus.
6296 if (isNavigationKey(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006297 return ensureTouchMode(false);
6298 }
Jeff Brown4e6319b2010-12-13 10:36:51 -08006299
6300 // If the key can be used for typing then leave touch mode
6301 // and select a focused view if needed (in ensureTouchMode).
6302 // Always allow the view to process the typing key.
6303 if (isTypingKey(event)) {
6304 ensureTouchMode(false);
6305 return false;
6306 }
6307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006308 return false;
6309 }
6310
Christopher Tatea53146c2010-09-07 11:57:52 -07006311 /* drag/drop */
Mathew Inwoode5ad5982018-08-17 15:07:52 +01006312 @UnsupportedAppUsage
Christopher Tate407b4e92010-11-30 17:14:08 -08006313 void setLocalDragState(Object obj) {
6314 mLocalDragState = obj;
6315 }
6316
Christopher Tatea53146c2010-09-07 11:57:52 -07006317 private void handleDragEvent(DragEvent event) {
6318 // From the root, only drag start/end/location are dispatched. entered/exited
6319 // are determined and dispatched by the viewgroup hierarchy, who then report
6320 // that back here for ultimate reporting back to the framework.
6321 if (mView != null && mAdded) {
6322 final int what = event.mAction;
6323
Vladislav Kaznacheev7fe1f792016-07-14 17:15:02 -07006324 // Cache the drag description when the operation starts, then fill it in
6325 // on subsequent calls as a convenience
6326 if (what == DragEvent.ACTION_DRAG_STARTED) {
6327 mCurrentDragView = null; // Start the current-recipient tracking
6328 mDragDescription = event.mClipDescription;
6329 } else {
Vladislav Kaznacheevcd84cfa2016-07-26 15:17:49 -07006330 if (what == DragEvent.ACTION_DRAG_ENDED) {
6331 mDragDescription = null;
6332 }
Vladislav Kaznacheev7fe1f792016-07-14 17:15:02 -07006333 event.mClipDescription = mDragDescription;
6334 }
6335
Christopher Tatea53146c2010-09-07 11:57:52 -07006336 if (what == DragEvent.ACTION_DRAG_EXITED) {
6337 // A direct EXITED event means that the window manager knows we've just crossed
6338 // a window boundary, so the current drag target within this one must have
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006339 // just been exited. Send the EXITED notification to the current drag view, if any.
Vadim Tryshev45bee6b2016-09-19 11:00:37 -07006340 if (View.sCascadedDragDrop) {
Vadim Tryshevef128112016-09-16 14:05:53 -07006341 mView.dispatchDragEnterExitInPreN(event);
6342 }
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006343 setDragFocus(null, event);
Christopher Tatea53146c2010-09-07 11:57:52 -07006344 } else {
Christopher Tatea53146c2010-09-07 11:57:52 -07006345 // For events with a [screen] location, translate into window coordinates
6346 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
6347 mDragPoint.set(event.mX, event.mY);
6348 if (mTranslator != null) {
6349 mTranslator.translatePointInScreenToAppWindow(mDragPoint);
6350 }
6351
6352 if (mCurScrollY != 0) {
6353 mDragPoint.offset(0, mCurScrollY);
6354 }
6355
6356 event.mX = mDragPoint.x;
6357 event.mY = mDragPoint.y;
6358 }
6359
6360 // Remember who the current drag target is pre-dispatch
6361 final View prevDragView = mCurrentDragView;
6362
Vadim Tryshev69733172016-09-30 17:25:30 -07006363 if (what == DragEvent.ACTION_DROP && event.mClipData != null) {
6364 event.mClipData.prepareToEnterProcess();
Vladislav Kaznacheev854d3f22016-08-11 10:19:36 -07006365 }
6366
Christopher Tatea53146c2010-09-07 11:57:52 -07006367 // Now dispatch the drag/drop event
Chris Tated4533f12010-10-19 15:15:08 -07006368 boolean result = mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07006369
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006370 if (what == DragEvent.ACTION_DRAG_LOCATION && !event.mEventHandlerWasCalled) {
6371 // If the LOCATION event wasn't delivered to any handler, no view now has a drag
6372 // focus.
6373 setDragFocus(null, event);
6374 }
6375
Christopher Tatea53146c2010-09-07 11:57:52 -07006376 // If we changed apparent drag target, tell the OS about it
6377 if (prevDragView != mCurrentDragView) {
6378 try {
6379 if (prevDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07006380 mWindowSession.dragRecipientExited(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07006381 }
6382 if (mCurrentDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07006383 mWindowSession.dragRecipientEntered(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07006384 }
6385 } catch (RemoteException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006386 Slog.e(mTag, "Unable to note drag target change");
Christopher Tatea53146c2010-09-07 11:57:52 -07006387 }
Christopher Tatea53146c2010-09-07 11:57:52 -07006388 }
Chris Tated4533f12010-10-19 15:15:08 -07006389
Christopher Tate407b4e92010-11-30 17:14:08 -08006390 // Report the drop result when we're done
Chris Tated4533f12010-10-19 15:15:08 -07006391 if (what == DragEvent.ACTION_DROP) {
6392 try {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006393 Log.i(mTag, "Reporting drop result: " + result);
Jeff Brown98365d72012-08-19 20:30:52 -07006394 mWindowSession.reportDropResult(mWindow, result);
Chris Tated4533f12010-10-19 15:15:08 -07006395 } catch (RemoteException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006396 Log.e(mTag, "Unable to report drop result");
Chris Tated4533f12010-10-19 15:15:08 -07006397 }
6398 }
Christopher Tate407b4e92010-11-30 17:14:08 -08006399
Vladislav Kaznacheev82063912015-11-20 14:20:13 -08006400 // When the drag operation ends, reset drag-related state
Christopher Tate407b4e92010-11-30 17:14:08 -08006401 if (what == DragEvent.ACTION_DRAG_ENDED) {
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006402 mCurrentDragView = null;
Christopher Tate407b4e92010-11-30 17:14:08 -08006403 setLocalDragState(null);
Vladislav Kaznacheev82063912015-11-20 14:20:13 -08006404 mAttachInfo.mDragToken = null;
Vladislav Kaznacheev4f639742015-11-18 13:21:35 -08006405 if (mAttachInfo.mDragSurface != null) {
6406 mAttachInfo.mDragSurface.release();
6407 mAttachInfo.mDragSurface = null;
6408 }
Christopher Tate407b4e92010-11-30 17:14:08 -08006409 }
Christopher Tatea53146c2010-09-07 11:57:52 -07006410 }
6411 }
6412 event.recycle();
6413 }
6414
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006415 public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
6416 if (mSeq != args.seq) {
6417 // The sequence has changed, so we need to update our value and make
6418 // sure to do a traversal afterward so the window manager is given our
6419 // most recent data.
6420 mSeq = args.seq;
6421 mAttachInfo.mForceReportNewAttributes = true;
Igor Murashkina86ab6402013-08-30 12:58:36 -07006422 scheduleTraversals();
Joe Onorato14782f72011-01-25 19:53:17 -08006423 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006424 if (mView == null) return;
6425 if (args.localChanges != 0) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006426 mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006427 }
Chris Craikd36a81f2014-07-17 10:16:51 -07006428
6429 int visibility = args.globalVisibility&View.SYSTEM_UI_CLEARABLE_FLAGS;
6430 if (visibility != mAttachInfo.mGlobalSystemUiVisibility) {
6431 mAttachInfo.mGlobalSystemUiVisibility = visibility;
6432 mView.dispatchSystemUiVisibilityChanged(visibility);
Dianne Hackborncf675782012-05-10 15:07:24 -07006433 }
Joe Onorato664644d2011-01-23 17:53:23 -08006434 }
6435
Phil Weaver964c68e2016-10-27 16:22:05 -07006436 /**
6437 * Notify that the window title changed
6438 */
6439 public void onWindowTitleChanged() {
6440 mAttachInfo.mForceReportNewAttributes = true;
6441 }
6442
Craig Mautner9c795042014-10-28 19:59:59 -07006443 public void handleDispatchWindowShown() {
6444 mAttachInfo.mTreeObserver.dispatchOnWindowShown();
6445 }
6446
Clara Bayarrifcd7e802016-03-10 12:58:18 +00006447 public void handleRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
Clara Bayarri75e09792015-07-29 16:20:40 +01006448 Bundle data = new Bundle();
6449 ArrayList<KeyboardShortcutGroup> list = new ArrayList<>();
6450 if (mView != null) {
Clara Bayarrifcd7e802016-03-10 12:58:18 +00006451 mView.requestKeyboardShortcuts(list, deviceId);
Clara Bayarri75e09792015-07-29 16:20:40 +01006452 }
6453 data.putParcelableArrayList(WindowManager.PARCEL_KEY_SHORTCUTS_ARRAY, list);
6454 try {
6455 receiver.send(0, data);
6456 } catch (RemoteException e) {
6457 }
6458 }
6459
Mathew Inwoode5ad5982018-08-17 15:07:52 +01006460 @UnsupportedAppUsage
Christopher Tate2c095f32010-10-04 14:13:40 -07006461 public void getLastTouchPoint(Point outLocation) {
6462 outLocation.x = (int) mLastTouchPoint.x;
6463 outLocation.y = (int) mLastTouchPoint.y;
6464 }
6465
Vladislav Kaznacheevba761122016-01-22 12:09:45 -08006466 public int getLastTouchSource() {
6467 return mLastTouchSource;
6468 }
6469
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006470 public void setDragFocus(View newDragTarget, DragEvent event) {
Vadim Tryshev45bee6b2016-09-19 11:00:37 -07006471 if (mCurrentDragView != newDragTarget && !View.sCascadedDragDrop) {
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006472 // Send EXITED and ENTERED notifications to the old and new drag focus views.
6473
6474 final float tx = event.mX;
6475 final float ty = event.mY;
6476 final int action = event.mAction;
Vadim Trysheva61efa42016-09-28 15:15:52 -07006477 final ClipData td = event.mClipData;
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006478 // Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED.
6479 event.mX = 0;
6480 event.mY = 0;
Vadim Trysheva61efa42016-09-28 15:15:52 -07006481 event.mClipData = null;
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006482
6483 if (mCurrentDragView != null) {
6484 event.mAction = DragEvent.ACTION_DRAG_EXITED;
6485 mCurrentDragView.callDragEventHandler(event);
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006486 }
6487
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006488 if (newDragTarget != null) {
6489 event.mAction = DragEvent.ACTION_DRAG_ENTERED;
6490 newDragTarget.callDragEventHandler(event);
Vadim Tryshev1edc6daf2016-09-15 16:19:15 -07006491 }
6492
6493 event.mAction = action;
6494 event.mX = tx;
6495 event.mY = ty;
Vadim Trysheva61efa42016-09-28 15:15:52 -07006496 event.mClipData = td;
Christopher Tatea53146c2010-09-07 11:57:52 -07006497 }
Vadim Tryshevef128112016-09-16 14:05:53 -07006498
6499 mCurrentDragView = newDragTarget;
Christopher Tatea53146c2010-09-07 11:57:52 -07006500 }
6501
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006502 private AudioManager getAudioManager() {
6503 if (mView == null) {
6504 throw new IllegalStateException("getAudioManager called when there is no mView");
6505 }
6506 if (mAudioManager == null) {
6507 mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
6508 }
6509 return mAudioManager;
6510 }
6511
Dake Gud9dbd272018-03-13 11:38:42 -07006512 private @Nullable AutofillManager getAutofillManager() {
6513 if (mView instanceof ViewGroup) {
6514 ViewGroup decorView = (ViewGroup) mView;
6515 if (decorView.getChildCount() > 0) {
6516 // We cannot use decorView's Context for querying AutofillManager: DecorView's
6517 // context is based on Application Context, it would allocate a different
6518 // AutofillManager instance.
6519 return decorView.getChildAt(0).getContext()
6520 .getSystemService(AutofillManager.class);
6521 }
6522 }
6523 return null;
6524 }
6525
6526 private boolean isAutofillUiShowing() {
6527 AutofillManager afm = getAutofillManager();
6528 if (afm == null) {
6529 return false;
6530 }
6531 return afm.isAutofillUiShowing();
6532 }
6533
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006534 public AccessibilityInteractionController getAccessibilityInteractionController() {
6535 if (mView == null) {
6536 throw new IllegalStateException("getAccessibilityInteractionController"
6537 + " called when there is no mView");
6538 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07006539 if (mAccessibilityInteractionController == null) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006540 mAccessibilityInteractionController = new AccessibilityInteractionController(this);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006541 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07006542 return mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006543 }
6544
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07006545 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
6546 boolean insetsPending) throws RemoteException {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006547
6548 float appScale = mAttachInfo.mApplicationScale;
Mitsuru Oshima3d914922009-05-13 22:29:15 -07006549 boolean restore = false;
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006550 if (params != null && mTranslator != null) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07006551 restore = true;
6552 params.backup();
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006553 mTranslator.translateWindowLayout(params);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07006554 }
Robert Carrc6d5af52018-02-26 17:46:00 -08006555
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006556 if (params != null) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006557 if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
Bryce Leef858b572017-06-29 14:03:33 -07006558
Robert Carrc6d5af52018-02-26 17:46:00 -08006559 if (mOrigWindowType != params.type) {
6560 // For compatibility with old apps, don't crash here.
6561 if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
6562 Slog.w(mTag, "Window type can not be changed after "
6563 + "the window is added; ignoring change of " + mView);
6564 params.type = mOrigWindowType;
6565 }
6566 }
Dianne Hackborn180c4842011-09-13 12:39:25 -07006567 }
Robert Carrc6d5af52018-02-26 17:46:00 -08006568
chaviwbe43ac82018-04-04 15:14:49 -07006569 long frameNumber = -1;
6570 if (mSurface.isValid()) {
6571 frameNumber = mSurface.getNextFrameNumber();
6572 }
6573
6574 int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params,
Dianne Hackborn189ee182010-12-02 21:48:53 -08006575 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
chaviwbe43ac82018-04-04 15:14:49 -07006576 (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
6577 insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006578 mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
Adrian Roos5c6b6222017-11-07 17:36:10 +01006579 mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout,
Andrii Kulian44607962017-03-16 11:06:24 -07006580 mPendingMergedConfiguration, mSurface);
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08006581
6582 mPendingAlwaysConsumeNavBar =
6583 (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR) != 0;
6584
Mitsuru Oshima3d914922009-05-13 22:29:15 -07006585 if (restore) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07006586 params.restore();
Mitsuru Oshima3d914922009-05-13 22:29:15 -07006587 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006588
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006589 if (mTranslator != null) {
6590 mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006591 mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006592 mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
6593 mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
Adrian Roosfa104232014-06-20 16:10:14 -07006594 mTranslator.translateRectInScreenToAppWindow(mPendingStableInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07006595 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07006596 return relayoutResult;
6597 }
Romain Guy8506ab42009-06-11 17:35:47 -07006598
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07006599 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006600 * {@inheritDoc}
6601 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07006602 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006603 public void playSoundEffect(int effectId) {
6604 checkThread();
6605
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07006606 try {
6607 final AudioManager audioManager = getAudioManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006608
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07006609 switch (effectId) {
6610 case SoundEffectConstants.CLICK:
6611 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
6612 return;
6613 case SoundEffectConstants.NAVIGATION_DOWN:
6614 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
6615 return;
6616 case SoundEffectConstants.NAVIGATION_LEFT:
6617 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
6618 return;
6619 case SoundEffectConstants.NAVIGATION_RIGHT:
6620 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
6621 return;
6622 case SoundEffectConstants.NAVIGATION_UP:
6623 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
6624 return;
6625 default:
6626 throw new IllegalArgumentException("unknown effect id " + effectId +
6627 " not defined in " + SoundEffectConstants.class.getCanonicalName());
6628 }
6629 } catch (IllegalStateException e) {
6630 // Exception thrown by getAudioManager() when mView is null
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006631 Log.e(mTag, "FATAL EXCEPTION when attempting to play sound effect: " + e);
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07006632 e.printStackTrace();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006633 }
6634 }
6635
6636 /**
6637 * {@inheritDoc}
6638 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07006639 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006640 public boolean performHapticFeedback(int effectId, boolean always) {
6641 try {
Jeff Brown98365d72012-08-19 20:30:52 -07006642 return mWindowSession.performHapticFeedback(mWindow, effectId, always);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006643 } catch (RemoteException e) {
6644 return false;
6645 }
6646 }
6647
6648 /**
6649 * {@inheritDoc}
6650 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07006651 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006652 public View focusSearch(View focused, int direction) {
6653 checkThread();
6654 if (!(mView instanceof ViewGroup)) {
6655 return null;
6656 }
6657 return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
6658 }
6659
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08006660 /**
6661 * {@inheritDoc}
6662 */
6663 @Override
Evan Rosky57223312017-02-08 14:42:45 -08006664 public View keyboardNavigationClusterSearch(View currentCluster,
6665 @FocusDirection int direction) {
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08006666 checkThread();
Vadim Tryshevb5ced222017-01-17 19:31:35 -08006667 return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
6668 mView, currentCluster, direction);
Vadim Tryshev01b0c9e2016-11-21 15:25:01 -08006669 }
6670
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006671 public void debug() {
6672 mView.debug();
6673 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006674
Jeff Brown5182c782013-10-15 20:31:52 -07006675 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
6676 String innerPrefix = prefix + " ";
6677 writer.print(prefix); writer.println("ViewRoot:");
6678 writer.print(innerPrefix); writer.print("mAdded="); writer.print(mAdded);
6679 writer.print(" mRemoved="); writer.println(mRemoved);
6680 writer.print(innerPrefix); writer.print("mConsumeBatchedInputScheduled=");
6681 writer.println(mConsumeBatchedInputScheduled);
Michael Wright9d744c72014-02-18 21:27:42 -08006682 writer.print(innerPrefix); writer.print("mConsumeBatchedInputImmediatelyScheduled=");
6683 writer.println(mConsumeBatchedInputImmediatelyScheduled);
Jeff Brown5182c782013-10-15 20:31:52 -07006684 writer.print(innerPrefix); writer.print("mPendingInputEventCount=");
6685 writer.println(mPendingInputEventCount);
6686 writer.print(innerPrefix); writer.print("mProcessInputEventsScheduled=");
6687 writer.println(mProcessInputEventsScheduled);
6688 writer.print(innerPrefix); writer.print("mTraversalScheduled=");
6689 writer.print(mTraversalScheduled);
Daniel Koulomzin087ae472015-12-16 17:52:25 -05006690 writer.print(innerPrefix); writer.print("mIsAmbientMode=");
6691 writer.print(mIsAmbientMode);
Jeff Brown5182c782013-10-15 20:31:52 -07006692 if (mTraversalScheduled) {
6693 writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
6694 } else {
6695 writer.println();
6696 }
6697 mFirstInputStage.dump(innerPrefix, writer);
6698
6699 mChoreographer.dump(prefix, writer);
6700
6701 writer.print(prefix); writer.println("View Hierarchy:");
6702 dumpViewHierarchy(innerPrefix, writer, mView);
6703 }
6704
6705 private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) {
6706 writer.print(prefix);
6707 if (view == null) {
6708 writer.println("null");
6709 return;
6710 }
6711 writer.println(view.toString());
6712 if (!(view instanceof ViewGroup)) {
6713 return;
6714 }
6715 ViewGroup grp = (ViewGroup)view;
6716 final int N = grp.getChildCount();
6717 if (N <= 0) {
6718 return;
6719 }
6720 prefix = prefix + " ";
6721 for (int i=0; i<N; i++) {
6722 dumpViewHierarchy(prefix, writer, grp.getChildAt(i));
6723 }
6724 }
6725
Romain Guy211370f2012-02-01 16:10:55 -08006726 public void dumpGfxInfo(int[] info) {
Romain Guy54ab3472012-06-14 12:52:53 -07006727 info[0] = info[1] = 0;
Romain Guy65b345f2011-07-27 18:51:50 -07006728 if (mView != null) {
6729 getGfxInfo(mView, info);
Romain Guy65b345f2011-07-27 18:51:50 -07006730 }
6731 }
6732
Romain Guya998dff2012-03-23 18:58:36 -07006733 private static void getGfxInfo(View view, int[] info) {
Chris Craik64a12e12014-03-28 18:12:12 -07006734 RenderNode renderNode = view.mRenderNode;
Romain Guy65b345f2011-07-27 18:51:50 -07006735 info[0]++;
Chris Craik64a12e12014-03-28 18:12:12 -07006736 if (renderNode != null) {
John Reckfe5e7b72014-05-23 17:42:28 -07006737 info[1] += renderNode.getDebugSize();
Romain Guy65b345f2011-07-27 18:51:50 -07006738 }
6739
6740 if (view instanceof ViewGroup) {
6741 ViewGroup group = (ViewGroup) view;
6742
6743 int count = group.getChildCount();
6744 for (int i = 0; i < count; i++) {
6745 getGfxInfo(group.getChildAt(i), info);
6746 }
6747 }
6748 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006749
Craig Mautner8f303ad2013-06-14 11:32:22 -07006750 /**
6751 * @param immediate True, do now if not in traversal. False, put on queue and do later.
6752 * @return True, request has been queued. False, request has been completed.
6753 */
6754 boolean die(boolean immediate) {
Craig Mautnerdf2390a2012-08-29 20:59:22 -07006755 // Make sure we do execute immediately if we are in the middle of a traversal or the damage
6756 // done by dispatchDetachedFromWindow will cause havoc on return.
6757 if (immediate && !mIsInTraversal) {
Dianne Hackborn94d69142009-09-28 22:14:42 -07006758 doDie();
Craig Mautner8f303ad2013-06-14 11:32:22 -07006759 return false;
Dianne Hackborn94d69142009-09-28 22:14:42 -07006760 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07006761
6762 if (!mIsDrawing) {
6763 destroyHardwareRenderer();
6764 } else {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006765 Log.e(mTag, "Attempting to destroy the window while drawing!\n" +
Craig Mautner8f303ad2013-06-14 11:32:22 -07006766 " window=" + this + ", title=" + mWindowAttributes.getTitle());
6767 }
6768 mHandler.sendEmptyMessage(MSG_DIE);
6769 return true;
Dianne Hackborn94d69142009-09-28 22:14:42 -07006770 }
6771
6772 void doDie() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006773 checkThread();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006774 if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006775 synchronized (this) {
Craig Mautner8f303ad2013-06-14 11:32:22 -07006776 if (mRemoved) {
6777 return;
6778 }
6779 mRemoved = true;
Romain Guy16260e72011-09-01 14:26:11 -07006780 if (mAdded) {
Romain Guy16260e72011-09-01 14:26:11 -07006781 dispatchDetachedFromWindow();
6782 }
6783
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006784 if (mAdded && !mFirst) {
Romain Guy29d89972010-09-22 16:10:57 -07006785 destroyHardwareRenderer();
6786
Romain Guyedbca122012-04-04 18:25:53 -07006787 if (mView != null) {
6788 int viewVisibility = mView.getVisibility();
6789 boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
6790 if (mWindowAttributesChanged || viewVisibilityChanged) {
6791 // If layout params have been changed, first give them
6792 // to the window manager to make sure it has the correct
6793 // animation info.
6794 try {
6795 if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
Jeff Brown98365d72012-08-19 20:30:52 -07006796 & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
6797 mWindowSession.finishDrawing(mWindow);
Romain Guyedbca122012-04-04 18:25:53 -07006798 }
6799 } catch (RemoteException e) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006800 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006801 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07006802
Romain Guyedbca122012-04-04 18:25:53 -07006803 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006804 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006805 }
Romain Guyedbca122012-04-04 18:25:53 -07006806
6807 mAdded = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006808 }
Craig Mautner05eb7302013-06-03 17:24:21 -07006809 WindowManagerGlobal.getInstance().doRemoveView(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006810 }
6811
Dianne Hackborn5fd21692011-06-07 14:09:47 -07006812 public void requestUpdateConfiguration(Configuration config) {
Jeff Browna175a5b2012-02-15 19:18:31 -08006813 Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
6814 mHandler.sendMessage(msg);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07006815 }
6816
Dianne Hackborna53de062012-05-08 18:53:51 -07006817 public void loadSystemProperties() {
Romain Guy5bb3c732012-11-29 17:52:58 -08006818 mHandler.post(new Runnable() {
6819 @Override
6820 public void run() {
6821 // Profiling
6822 mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false);
6823 profileRendering(mAttachInfo.mHasWindowFocus);
6824
6825 // Hardware rendering
Stan Iliev45faba52016-06-28 13:33:15 -04006826 if (mAttachInfo.mThreadedRenderer != null) {
6827 if (mAttachInfo.mThreadedRenderer.loadSystemProperties()) {
Romain Guy5bb3c732012-11-29 17:52:58 -08006828 invalidate();
6829 }
6830 }
6831
6832 // Layout debugging
Kiyoung Kim89052d92018-12-20 18:26:10 +09006833 boolean layout = DisplayProperties.debug_layout().orElse(false);
Romain Guy5bb3c732012-11-29 17:52:58 -08006834 if (layout != mAttachInfo.mDebugLayout) {
6835 mAttachInfo.mDebugLayout = layout;
6836 if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
6837 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
6838 }
6839 }
Dianne Hackborna53de062012-05-08 18:53:51 -07006840 }
Romain Guy5bb3c732012-11-29 17:52:58 -08006841 });
Dianne Hackborna53de062012-05-08 18:53:51 -07006842 }
6843
Romain Guy29d89972010-09-22 16:10:57 -07006844 private void destroyHardwareRenderer() {
Stan Iliev45faba52016-06-28 13:33:15 -04006845 ThreadedRenderer hardwareRenderer = mAttachInfo.mThreadedRenderer;
Romain Guya998dff2012-03-23 18:58:36 -07006846
6847 if (hardwareRenderer != null) {
6848 if (mView != null) {
6849 hardwareRenderer.destroyHardwareResources(mView);
6850 }
John Reckf47a5942014-06-30 16:20:04 -07006851 hardwareRenderer.destroy();
Romain Guya998dff2012-03-23 18:58:36 -07006852 hardwareRenderer.setRequested(false);
6853
Stan Iliev45faba52016-06-28 13:33:15 -04006854 mAttachInfo.mThreadedRenderer = null;
Chris Craikd36a81f2014-07-17 10:16:51 -07006855 mAttachInfo.mHardwareAccelerated = false;
Romain Guy29d89972010-09-22 16:10:57 -07006856 }
6857 }
6858
Mathew Inwoode5ad5982018-08-17 15:07:52 +01006859 @UnsupportedAppUsage
Andrii Kulian44607962017-03-16 11:06:24 -07006860 private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Filip Gruszczynski2217f612015-05-26 11:32:08 -07006861 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
Andrii Kulian44607962017-03-16 11:06:24 -07006862 MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
Adrian Roos5c6b6222017-11-07 17:36:10 +01006863 boolean alwaysConsumeNavBar, int displayId,
6864 DisplayCutout.ParcelableWrapper displayCutout) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006865 if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
Svetoslav Ganov758143e2012-08-06 16:40:27 -07006866 + " contentInsets=" + contentInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006867 + " visibleInsets=" + visibleInsets.toShortString()
Chong Zhangd153c4f2015-11-06 20:26:40 -08006868 + " reportDraw=" + reportDraw
6869 + " backDropFrame=" + backDropFrame);
Chong Zhangdcee1de2015-10-06 10:26:00 -07006870
6871 // Tell all listeners that we are resizing the window so that the chrome can get
6872 // updated as fast as possible on a separate thread,
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09006873 if (mDragResizing && mUseMTRenderer) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08006874 boolean fullscreen = frame.equals(backDropFrame);
Chong Zhangdcee1de2015-10-06 10:26:00 -07006875 synchronized (mWindowCallbacks) {
6876 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08006877 mWindowCallbacks.get(i).onWindowSizeIsChanging(backDropFrame, fullscreen,
6878 visibleInsets, stableInsets);
Chong Zhangdcee1de2015-10-06 10:26:00 -07006879 }
6880 }
6881 }
6882
Svetoslav Ganov758143e2012-08-06 16:40:27 -07006883 Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006884 if (mTranslator != null) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07006885 mTranslator.translateRectInScreenToAppWindow(frame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006886 mTranslator.translateRectInScreenToAppWindow(overscanInsets);
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07006887 mTranslator.translateRectInScreenToAppWindow(contentInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07006888 mTranslator.translateRectInScreenToAppWindow(visibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07006889 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07006890 SomeArgs args = SomeArgs.obtain();
6891 final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
6892 args.arg1 = sameProcessCall ? new Rect(frame) : frame;
6893 args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets;
6894 args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
Andrii Kulian44607962017-03-16 11:06:24 -07006895 args.arg4 = sameProcessCall && mergedConfiguration != null
Wale Ogunwalecdc8ada2017-03-30 13:55:36 -07006896 ? new MergedConfiguration(mergedConfiguration) : mergedConfiguration;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006897 args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
Adrian Roosfa104232014-06-20 16:10:14 -07006898 args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
Filip Gruszczynski2217f612015-05-26 11:32:08 -07006899 args.arg7 = sameProcessCall ? new Rect(outsets) : outsets;
Jorim Jaggia7262a82015-11-03 15:15:40 +01006900 args.arg8 = sameProcessCall ? new Rect(backDropFrame) : backDropFrame;
Adrian Roos5c6b6222017-11-07 17:36:10 +01006901 args.arg9 = displayCutout.get(); // DisplayCutout is immutable.
Jorim Jaggia4a58ef2016-01-27 02:10:08 -08006902 args.argi1 = forceLayout ? 1 : 0;
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08006903 args.argi2 = alwaysConsumeNavBar ? 1 : 0;
Andrii Kulianb047b8b2017-02-08 18:38:26 -08006904 args.argi3 = displayId;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07006905 msg.obj = args;
Jeff Browna175a5b2012-02-15 19:18:31 -08006906 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006907 }
Chet Haase1f4786b2011-11-02 10:51:52 -07006908
Craig Mautner5702d4d2012-06-30 14:10:16 -07006909 public void dispatchMoved(int newX, int newY) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006910 if (DEBUG_LAYOUT) Log.v(mTag, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
Craig Mautner5702d4d2012-06-30 14:10:16 -07006911 if (mTranslator != null) {
6912 PointF point = new PointF(newX, newY);
6913 mTranslator.translatePointInScreenToAppWindow(point);
6914 newX = (int) (point.x + 0.5);
6915 newY = (int) (point.y + 0.5);
6916 }
6917 Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY);
6918 mHandler.sendMessage(msg);
6919 }
6920
Jeff Brown4952dfd2011-11-30 19:23:22 -08006921 /**
6922 * Represents a pending input event that is waiting in a queue.
6923 *
6924 * Input events are processed in serial order by the timestamp specified by
Romain Guy211370f2012-02-01 16:10:55 -08006925 * {@link InputEvent#getEventTimeNano()}. In general, the input dispatcher delivers
Jeff Brown4952dfd2011-11-30 19:23:22 -08006926 * one input event to the application at a time and waits for the application
6927 * to finish handling it before delivering the next one.
6928 *
6929 * However, because the application or IME can synthesize and inject multiple
6930 * key events at a time without going through the input dispatcher, we end up
6931 * needing a queue on the application's side.
6932 */
6933 private static final class QueuedInputEvent {
Jeff Brownf9e989d2013-04-04 23:04:03 -07006934 public static final int FLAG_DELIVER_POST_IME = 1 << 0;
6935 public static final int FLAG_DEFERRED = 1 << 1;
6936 public static final int FLAG_FINISHED = 1 << 2;
6937 public static final int FLAG_FINISHED_HANDLED = 1 << 3;
6938 public static final int FLAG_RESYNTHESIZED = 1 << 4;
Michael Wright899d7052014-04-23 17:23:39 -07006939 public static final int FLAG_UNHANDLED = 1 << 5;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006940
6941 public QueuedInputEvent mNext;
6942
6943 public InputEvent mEvent;
Jeff Brown32cbc38552011-12-01 14:01:49 -08006944 public InputEventReceiver mReceiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006945 public int mFlags;
Jeff Brownf9e989d2013-04-04 23:04:03 -07006946
6947 public boolean shouldSkipIme() {
6948 if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
6949 return true;
6950 }
6951 return mEvent instanceof MotionEvent
Prashant Malanifecbc672016-07-22 15:38:05 -07006952 && (mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
6953 || mEvent.isFromSource(InputDevice.SOURCE_ROTARY_ENCODER));
Jeff Brownf9e989d2013-04-04 23:04:03 -07006954 }
Michael Wright899d7052014-04-23 17:23:39 -07006955
6956 public boolean shouldSendToSynthesizer() {
6957 if ((mFlags & FLAG_UNHANDLED) != 0) {
6958 return true;
6959 }
6960
6961 return false;
6962 }
Michael Wright06a79252014-05-05 17:45:29 -07006963
6964 @Override
6965 public String toString() {
6966 StringBuilder sb = new StringBuilder("QueuedInputEvent{flags=");
6967 boolean hasPrevious = false;
6968 hasPrevious = flagToString("DELIVER_POST_IME", FLAG_DELIVER_POST_IME, hasPrevious, sb);
6969 hasPrevious = flagToString("DEFERRED", FLAG_DEFERRED, hasPrevious, sb);
6970 hasPrevious = flagToString("FINISHED", FLAG_FINISHED, hasPrevious, sb);
6971 hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb);
6972 hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb);
6973 hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb);
6974 if (!hasPrevious) {
6975 sb.append("0");
6976 }
6977 sb.append(", hasNextQueuedEvent=" + (mEvent != null ? "true" : "false"));
6978 sb.append(", hasInputEventReceiver=" + (mReceiver != null ? "true" : "false"));
6979 sb.append(", mEvent=" + mEvent + "}");
6980 return sb.toString();
6981 }
6982
6983 private boolean flagToString(String name, int flag,
6984 boolean hasPrevious, StringBuilder sb) {
6985 if ((mFlags & flag) != 0) {
6986 if (hasPrevious) {
6987 sb.append("|");
6988 }
6989 sb.append(name);
6990 return true;
6991 }
6992 return hasPrevious;
6993 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08006994 }
6995
6996 private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
Jeff Brown32cbc38552011-12-01 14:01:49 -08006997 InputEventReceiver receiver, int flags) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08006998 QueuedInputEvent q = mQueuedInputEventPool;
6999 if (q != null) {
7000 mQueuedInputEventPoolSize -= 1;
7001 mQueuedInputEventPool = q.mNext;
7002 q.mNext = null;
7003 } else {
7004 q = new QueuedInputEvent();
Jeff Brown46b9ac02010-04-22 18:58:52 -07007005 }
7006
Jeff Brown4952dfd2011-11-30 19:23:22 -08007007 q.mEvent = event;
Jeff Brown32cbc38552011-12-01 14:01:49 -08007008 q.mReceiver = receiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08007009 q.mFlags = flags;
Jeff Brown4952dfd2011-11-30 19:23:22 -08007010 return q;
7011 }
7012
7013 private void recycleQueuedInputEvent(QueuedInputEvent q) {
7014 q.mEvent = null;
Jeff Brown32cbc38552011-12-01 14:01:49 -08007015 q.mReceiver = null;
Jeff Brown4952dfd2011-11-30 19:23:22 -08007016
7017 if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
7018 mQueuedInputEventPoolSize += 1;
7019 q.mNext = mQueuedInputEventPool;
7020 mQueuedInputEventPool = q;
7021 }
7022 }
7023
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007024 @UnsupportedAppUsage
Jeff Brownf9261d22012-02-03 13:49:15 -08007025 void enqueueInputEvent(InputEvent event) {
7026 enqueueInputEvent(event, null, 0, false);
7027 }
7028
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007029 @UnsupportedAppUsage
Jeff Brown4952dfd2011-11-30 19:23:22 -08007030 void enqueueInputEvent(InputEvent event,
Jeff Brownf9261d22012-02-03 13:49:15 -08007031 InputEventReceiver receiver, int flags, boolean processImmediately) {
Michael Wright5bd69e62015-05-14 14:48:08 +01007032 adjustInputEventForCompatibility(event);
Jeff Brown32cbc38552011-12-01 14:01:49 -08007033 QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
Jeff Brown4952dfd2011-11-30 19:23:22 -08007034
Jeff Brown4952dfd2011-11-30 19:23:22 -08007035 // Always enqueue the input event in order, regardless of its time stamp.
7036 // We do this because the application or the IME may inject key events
7037 // in response to touch events and we want to ensure that the injected keys
7038 // are processed in the order they were received and we cannot trust that
7039 // the time stamp of injected events are monotonic.
Michael Wrightc8a7e542013-03-20 17:58:33 -07007040 QueuedInputEvent last = mPendingInputEventTail;
Jeff Brown4952dfd2011-11-30 19:23:22 -08007041 if (last == null) {
Michael Wrightc8a7e542013-03-20 17:58:33 -07007042 mPendingInputEventHead = q;
7043 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08007044 } else {
Jeff Brown4952dfd2011-11-30 19:23:22 -08007045 last.mNext = q;
Michael Wrightc8a7e542013-03-20 17:58:33 -07007046 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08007047 }
Michael Wright95ae9422013-03-14 10:58:50 -07007048 mPendingInputEventCount += 1;
7049 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
7050 mPendingInputEventCount);
Jeff Brown4952dfd2011-11-30 19:23:22 -08007051
Jeff Brownf9261d22012-02-03 13:49:15 -08007052 if (processImmediately) {
7053 doProcessInputEvents();
7054 } else {
7055 scheduleProcessInputEvents();
7056 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08007057 }
7058
7059 private void scheduleProcessInputEvents() {
Jeff Brown96e942d2011-11-30 19:55:01 -08007060 if (!mProcessInputEventsScheduled) {
7061 mProcessInputEventsScheduled = true;
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007062 Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
7063 msg.setAsynchronous(true);
7064 mHandler.sendMessage(msg);
Jeff Brown4952dfd2011-11-30 19:23:22 -08007065 }
7066 }
7067
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007068 void doProcessInputEvents() {
Jeff Brownf9e989d2013-04-04 23:04:03 -07007069 // Deliver all pending input events in the queue.
Michael Wrightc8a7e542013-03-20 17:58:33 -07007070 while (mPendingInputEventHead != null) {
7071 QueuedInputEvent q = mPendingInputEventHead;
7072 mPendingInputEventHead = q.mNext;
7073 if (mPendingInputEventHead == null) {
7074 mPendingInputEventTail = null;
7075 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08007076 q.mNext = null;
Jeff Brown29c0ed22013-01-14 13:50:37 -08007077
Michael Wright95ae9422013-03-14 10:58:50 -07007078 mPendingInputEventCount -= 1;
7079 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
7080 mPendingInputEventCount);
7081
John Reckba6adf62015-02-19 14:36:50 -08007082 long eventTime = q.mEvent.getEventTimeNano();
7083 long oldestEventTime = eventTime;
7084 if (q.mEvent instanceof MotionEvent) {
7085 MotionEvent me = (MotionEvent)q.mEvent;
7086 if (me.getHistorySize() > 0) {
7087 oldestEventTime = me.getHistoricalEventTimeNano(0);
7088 }
7089 }
7090 mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
7091
Jeff Brownf9e989d2013-04-04 23:04:03 -07007092 deliverInputEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08007093 }
7094
7095 // We are done processing all input events that we can process right now
7096 // so we can clear the pending flag immediately.
Jeff Brown96e942d2011-11-30 19:55:01 -08007097 if (mProcessInputEventsScheduled) {
7098 mProcessInputEventsScheduled = false;
Jeff Browna175a5b2012-02-15 19:18:31 -08007099 mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
Jeff Brown4952dfd2011-11-30 19:23:22 -08007100 }
7101 }
7102
Jeff Brownf9e989d2013-04-04 23:04:03 -07007103 private void deliverInputEvent(QueuedInputEvent q) {
Michael Wrightd2c3adc2014-02-18 22:50:50 -08007104 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
7105 q.mEvent.getSequenceNumber());
7106 if (mInputEventConsistencyVerifier != null) {
7107 mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
7108 }
Michael Wrightc8a7e542013-03-20 17:58:33 -07007109
Michael Wright899d7052014-04-23 17:23:39 -07007110 InputStage stage;
7111 if (q.shouldSendToSynthesizer()) {
7112 stage = mSyntheticInputStage;
7113 } else {
7114 stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
7115 }
7116
Evan Roskycd80e612018-05-17 17:46:09 -07007117 if (q.mEvent instanceof KeyEvent) {
7118 mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
7119 }
7120
Michael Wrightd2c3adc2014-02-18 22:50:50 -08007121 if (stage != null) {
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08007122 handleWindowFocusChanged();
Michael Wrightd2c3adc2014-02-18 22:50:50 -08007123 stage.deliver(q);
7124 } else {
7125 finishInputEvent(q);
Michael Wrightbf020962013-03-28 17:27:50 -07007126 }
Michael Wrightbf020962013-03-28 17:27:50 -07007127 }
7128
Jeff Brownf9e989d2013-04-04 23:04:03 -07007129 private void finishInputEvent(QueuedInputEvent q) {
Michael Wrightd2c3adc2014-02-18 22:50:50 -08007130 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
7131 q.mEvent.getSequenceNumber());
Michael Wright9d744c72014-02-18 21:27:42 -08007132
Jeff Brown32cbc38552011-12-01 14:01:49 -08007133 if (q.mReceiver != null) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07007134 boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
Jeff Brown32cbc38552011-12-01 14:01:49 -08007135 q.mReceiver.finishInputEvent(q.mEvent, handled);
Jeff Brown92cc2d82011-12-02 01:19:47 -08007136 } else {
7137 q.mEvent.recycleIfNeededAfterDispatch();
Jeff Brown4952dfd2011-11-30 19:23:22 -08007138 }
7139
7140 recycleQueuedInputEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08007141 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08007142
Michael Wright5bd69e62015-05-14 14:48:08 +01007143 private void adjustInputEventForCompatibility(InputEvent e) {
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07007144 if (mTargetSdkVersion < Build.VERSION_CODES.M && e instanceof MotionEvent) {
Michael Wright5bd69e62015-05-14 14:48:08 +01007145 MotionEvent motion = (MotionEvent) e;
7146 final int mask =
7147 MotionEvent.BUTTON_STYLUS_PRIMARY | MotionEvent.BUTTON_STYLUS_SECONDARY;
7148 final int buttonState = motion.getButtonState();
7149 final int compatButtonState = (buttonState & mask) >> 4;
7150 if (compatButtonState != 0) {
7151 motion.setButtonState(buttonState | compatButtonState);
7152 }
7153 }
7154 }
7155
Jeff Brownf9e989d2013-04-04 23:04:03 -07007156 static boolean isTerminalInputEvent(InputEvent event) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08007157 if (event instanceof KeyEvent) {
7158 final KeyEvent keyEvent = (KeyEvent)event;
7159 return keyEvent.getAction() == KeyEvent.ACTION_UP;
7160 } else {
7161 final MotionEvent motionEvent = (MotionEvent)event;
7162 final int action = motionEvent.getAction();
7163 return action == MotionEvent.ACTION_UP
7164 || action == MotionEvent.ACTION_CANCEL
7165 || action == MotionEvent.ACTION_HOVER_EXIT;
Jeff Brown4952dfd2011-11-30 19:23:22 -08007166 }
7167 }
7168
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007169 void scheduleConsumeBatchedInput() {
7170 if (!mConsumeBatchedInputScheduled) {
7171 mConsumeBatchedInputScheduled = true;
7172 mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
7173 mConsumedBatchedInputRunnable, null);
Jeff Brown4a06c802012-02-15 15:06:01 -08007174 }
7175 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007176
7177 void unscheduleConsumeBatchedInput() {
7178 if (mConsumeBatchedInputScheduled) {
7179 mConsumeBatchedInputScheduled = false;
7180 mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT,
7181 mConsumedBatchedInputRunnable, null);
7182 }
7183 }
7184
Michael Wright9d744c72014-02-18 21:27:42 -08007185 void scheduleConsumeBatchedInputImmediately() {
7186 if (!mConsumeBatchedInputImmediatelyScheduled) {
7187 unscheduleConsumeBatchedInput();
7188 mConsumeBatchedInputImmediatelyScheduled = true;
7189 mHandler.post(mConsumeBatchedInputImmediatelyRunnable);
7190 }
7191 }
7192
Jeff Brown771526c2012-04-27 15:13:25 -07007193 void doConsumeBatchedInput(long frameTimeNanos) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007194 if (mConsumeBatchedInputScheduled) {
7195 mConsumeBatchedInputScheduled = false;
Jeff Brown330314c2012-04-27 02:20:22 -07007196 if (mInputEventReceiver != null) {
Michael Wright9d744c72014-02-18 21:27:42 -08007197 if (mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos)
7198 && frameTimeNanos != -1) {
Michael Wright62ce65d2013-10-25 14:50:36 -07007199 // If we consumed a batch here, we want to go ahead and schedule the
7200 // consumption of batched input events on the next frame. Otherwise, we would
7201 // wait until we have more input events pending and might get starved by other
Michael Wright9d744c72014-02-18 21:27:42 -08007202 // things occurring in the process. If the frame time is -1, however, then
7203 // we're in a non-batching mode, so there's no need to schedule this.
Michael Wright62ce65d2013-10-25 14:50:36 -07007204 scheduleConsumeBatchedInput();
7205 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007206 }
Jeff Brown330314c2012-04-27 02:20:22 -07007207 doProcessInputEvents();
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007208 }
7209 }
7210
7211 final class TraversalRunnable implements Runnable {
7212 @Override
7213 public void run() {
7214 doTraversal();
7215 }
7216 }
7217 final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
Jeff Brown4a06c802012-02-15 15:06:01 -08007218
Jeff Brown32cbc38552011-12-01 14:01:49 -08007219 final class WindowInputEventReceiver extends InputEventReceiver {
7220 public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
7221 super(inputChannel, looper);
Jeff Brown46b9ac02010-04-22 18:58:52 -07007222 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08007223
7224 @Override
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -07007225 public void onInputEvent(InputEvent event, int displayId) {
Jeff Brownf9261d22012-02-03 13:49:15 -08007226 enqueueInputEvent(event, this, 0, true);
Jeff Brown32cbc38552011-12-01 14:01:49 -08007227 }
Jeff Brown072ec962012-02-07 14:46:57 -08007228
7229 @Override
7230 public void onBatchedInputEventPending() {
Michael Wright9d744c72014-02-18 21:27:42 -08007231 if (mUnbufferedInputDispatch) {
7232 super.onBatchedInputEventPending();
7233 } else {
7234 scheduleConsumeBatchedInput();
7235 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007236 }
7237
7238 @Override
7239 public void dispose() {
7240 unscheduleConsumeBatchedInput();
7241 super.dispose();
Jeff Brown072ec962012-02-07 14:46:57 -08007242 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08007243 }
7244 WindowInputEventReceiver mInputEventReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007245
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007246 final class ConsumeBatchedInputRunnable implements Runnable {
7247 @Override
7248 public void run() {
Jeff Brown771526c2012-04-27 15:13:25 -07007249 doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007250 }
7251 }
7252 final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =
7253 new ConsumeBatchedInputRunnable();
7254 boolean mConsumeBatchedInputScheduled;
7255
Michael Wright9d744c72014-02-18 21:27:42 -08007256 final class ConsumeBatchedInputImmediatelyRunnable implements Runnable {
7257 @Override
7258 public void run() {
7259 doConsumeBatchedInput(-1);
7260 }
7261 }
7262 final ConsumeBatchedInputImmediatelyRunnable mConsumeBatchedInputImmediatelyRunnable =
7263 new ConsumeBatchedInputImmediatelyRunnable();
7264 boolean mConsumeBatchedInputImmediatelyScheduled;
7265
Jeff Brown6cb7b462012-03-05 13:21:17 -08007266 final class InvalidateOnAnimationRunnable implements Runnable {
7267 private boolean mPosted;
Igor Murashkina86ab6402013-08-30 12:58:36 -07007268 private final ArrayList<View> mViews = new ArrayList<View>();
7269 private final ArrayList<AttachInfo.InvalidateInfo> mViewRects =
Jeff Brown6cb7b462012-03-05 13:21:17 -08007270 new ArrayList<AttachInfo.InvalidateInfo>();
7271 private View[] mTempViews;
7272 private AttachInfo.InvalidateInfo[] mTempViewRects;
7273
7274 public void addView(View view) {
7275 synchronized (this) {
7276 mViews.add(view);
7277 postIfNeededLocked();
7278 }
7279 }
7280
7281 public void addViewRect(AttachInfo.InvalidateInfo info) {
7282 synchronized (this) {
7283 mViewRects.add(info);
7284 postIfNeededLocked();
7285 }
7286 }
7287
7288 public void removeView(View view) {
7289 synchronized (this) {
7290 mViews.remove(view);
7291
7292 for (int i = mViewRects.size(); i-- > 0; ) {
7293 AttachInfo.InvalidateInfo info = mViewRects.get(i);
7294 if (info.target == view) {
7295 mViewRects.remove(i);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08007296 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08007297 }
7298 }
7299
7300 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007301 mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08007302 mPosted = false;
7303 }
7304 }
7305 }
7306
7307 @Override
7308 public void run() {
7309 final int viewCount;
7310 final int viewRectCount;
7311 synchronized (this) {
7312 mPosted = false;
7313
7314 viewCount = mViews.size();
7315 if (viewCount != 0) {
7316 mTempViews = mViews.toArray(mTempViews != null
7317 ? mTempViews : new View[viewCount]);
7318 mViews.clear();
7319 }
7320
7321 viewRectCount = mViewRects.size();
7322 if (viewRectCount != 0) {
7323 mTempViewRects = mViewRects.toArray(mTempViewRects != null
7324 ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]);
7325 mViewRects.clear();
7326 }
7327 }
7328
7329 for (int i = 0; i < viewCount; i++) {
7330 mTempViews[i].invalidate();
Adam Powell3e3c4ee2012-05-16 17:34:21 -07007331 mTempViews[i] = null;
Jeff Brown6cb7b462012-03-05 13:21:17 -08007332 }
7333
7334 for (int i = 0; i < viewRectCount; i++) {
7335 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
7336 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08007337 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08007338 }
7339 }
7340
7341 private void postIfNeededLocked() {
7342 if (!mPosted) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07007343 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08007344 mPosted = true;
7345 }
7346 }
7347 }
7348 final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
7349 new InvalidateOnAnimationRunnable();
7350
Jeff Browna175a5b2012-02-15 19:18:31 -08007351 public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
7352 Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
7353 mHandler.sendMessageDelayed(msg, delayMilliseconds);
7354 }
7355
Jeff Browna175a5b2012-02-15 19:18:31 -08007356 public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
7357 long delayMilliseconds) {
7358 final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
7359 mHandler.sendMessageDelayed(msg, delayMilliseconds);
7360 }
7361
Jeff Brown6cb7b462012-03-05 13:21:17 -08007362 public void dispatchInvalidateOnAnimation(View view) {
7363 mInvalidateOnAnimationRunnable.addView(view);
7364 }
7365
7366 public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) {
7367 mInvalidateOnAnimationRunnable.addViewRect(info);
7368 }
7369
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007370 @UnsupportedAppUsage
Jeff Brown6cb7b462012-03-05 13:21:17 -08007371 public void cancelInvalidate(View view) {
7372 mHandler.removeMessages(MSG_INVALIDATE, view);
7373 // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning
7374 // them to the pool
7375 mHandler.removeMessages(MSG_INVALIDATE_RECT, view);
7376 mInvalidateOnAnimationRunnable.removeView(view);
7377 }
7378
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007379 @UnsupportedAppUsage
keunyoung30f420f2013-08-02 14:23:10 -07007380 public void dispatchInputEvent(InputEvent event) {
Jae Seo6a6059a2014-04-17 21:35:29 -07007381 dispatchInputEvent(event, null);
7382 }
7383
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007384 @UnsupportedAppUsage
Jae Seo6a6059a2014-04-17 21:35:29 -07007385 public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
7386 SomeArgs args = SomeArgs.obtain();
7387 args.arg1 = event;
7388 args.arg2 = receiver;
7389 Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
Jeff Browne0dbd002012-02-15 19:34:58 -08007390 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08007391 mHandler.sendMessage(msg);
7392 }
7393
Michael Wright899d7052014-04-23 17:23:39 -07007394 public void synthesizeInputEvent(InputEvent event) {
7395 Message msg = mHandler.obtainMessage(MSG_SYNTHESIZE_INPUT_EVENT, event);
7396 msg.setAsynchronous(true);
7397 mHandler.sendMessage(msg);
7398 }
7399
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007400 @UnsupportedAppUsage
Jeff Browna175a5b2012-02-15 19:18:31 -08007401 public void dispatchKeyFromIme(KeyEvent event) {
7402 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
Jeff Browne0dbd002012-02-15 19:34:58 -08007403 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08007404 mHandler.sendMessage(msg);
Jeff Browncb1404e2011-01-15 18:14:15 -08007405 }
7406
Dake Gu6a20a192018-02-08 12:09:30 -08007407 public void dispatchKeyFromAutofill(KeyEvent event) {
7408 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_AUTOFILL, event);
7409 msg.setAsynchronous(true);
7410 mHandler.sendMessage(msg);
7411 }
7412
Michael Wright899d7052014-04-23 17:23:39 -07007413 /**
7414 * Reinject unhandled {@link InputEvent}s in order to synthesize fallbacks events.
7415 *
7416 * Note that it is the responsibility of the caller of this API to recycle the InputEvent it
7417 * passes in.
7418 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +01007419 @UnsupportedAppUsage
Michael Wright3da28342014-04-22 17:00:11 -07007420 public void dispatchUnhandledInputEvent(InputEvent event) {
Michael Wright899d7052014-04-23 17:23:39 -07007421 if (event instanceof MotionEvent) {
7422 event = MotionEvent.obtain((MotionEvent) event);
Michael Wright3da28342014-04-22 17:00:11 -07007423 }
Michael Wright899d7052014-04-23 17:23:39 -07007424 synthesizeInputEvent(event);
Michael Wright3da28342014-04-22 17:00:11 -07007425 }
7426
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007427 public void dispatchAppVisibility(boolean visible) {
Jeff Browna175a5b2012-02-15 19:18:31 -08007428 Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007429 msg.arg1 = visible ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08007430 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007431 }
7432
7433 public void dispatchGetNewSurface() {
Jeff Browna175a5b2012-02-15 19:18:31 -08007434 Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
7435 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007436 }
7437
7438 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08007439 synchronized (this) {
Dianne Hackborn011944c2017-12-15 15:44:55 -08007440 mWindowFocusChanged = true;
Dianne Hackborn5c3296a2017-12-13 17:52:26 -08007441 mUpcomingWindowFocus = hasFocus;
7442 mUpcomingInTouchMode = inTouchMode;
7443 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007444 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08007445 msg.what = MSG_WINDOW_FOCUS_CHANGED;
Jeff Browna175a5b2012-02-15 19:18:31 -08007446 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007447 }
7448
Craig Mautner9c795042014-10-28 19:59:59 -07007449 public void dispatchWindowShown() {
7450 mHandler.sendEmptyMessage(MSG_DISPATCH_WINDOW_SHOWN);
7451 }
7452
Dianne Hackbornffa42482009-09-23 22:20:11 -07007453 public void dispatchCloseSystemDialogs(String reason) {
7454 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08007455 msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
Dianne Hackbornffa42482009-09-23 22:20:11 -07007456 msg.obj = reason;
Jeff Browna175a5b2012-02-15 19:18:31 -08007457 mHandler.sendMessage(msg);
Dianne Hackbornffa42482009-09-23 22:20:11 -07007458 }
Christopher Tatea53146c2010-09-07 11:57:52 -07007459
7460 public void dispatchDragEvent(DragEvent event) {
Chris Tate91e9bb32010-10-12 12:58:43 -07007461 final int what;
7462 if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
Jeff Browna175a5b2012-02-15 19:18:31 -08007463 what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
7464 mHandler.removeMessages(what);
Chris Tate91e9bb32010-10-12 12:58:43 -07007465 } else {
Jeff Browna175a5b2012-02-15 19:18:31 -08007466 what = MSG_DISPATCH_DRAG_EVENT;
Chris Tate91e9bb32010-10-12 12:58:43 -07007467 }
Jeff Browna175a5b2012-02-15 19:18:31 -08007468 Message msg = mHandler.obtainMessage(what, event);
7469 mHandler.sendMessage(msg);
Christopher Tatea53146c2010-09-07 11:57:52 -07007470 }
7471
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08007472 public void updatePointerIcon(float x, float y) {
7473 final int what = MSG_UPDATE_POINTER_ICON;
7474 mHandler.removeMessages(what);
7475 final long now = SystemClock.uptimeMillis();
7476 final MotionEvent event = MotionEvent.obtain(
7477 0, now, MotionEvent.ACTION_HOVER_MOVE, x, y, 0);
7478 Message msg = mHandler.obtainMessage(what, event);
7479 mHandler.sendMessage(msg);
7480 }
7481
Dianne Hackborn9a230e02011-10-06 11:51:27 -07007482 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
7483 int localValue, int localChanges) {
7484 SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
7485 args.seq = seq;
7486 args.globalVisibility = globalVisibility;
7487 args.localValue = localValue;
7488 args.localChanges = localChanges;
Jeff Browna175a5b2012-02-15 19:18:31 -08007489 mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
7490 }
7491
7492 public void dispatchCheckFocus() {
7493 if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
7494 // This will result in a call to checkFocus() below.
7495 mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
7496 }
Joe Onorato664644d2011-01-23 17:53:23 -08007497 }
7498
Clara Bayarrifcd7e802016-03-10 12:58:18 +00007499 public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
7500 mHandler.obtainMessage(
7501 MSG_REQUEST_KEYBOARD_SHORTCUTS, deviceId, 0, receiver).sendToTarget();
Clara Bayarri75e09792015-07-29 16:20:40 +01007502 }
7503
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08007504 public void dispatchPointerCaptureChanged(boolean on) {
7505 final int what = MSG_POINTER_CAPTURE_CHANGED;
7506 mHandler.removeMessages(what);
7507 Message msg = mHandler.obtainMessage(what);
7508 msg.arg1 = on ? 1 : 0;
7509 mHandler.sendMessage(msg);
7510 }
7511
svetoslavganov75986cf2009-05-14 22:28:01 -07007512 /**
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07007513 * Post a callback to send a
7514 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
Svetoslav Ganova0156172011-06-26 17:55:44 -07007515 * This event is send at most once every
7516 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07007517 */
Alan Viverette77e9a282013-09-12 17:16:09 -07007518 private void postSendWindowContentChangedCallback(View source, int changeType) {
Eugene Susla72c510f2018-01-23 21:12:11 +00007519 if (mSendWindowContentChangedAccessibilityEvent == null) {
7520 mSendWindowContentChangedAccessibilityEvent =
7521 new SendWindowContentChangedAccessibilityEvent();
7522 }
7523 mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07007524 }
7525
7526 /**
7527 * Remove a posted callback to send a
7528 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
7529 */
7530 private void removeSendWindowContentChangedCallback() {
Eugene Susla72c510f2018-01-23 21:12:11 +00007531 if (mSendWindowContentChangedAccessibilityEvent != null) {
7532 mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07007533 }
7534 }
7535
Igor Murashkina86ab6402013-08-30 12:58:36 -07007536 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007537 public boolean showContextMenuForChild(View originalView) {
7538 return false;
7539 }
7540
Igor Murashkina86ab6402013-08-30 12:58:36 -07007541 @Override
Oren Blasberged391262015-09-01 12:12:51 -07007542 public boolean showContextMenuForChild(View originalView, float x, float y) {
7543 return false;
7544 }
7545
7546 @Override
Adam Powell6e346362010-07-23 10:18:23 -07007547 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
7548 return null;
7549 }
7550
Igor Murashkina86ab6402013-08-30 12:58:36 -07007551 @Override
Clara Bayarri4423d912015-03-02 19:42:48 +00007552 public ActionMode startActionModeForChild(
7553 View originalView, ActionMode.Callback callback, int type) {
7554 return null;
7555 }
7556
7557 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007558 public void createContextMenu(ContextMenu menu) {
7559 }
7560
Igor Murashkina86ab6402013-08-30 12:58:36 -07007561 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007562 public void childDrawableStateChanged(View child) {
7563 }
7564
Igor Murashkina86ab6402013-08-30 12:58:36 -07007565 @Override
Svetoslav Ganov736c2752011-04-22 18:30:36 -07007566 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
George Mount41725de2015-04-09 08:23:05 -07007567 if (mView == null || mStopped || mPausedForTransition) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -07007568 return false;
7569 }
Eugene Suslaccce5c92017-05-22 13:14:57 -07007570
Eugene Susla72c510f2018-01-23 21:12:11 +00007571 // Immediately flush pending content changed event (if any) to preserve event order
7572 if (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
7573 && mSendWindowContentChangedAccessibilityEvent != null
7574 && mSendWindowContentChangedAccessibilityEvent.mSource != null) {
7575 mSendWindowContentChangedAccessibilityEvent.removeCallbacksAndRun();
7576 }
Eugene Suslaccce5c92017-05-22 13:14:57 -07007577
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07007578 // Intercept accessibility focus events fired by virtual nodes to keep
7579 // track of accessibility focus position in such nodes.
Svetoslav Ganov791fd312012-05-14 15:12:30 -07007580 final int eventType = event.getEventType();
7581 switch (eventType) {
7582 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07007583 final long sourceNodeId = event.getSourceNodeId();
7584 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
7585 sourceNodeId);
7586 View source = mView.findViewByAccessibilityId(accessibilityViewId);
7587 if (source != null) {
7588 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
7589 if (provider != null) {
Svetoslavb3ba1d42014-09-26 15:20:40 -07007590 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
7591 sourceNodeId);
7592 final AccessibilityNodeInfo node;
Phil Weaverf00cd142017-03-03 13:44:00 -08007593 node = provider.createAccessibilityNodeInfo(virtualNodeId);
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07007594 setAccessibilityFocus(source, node);
7595 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07007596 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07007597 } break;
7598 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07007599 final long sourceNodeId = event.getSourceNodeId();
7600 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
7601 sourceNodeId);
7602 View source = mView.findViewByAccessibilityId(accessibilityViewId);
7603 if (source != null) {
7604 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
7605 if (provider != null) {
7606 setAccessibilityFocus(null, null);
7607 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07007608 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07007609 } break;
Svetoslavf0c758b2014-09-03 17:47:37 -07007610
7611
7612 case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: {
Alan Viverette34457f52015-03-25 13:09:20 -07007613 handleWindowContentChangedEvent(event);
Svetoslavf0c758b2014-09-03 17:47:37 -07007614 } break;
Svetoslav Ganov791fd312012-05-14 15:12:30 -07007615 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007616 mAccessibilityManager.sendAccessibilityEvent(event);
Svetoslav Ganov736c2752011-04-22 18:30:36 -07007617 return true;
7618 }
7619
Alan Viverette34457f52015-03-25 13:09:20 -07007620 /**
7621 * Updates the focused virtual view, when necessary, in response to a
7622 * content changed event.
7623 * <p>
7624 * This is necessary to get updated bounds after a position change.
7625 *
7626 * @param event an accessibility event of type
7627 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}
7628 */
7629 private void handleWindowContentChangedEvent(AccessibilityEvent event) {
Alan Viverette25acc7e2015-05-19 11:32:08 -07007630 final View focusedHost = mAccessibilityFocusedHost;
7631 if (focusedHost == null || mAccessibilityFocusedVirtualView == null) {
7632 // No virtual view focused, nothing to do here.
Alan Viverette34457f52015-03-25 13:09:20 -07007633 return;
7634 }
7635
Alan Viverette25acc7e2015-05-19 11:32:08 -07007636 final AccessibilityNodeProvider provider = focusedHost.getAccessibilityNodeProvider();
Alan Viverette34457f52015-03-25 13:09:20 -07007637 if (provider == null) {
Alan Viverette25acc7e2015-05-19 11:32:08 -07007638 // Error state: virtual view with no provider. Clear focus.
7639 mAccessibilityFocusedHost = null;
7640 mAccessibilityFocusedVirtualView = null;
Phil Weavere37cfab2016-04-07 21:01:57 -07007641 focusedHost.clearAccessibilityFocusNoCallbacks(0);
Alan Viverette34457f52015-03-25 13:09:20 -07007642 return;
7643 }
7644
7645 // We only care about change types that may affect the bounds of the
7646 // focused virtual view.
7647 final int changes = event.getContentChangeTypes();
7648 if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) == 0
7649 && changes != AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) {
7650 return;
7651 }
7652
7653 final long eventSourceNodeId = event.getSourceNodeId();
7654 final int changedViewId = AccessibilityNodeInfo.getAccessibilityViewId(eventSourceNodeId);
7655
7656 // Search up the tree for subtree containment.
7657 boolean hostInSubtree = false;
7658 View root = mAccessibilityFocusedHost;
7659 while (root != null && !hostInSubtree) {
7660 if (changedViewId == root.getAccessibilityViewId()) {
7661 hostInSubtree = true;
7662 } else {
7663 final ViewParent parent = root.getParent();
7664 if (parent instanceof View) {
7665 root = (View) parent;
7666 } else {
7667 root = null;
7668 }
7669 }
7670 }
7671
7672 // We care only about changes in subtrees containing the host view.
7673 if (!hostInSubtree) {
7674 return;
7675 }
7676
7677 final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId();
7678 int focusedChildId = AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId);
Alan Viverette34457f52015-03-25 13:09:20 -07007679
7680 // Refresh the node for the focused virtual view.
Alan Viverettea7ea65e2015-05-15 11:30:21 -07007681 final Rect oldBounds = mTempRect;
7682 mAccessibilityFocusedVirtualView.getBoundsInScreen(oldBounds);
Alan Viverette34457f52015-03-25 13:09:20 -07007683 mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo(focusedChildId);
Alan Viverette25acc7e2015-05-19 11:32:08 -07007684 if (mAccessibilityFocusedVirtualView == null) {
7685 // Error state: The node no longer exists. Clear focus.
7686 mAccessibilityFocusedHost = null;
Phil Weavere37cfab2016-04-07 21:01:57 -07007687 focusedHost.clearAccessibilityFocusNoCallbacks(0);
Alan Viverette25acc7e2015-05-19 11:32:08 -07007688
7689 // This will probably fail, but try to keep the provider's internal
7690 // state consistent by clearing focus.
7691 provider.performAction(focusedChildId,
7692 AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(), null);
Alan Viverettea7ea65e2015-05-15 11:30:21 -07007693 invalidateRectOnScreen(oldBounds);
Alan Viverette25acc7e2015-05-19 11:32:08 -07007694 } else {
7695 // The node was refreshed, invalidate bounds if necessary.
7696 final Rect newBounds = mAccessibilityFocusedVirtualView.getBoundsInScreen();
7697 if (!oldBounds.equals(newBounds)) {
7698 oldBounds.union(newBounds);
7699 invalidateRectOnScreen(oldBounds);
7700 }
Alan Viverettea7ea65e2015-05-15 11:30:21 -07007701 }
Alan Viverette34457f52015-03-25 13:09:20 -07007702 }
7703
Svetoslav Ganov42138042012-03-20 11:51:39 -07007704 @Override
Alan Viverette77e9a282013-09-12 17:16:09 -07007705 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
Phil Weaver63e45032017-05-11 10:54:37 -07007706 postSendWindowContentChangedCallback(Preconditions.checkNotNull(source), changeType);
Svetoslav Ganov42138042012-03-20 11:51:39 -07007707 }
7708
Fabrice Di Meglio9dd4c5c2013-02-08 18:15:07 -08007709 @Override
7710 public boolean canResolveLayoutDirection() {
7711 return true;
7712 }
7713
7714 @Override
7715 public boolean isLayoutDirectionResolved() {
7716 return true;
7717 }
7718
7719 @Override
7720 public int getLayoutDirection() {
7721 return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT;
7722 }
7723
7724 @Override
7725 public boolean canResolveTextDirection() {
7726 return true;
7727 }
7728
7729 @Override
7730 public boolean isTextDirectionResolved() {
7731 return true;
7732 }
7733
7734 @Override
7735 public int getTextDirection() {
7736 return View.TEXT_DIRECTION_RESOLVED_DEFAULT;
7737 }
7738
7739 @Override
7740 public boolean canResolveTextAlignment() {
7741 return true;
7742 }
7743
7744 @Override
7745 public boolean isTextAlignmentResolved() {
7746 return true;
7747 }
7748
7749 @Override
7750 public int getTextAlignment() {
7751 return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT;
7752 }
7753
Eugene Susla72c510f2018-01-23 21:12:11 +00007754 private View getCommonPredecessor(View first, View second) {
7755 if (mTempHashSet == null) {
7756 mTempHashSet = new HashSet<View>();
7757 }
7758 HashSet<View> seen = mTempHashSet;
7759 seen.clear();
7760 View firstCurrent = first;
7761 while (firstCurrent != null) {
7762 seen.add(firstCurrent);
7763 ViewParent firstCurrentParent = firstCurrent.mParent;
7764 if (firstCurrentParent instanceof View) {
7765 firstCurrent = (View) firstCurrentParent;
7766 } else {
7767 firstCurrent = null;
7768 }
7769 }
7770 View secondCurrent = second;
7771 while (secondCurrent != null) {
7772 if (seen.contains(secondCurrent)) {
7773 seen.clear();
7774 return secondCurrent;
7775 }
7776 ViewParent secondCurrentParent = secondCurrent.mParent;
7777 if (secondCurrentParent instanceof View) {
7778 secondCurrent = (View) secondCurrentParent;
7779 } else {
7780 secondCurrent = null;
7781 }
7782 }
7783 seen.clear();
7784 return null;
7785 }
7786
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007787 void checkThread() {
7788 if (mThread != Thread.currentThread()) {
7789 throw new CalledFromWrongThreadException(
7790 "Only the original thread that created a view hierarchy can touch its views.");
7791 }
7792 }
7793
Igor Murashkina86ab6402013-08-30 12:58:36 -07007794 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007795 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Joe Onoratoc6cc0f82011-04-12 11:53:13 -07007796 // ViewAncestor never intercepts touch event, so this can be a no-op
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007797 }
7798
Igor Murashkina86ab6402013-08-30 12:58:36 -07007799 @Override
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07007800 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
Yigit Boyard62d5e92016-01-19 18:56:20 -08007801 if (rectangle == null) {
7802 return scrollToRectOrFocus(null, immediate);
7803 }
7804 rectangle.offset(child.getLeft() - child.getScrollX(),
7805 child.getTop() - child.getScrollY());
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07007806 final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
Yigit Boyard62d5e92016-01-19 18:56:20 -08007807 mTempRect.set(rectangle);
7808 mTempRect.offset(0, -mCurScrollY);
7809 mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
7810 try {
7811 mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect);
7812 } catch (RemoteException re) {
7813 /* ignore */
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07007814 }
7815 return scrolled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007816 }
Romain Guy8506ab42009-06-11 17:35:47 -07007817
Igor Murashkina86ab6402013-08-30 12:58:36 -07007818 @Override
Adam Powell539ee872012-02-03 19:00:49 -08007819 public void childHasTransientStateChanged(View child, boolean hasTransientState) {
7820 // Do nothing.
7821 }
7822
Adam Powell10ba2772014-04-15 09:46:51 -07007823 @Override
7824 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
7825 return false;
7826 }
7827
7828 @Override
7829 public void onStopNestedScroll(View target) {
7830 }
7831
7832 @Override
7833 public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
7834 }
7835
7836 @Override
7837 public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
7838 int dxUnconsumed, int dyUnconsumed) {
7839 }
7840
7841 @Override
7842 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
7843 }
7844
7845 @Override
Adam Powellb36e4f92014-05-01 10:23:33 -07007846 public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
Adam Powell10ba2772014-04-15 09:46:51 -07007847 return false;
7848 }
7849
Adam Powellb72be592014-07-16 21:41:31 -07007850 @Override
7851 public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
7852 return false;
7853 }
7854
Adam Powellb6ab0982015-01-07 17:00:12 -08007855 @Override
7856 public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
7857 return false;
7858 }
7859
Robert Carr49cd9f82017-05-25 18:24:42 -07007860
7861 private void reportNextDraw() {
7862 if (mReportNextDraw == false) {
7863 drawPending();
7864 }
7865 mReportNextDraw = true;
7866 }
7867
Jorim Jaggib774e552015-08-24 14:52:45 -07007868 /**
7869 * Force the window to report its next draw.
7870 * <p>
7871 * This method is only supposed to be used to speed up the interaction from SystemUI and window
7872 * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE
7873 * unless you fully understand this interaction.
7874 * @hide
7875 */
7876 public void setReportNextDraw() {
Robert Carr49cd9f82017-05-25 18:24:42 -07007877 reportNextDraw();
Jorim Jaggib774e552015-08-24 14:52:45 -07007878 invalidate();
7879 }
7880
Craig Mautnerbc57cd12013-08-19 15:47:42 -07007881 void changeCanvasOpacity(boolean opaque) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08007882 Log.d(mTag, "changeCanvasOpacity: opaque=" + opaque);
Stan Iliev45faba52016-06-28 13:33:15 -04007883 if (mAttachInfo.mThreadedRenderer != null) {
7884 mAttachInfo.mThreadedRenderer.setOpaque(opaque);
John Reck63a06672014-05-07 13:45:54 -07007885 }
Craig Mautnerbc57cd12013-08-19 15:47:42 -07007886 }
7887
Evan Rosky5e29c072017-06-02 17:31:22 -07007888 /**
7889 * Dispatches a KeyEvent to all registered key fallback handlers.
7890 *
7891 * @param event
7892 * @return {@code true} if the event was handled, {@code false} otherwise.
7893 */
Evan Roskycd80e612018-05-17 17:46:09 -07007894 public boolean dispatchUnhandledKeyEvent(KeyEvent event) {
Evan Rosky4807ae22018-03-22 16:04:15 -07007895 return mUnhandledKeyManager.dispatch(mView, event);
Evan Rosky5e29c072017-06-02 17:31:22 -07007896 }
7897
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07007898 class TakenSurfaceHolder extends BaseSurfaceHolder {
7899 @Override
7900 public boolean onAllowLockCanvas() {
7901 return mDrawingAllowed;
7902 }
7903
7904 @Override
7905 public void onRelayoutContainer() {
7906 // Not currently interesting -- from changing between fixed and layout size.
7907 }
7908
Igor Murashkina86ab6402013-08-30 12:58:36 -07007909 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07007910 public void setFormat(int format) {
7911 ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
7912 }
7913
Igor Murashkina86ab6402013-08-30 12:58:36 -07007914 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07007915 public void setType(int type) {
7916 ((RootViewSurfaceTaker)mView).setSurfaceType(type);
7917 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07007918
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07007919 @Override
7920 public void onUpdateSurface() {
7921 // We take care of format and type changes on our own.
7922 throw new IllegalStateException("Shouldn't be here");
7923 }
7924
Igor Murashkina86ab6402013-08-30 12:58:36 -07007925 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07007926 public boolean isCreating() {
7927 return mIsCreating;
7928 }
7929
7930 @Override
7931 public void setFixedSize(int width, int height) {
7932 throw new UnsupportedOperationException(
7933 "Currently only support sizing from layout");
7934 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07007935
7936 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07007937 public void setKeepScreenOn(boolean screenOn) {
7938 ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
7939 }
7940 }
Romain Guy8506ab42009-06-11 17:35:47 -07007941
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007942 static class W extends IWindow.Stub {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007943 private final WeakReference<ViewRootImpl> mViewAncestor;
Jeff Brown98365d72012-08-19 20:30:52 -07007944 private final IWindowSession mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007945
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007946 W(ViewRootImpl viewAncestor) {
7947 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
Jeff Brown98365d72012-08-19 20:30:52 -07007948 mWindowSession = viewAncestor.mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007949 }
7950
Igor Murashkina86ab6402013-08-30 12:58:36 -07007951 @Override
Dianne Hackbornc4aad012013-02-22 15:05:25 -08007952 public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Filip Gruszczynski2217f612015-05-26 11:32:08 -07007953 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
Andrii Kulian44607962017-03-16 11:06:24 -07007954 MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
Adrian Roos5c6b6222017-11-07 17:36:10 +01007955 boolean alwaysConsumeNavBar, int displayId,
7956 DisplayCutout.ParcelableWrapper displayCutout) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007957 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007958 if (viewAncestor != null) {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08007959 viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
Andrii Kulian44607962017-03-16 11:06:24 -07007960 visibleInsets, stableInsets, outsets, reportDraw, mergedConfiguration,
Adrian Roos5c6b6222017-11-07 17:36:10 +01007961 backDropFrame, forceLayout, alwaysConsumeNavBar, displayId, displayCutout);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007962 }
7963 }
7964
Craig Mautner5702d4d2012-06-30 14:10:16 -07007965 @Override
7966 public void moved(int newX, int newY) {
7967 final ViewRootImpl viewAncestor = mViewAncestor.get();
7968 if (viewAncestor != null) {
7969 viewAncestor.dispatchMoved(newX, newY);
7970 }
7971 }
7972
Igor Murashkina86ab6402013-08-30 12:58:36 -07007973 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007974 public void dispatchAppVisibility(boolean visible) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007975 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007976 if (viewAncestor != null) {
7977 viewAncestor.dispatchAppVisibility(visible);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007978 }
7979 }
7980
Igor Murashkina86ab6402013-08-30 12:58:36 -07007981 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007982 public void dispatchGetNewSurface() {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007983 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007984 if (viewAncestor != null) {
7985 viewAncestor.dispatchGetNewSurface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007986 }
7987 }
7988
Igor Murashkina86ab6402013-08-30 12:58:36 -07007989 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007990 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007991 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007992 if (viewAncestor != null) {
7993 viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007994 }
7995 }
7996
7997 private static int checkCallingPermission(String permission) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007998 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08007999 return ActivityManager.getService().checkPermission(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008000 permission, Binder.getCallingPid(), Binder.getCallingUid());
8001 } catch (RemoteException e) {
8002 return PackageManager.PERMISSION_DENIED;
8003 }
8004 }
8005
Igor Murashkina86ab6402013-08-30 12:58:36 -07008006 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008007 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07008008 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008009 if (viewAncestor != null) {
8010 final View view = viewAncestor.mView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008011 if (view != null) {
8012 if (checkCallingPermission(Manifest.permission.DUMP) !=
8013 PackageManager.PERMISSION_GRANTED) {
8014 throw new SecurityException("Insufficient permissions to invoke"
8015 + " executeCommand() from pid=" + Binder.getCallingPid()
8016 + ", uid=" + Binder.getCallingUid());
8017 }
8018
8019 OutputStream clientStream = null;
8020 try {
8021 clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
8022 ViewDebug.dispatchCommand(view, command, parameters, clientStream);
8023 } catch (IOException e) {
8024 e.printStackTrace();
8025 } finally {
8026 if (clientStream != null) {
8027 try {
8028 clientStream.close();
8029 } catch (IOException e) {
8030 e.printStackTrace();
8031 }
8032 }
8033 }
8034 }
8035 }
8036 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07008037
8038 @Override
Dianne Hackbornffa42482009-09-23 22:20:11 -07008039 public void closeSystemDialogs(String reason) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07008040 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008041 if (viewAncestor != null) {
8042 viewAncestor.dispatchCloseSystemDialogs(reason);
Dianne Hackbornffa42482009-09-23 22:20:11 -07008043 }
8044 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07008045
8046 @Override
Marco Nelissenbf6956b2009-11-09 15:21:13 -08008047 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
8048 boolean sync) {
Dianne Hackborn19382ac2009-09-11 21:13:37 -07008049 if (sync) {
8050 try {
Jeff Brown98365d72012-08-19 20:30:52 -07008051 mWindowSession.wallpaperOffsetsComplete(asBinder());
Dianne Hackborn19382ac2009-09-11 21:13:37 -07008052 } catch (RemoteException e) {
8053 }
8054 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07008055 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008056
Igor Murashkina86ab6402013-08-30 12:58:36 -07008057 @Override
Dianne Hackborn75804932009-10-20 20:15:20 -07008058 public void dispatchWallpaperCommand(String action, int x, int y,
8059 int z, Bundle extras, boolean sync) {
8060 if (sync) {
8061 try {
Jeff Brown98365d72012-08-19 20:30:52 -07008062 mWindowSession.wallpaperCommandComplete(asBinder(), null);
Dianne Hackborn75804932009-10-20 20:15:20 -07008063 } catch (RemoteException e) {
8064 }
8065 }
8066 }
Christopher Tatea53146c2010-09-07 11:57:52 -07008067
8068 /* Drag/drop */
Igor Murashkina86ab6402013-08-30 12:58:36 -07008069 @Override
Christopher Tatea53146c2010-09-07 11:57:52 -07008070 public void dispatchDragEvent(DragEvent event) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07008071 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008072 if (viewAncestor != null) {
8073 viewAncestor.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07008074 }
8075 }
Joe Onorato664644d2011-01-23 17:53:23 -08008076
Igor Murashkina86ab6402013-08-30 12:58:36 -07008077 @Override
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08008078 public void updatePointerIcon(float x, float y) {
8079 final ViewRootImpl viewAncestor = mViewAncestor.get();
8080 if (viewAncestor != null) {
8081 viewAncestor.updatePointerIcon(x, y);
8082 }
8083 }
8084
8085 @Override
Dianne Hackborn9a230e02011-10-06 11:51:27 -07008086 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
8087 int localValue, int localChanges) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07008088 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008089 if (viewAncestor != null) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07008090 viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility,
8091 localValue, localChanges);
Joe Onorato664644d2011-01-23 17:53:23 -08008092 }
8093 }
Dianne Hackborn12d3a942012-04-27 14:16:30 -07008094
Igor Murashkina86ab6402013-08-30 12:58:36 -07008095 @Override
Craig Mautner9c795042014-10-28 19:59:59 -07008096 public void dispatchWindowShown() {
8097 final ViewRootImpl viewAncestor = mViewAncestor.get();
8098 if (viewAncestor != null) {
8099 viewAncestor.dispatchWindowShown();
8100 }
8101 }
Clara Bayarri75e09792015-07-29 16:20:40 +01008102
8103 @Override
Clara Bayarrifcd7e802016-03-10 12:58:18 +00008104 public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
8105 ViewRootImpl viewAncestor = mViewAncestor.get();
8106 if (viewAncestor != null) {
8107 viewAncestor.dispatchRequestKeyboardShortcuts(receiver, deviceId);
8108 }
Clara Bayarri75e09792015-07-29 16:20:40 +01008109 }
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08008110
8111 @Override
8112 public void dispatchPointerCaptureChanged(boolean hasCapture) {
8113 final ViewRootImpl viewAncestor = mViewAncestor.get();
8114 if (viewAncestor != null) {
8115 viewAncestor.dispatchPointerCaptureChanged(hasCapture);
8116 }
8117 }
8118
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008119 }
8120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008121 public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
Mathew Inwoode5ad5982018-08-17 15:07:52 +01008122 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008123 public CalledFromWrongThreadException(String msg) {
8124 super(msg);
8125 }
8126 }
8127
Alan Viverettebea0c7da2015-09-01 16:00:20 -04008128 static HandlerActionQueue getRunQueue() {
8129 HandlerActionQueue rq = sRunQueues.get();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008130 if (rq != null) {
8131 return rq;
8132 }
Alan Viverettebea0c7da2015-09-01 16:00:20 -04008133 rq = new HandlerActionQueue();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008134 sRunQueues.set(rq);
8135 return rq;
8136 }
Romain Guy8506ab42009-06-11 17:35:47 -07008137
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008138 /**
Skuhneb8160872015-09-22 09:51:39 -07008139 * Start a drag resizing which will inform all listeners that a window resize is taking place.
8140 */
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08008141 private void startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets,
Jorim Jaggic39c7b02016-03-24 10:47:07 -07008142 Rect stableInsets, int resizeMode) {
Skuhneb8160872015-09-22 09:51:39 -07008143 if (!mDragResizing) {
8144 mDragResizing = true;
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09008145 if (mUseMTRenderer) {
8146 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
8147 mWindowCallbacks.get(i).onWindowDragResizeStart(
8148 initialBounds, fullscreen, systemInsets, stableInsets, resizeMode);
8149 }
Skuhneb8160872015-09-22 09:51:39 -07008150 }
8151 mFullRedrawNeeded = true;
8152 }
8153 }
8154
8155 /**
8156 * End a drag resize which will inform all listeners that a window resize has ended.
8157 */
8158 private void endDragResizing() {
8159 if (mDragResizing) {
8160 mDragResizing = false;
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09008161 if (mUseMTRenderer) {
8162 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
8163 mWindowCallbacks.get(i).onWindowDragResizeEnd();
8164 }
Skuhneb8160872015-09-22 09:51:39 -07008165 }
8166 mFullRedrawNeeded = true;
8167 }
8168 }
8169
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07008170 private boolean updateContentDrawBounds() {
8171 boolean updated = false;
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09008172 if (mUseMTRenderer) {
8173 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
8174 updated |=
8175 mWindowCallbacks.get(i).onContentDrawn(mWindowAttributes.surfaceInsets.left,
8176 mWindowAttributes.surfaceInsets.top, mWidth, mHeight);
8177 }
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07008178 }
8179 return updated | (mDragResizing && mReportNextDraw);
8180 }
8181
8182 private void requestDrawWindow() {
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09008183 if (!mUseMTRenderer) {
8184 return;
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07008185 }
Tomasz Mikolajewski711f1f92017-07-25 12:45:31 +09008186 mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size());
Jorim Jaggi16b63192016-03-25 18:32:19 -07008187 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
8188 mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw);
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07008189 }
8190 }
8191
Skuhneb8160872015-09-22 09:51:39 -07008192 /**
Jorim Jaggi4846ee32016-01-07 17:39:12 +01008193 * Tells this instance that its corresponding activity has just relaunched. In this case, we
8194 * need to force a relayout of the window to make sure we get the correct bounds from window
8195 * manager.
8196 */
8197 public void reportActivityRelaunched() {
8198 mActivityRelaunched = true;
8199 }
8200
8201 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008202 * Class for managing the accessibility interaction connection
8203 * based on the global accessibility state.
8204 */
8205 final class AccessibilityInteractionConnectionManager
8206 implements AccessibilityStateChangeListener {
Igor Murashkina86ab6402013-08-30 12:58:36 -07008207 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008208 public void onAccessibilityStateChanged(boolean enabled) {
8209 if (enabled) {
8210 ensureConnection();
Phil Weaver05a29822017-09-22 11:03:06 -07008211 if (mAttachInfo.mHasWindowFocus && (mView != null)) {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08008212 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
8213 View focusedView = mView.findFocus();
8214 if (focusedView != null && focusedView != mView) {
8215 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
8216 }
8217 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008218 } else {
8219 ensureNoConnection();
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07008220 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008221 }
8222 }
8223
8224 public void ensureConnection() {
Phil Weaverf00cd142017-03-03 13:44:00 -08008225 final boolean registered = mAttachInfo.mAccessibilityWindowId
8226 != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
Chris Craikcce47eb2014-07-16 15:12:15 -07008227 if (!registered) {
8228 mAttachInfo.mAccessibilityWindowId =
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08008229 mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
Svet Ganov240aed92017-12-02 12:32:23 -08008230 mContext.getPackageName(),
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08008231 new AccessibilityInteractionConnection(ViewRootImpl.this));
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008232 }
8233 }
8234
8235 public void ensureNoConnection() {
Phil Weaverf00cd142017-03-03 13:44:00 -08008236 final boolean registered = mAttachInfo.mAccessibilityWindowId
8237 != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008238 if (registered) {
Phil Weaverf00cd142017-03-03 13:44:00 -08008239 mAttachInfo.mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008240 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
8241 }
8242 }
8243 }
8244
Chris Craikcce47eb2014-07-16 15:12:15 -07008245 final class HighContrastTextManager implements HighTextContrastChangeListener {
8246 HighContrastTextManager() {
John Reck938e8842017-08-24 13:41:59 -07008247 ThreadedRenderer.setHighContrastText(mAccessibilityManager.isHighTextContrastEnabled());
Chris Craikcce47eb2014-07-16 15:12:15 -07008248 }
8249 @Override
8250 public void onHighTextContrastStateChanged(boolean enabled) {
John Reck938e8842017-08-24 13:41:59 -07008251 ThreadedRenderer.setHighContrastText(enabled);
Chris Craikcce47eb2014-07-16 15:12:15 -07008252
8253 // Destroy Displaylists so they can be recreated with high contrast recordings
8254 destroyHardwareResources();
Chris Craikd36a81f2014-07-17 10:16:51 -07008255
8256 // Schedule redraw, which will rerecord + redraw all text
8257 invalidate();
Chris Craikcce47eb2014-07-16 15:12:15 -07008258 }
8259 }
8260
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008261 /**
8262 * This class is an interface this ViewAncestor provides to the
8263 * AccessibilityManagerService to the latter can interact with
8264 * the view hierarchy in this ViewAncestor.
8265 */
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07008266 static final class AccessibilityInteractionConnection
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008267 extends IAccessibilityInteractionConnection.Stub {
Svetoslav Ganov02107852011-10-03 17:06:56 -07008268 private final WeakReference<ViewRootImpl> mViewRootImpl;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008269
Svetoslav Ganovf79f4762011-10-28 15:40:32 -07008270 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) {
8271 mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008272 }
8273
Svetoslav Ganov42138042012-03-20 11:51:39 -07008274 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07008275 public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07008276 Region interactiveRegion, int interactionId,
8277 IAccessibilityInteractionConnectionCallback callback, int flags,
Phil Weaverc2e28932016-12-08 12:29:25 -08008278 int interrogatingPid, long interrogatingTid, MagnificationSpec spec, Bundle args) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07008279 ViewRootImpl viewRootImpl = mViewRootImpl.get();
8280 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07008281 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov02107852011-10-03 17:06:56 -07008282 .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07008283 interactiveRegion, interactionId, callback, flags, interrogatingPid,
Phil Weaverc2e28932016-12-08 12:29:25 -08008284 interrogatingTid, spec, args);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008285 } else {
8286 // We cannot make the call and notify the caller so it does not wait.
8287 try {
8288 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
8289 } catch (RemoteException re) {
8290 /* best effort - ignore */
8291 }
Svetoslav Ganov601ad802011-06-09 14:47:38 -07008292 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008293 }
8294
Svetoslav Ganov42138042012-03-20 11:51:39 -07008295 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07008296 public void performAccessibilityAction(long accessibilityNodeId, int action,
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07008297 Bundle arguments, int interactionId,
8298 IAccessibilityInteractionConnectionCallback callback, int flags,
Svet Ganov7498efd2014-09-03 21:33:00 -07008299 int interrogatingPid, long interrogatingTid) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07008300 ViewRootImpl viewRootImpl = mViewRootImpl.get();
8301 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07008302 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07008303 .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
Svet Ganov7498efd2014-09-03 21:33:00 -07008304 interactionId, callback, flags, interrogatingPid, interrogatingTid);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008305 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008306 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008307 try {
8308 callback.setPerformAccessibilityActionResult(false, interactionId);
8309 } catch (RemoteException re) {
8310 /* best effort - ignore */
8311 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008312 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008313 }
8314
Svetoslav Ganov42138042012-03-20 11:51:39 -07008315 @Override
Svetoslav Ganov80943d82013-01-02 10:25:37 -08008316 public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07008317 String viewId, Region interactiveRegion, int interactionId,
Svetoslav Ganov80943d82013-01-02 10:25:37 -08008318 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07008319 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07008320 ViewRootImpl viewRootImpl = mViewRootImpl.get();
8321 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07008322 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov80943d82013-01-02 10:25:37 -08008323 .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07008324 viewId, interactiveRegion, interactionId, callback, flags,
8325 interrogatingPid, interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008326 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008327 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008328 try {
8329 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
8330 } catch (RemoteException re) {
8331 /* best effort - ignore */
8332 }
8333 }
8334 }
8335
Svetoslav Ganov42138042012-03-20 11:51:39 -07008336 @Override
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008337 public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
Svetoslav9ae9ed22014-09-02 16:36:35 -07008338 Region interactiveRegion, int interactionId,
8339 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07008340 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008341 ViewRootImpl viewRootImpl = mViewRootImpl.get();
8342 if (viewRootImpl != null && viewRootImpl.mView != null) {
8343 viewRootImpl.getAccessibilityInteractionController()
8344 .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
Svetoslav9ae9ed22014-09-02 16:36:35 -07008345 interactiveRegion, interactionId, callback, flags, interrogatingPid,
8346 interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008347 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008348 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08008349 try {
8350 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
8351 } catch (RemoteException re) {
8352 /* best effort - ignore */
8353 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008354 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008355 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008356
Svetoslav Ganov42138042012-03-20 11:51:39 -07008357 @Override
Svetoslav9ae9ed22014-09-02 16:36:35 -07008358 public void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion,
8359 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07008360 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008361 ViewRootImpl viewRootImpl = mViewRootImpl.get();
8362 if (viewRootImpl != null && viewRootImpl.mView != null) {
8363 viewRootImpl.getAccessibilityInteractionController()
Svetoslav9ae9ed22014-09-02 16:36:35 -07008364 .findFocusClientThread(accessibilityNodeId, focusType, interactiveRegion,
8365 interactionId, callback, flags, interrogatingPid, interrogatingTid,
8366 spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07008367 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008368 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008369 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008370 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008371 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008372 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008373 }
8374 }
8375 }
8376
Svetoslav Ganov42138042012-03-20 11:51:39 -07008377 @Override
Svetoslav9ae9ed22014-09-02 16:36:35 -07008378 public void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion,
8379 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07008380 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008381 ViewRootImpl viewRootImpl = mViewRootImpl.get();
8382 if (viewRootImpl != null && viewRootImpl.mView != null) {
8383 viewRootImpl.getAccessibilityInteractionController()
Svetoslav9ae9ed22014-09-02 16:36:35 -07008384 .focusSearchClientThread(accessibilityNodeId, direction, interactiveRegion,
8385 interactionId, callback, flags, interrogatingPid, interrogatingTid,
8386 spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07008387 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008388 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008389 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008390 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008391 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07008392 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008393 }
8394 }
8395 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07008396 }
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07008397
Eugene Susla72c510f2018-01-23 21:12:11 +00008398 private class SendWindowContentChangedAccessibilityEvent implements Runnable {
8399 private int mChangeTypes = 0;
8400
8401 public View mSource;
8402 public long mLastEventTimeMillis;
Eugene Susla9af1378c2018-03-22 16:29:10 -07008403 /**
8404 * Override for {@link AccessibilityEvent#originStackTrace} to provide the stack trace
8405 * of the original {@link #runOrPost} call instead of one for sending the delayed event
8406 * from a looper.
8407 */
8408 public StackTraceElement[] mOrigin;
Eugene Susla72c510f2018-01-23 21:12:11 +00008409
8410 @Override
8411 public void run() {
8412 // Protect against re-entrant code and attempt to do the right thing in the case that
8413 // we're multithreaded.
8414 View source = mSource;
8415 mSource = null;
8416 if (source == null) {
8417 Log.e(TAG, "Accessibility content change has no source");
8418 return;
8419 }
8420 // The accessibility may be turned off while we were waiting so check again.
8421 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
8422 mLastEventTimeMillis = SystemClock.uptimeMillis();
8423 AccessibilityEvent event = AccessibilityEvent.obtain();
8424 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
8425 event.setContentChangeTypes(mChangeTypes);
Eugene Susla9af1378c2018-03-22 16:29:10 -07008426 if (AccessibilityEvent.DEBUG_ORIGIN) event.originStackTrace = mOrigin;
Eugene Susla72c510f2018-01-23 21:12:11 +00008427 source.sendAccessibilityEventUnchecked(event);
8428 } else {
8429 mLastEventTimeMillis = 0;
8430 }
8431 // In any case reset to initial state.
8432 source.resetSubtreeAccessibilityStateChanged();
8433 mChangeTypes = 0;
Eugene Susla9af1378c2018-03-22 16:29:10 -07008434 if (AccessibilityEvent.DEBUG_ORIGIN) mOrigin = null;
Eugene Susla72c510f2018-01-23 21:12:11 +00008435 }
8436
8437 public void runOrPost(View source, int changeType) {
8438 if (mHandler.getLooper() != Looper.myLooper()) {
8439 CalledFromWrongThreadException e = new CalledFromWrongThreadException("Only the "
8440 + "original thread that created a view hierarchy can touch its views.");
8441 // TODO: Throw the exception
8442 Log.e(TAG, "Accessibility content change on non-UI thread. Future Android "
8443 + "versions will throw an exception.", e);
8444 // Attempt to recover. This code does not eliminate the thread safety issue, but
8445 // it should force any issues to happen near the above log.
8446 mHandler.removeCallbacks(this);
8447 if (mSource != null) {
8448 // Dispatch whatever was pending. It's still possible that the runnable started
8449 // just before we removed the callbacks, and bad things will happen, but at
8450 // least they should happen very close to the logged error.
8451 run();
8452 }
8453 }
8454 if (mSource != null) {
8455 // If there is no common predecessor, then mSource points to
8456 // a removed view, hence in this case always prefer the source.
8457 View predecessor = getCommonPredecessor(mSource, source);
Eugene Susla9af1378c2018-03-22 16:29:10 -07008458 if (predecessor != null) {
8459 predecessor = predecessor.getSelfOrParentImportantForA11y();
8460 }
Eugene Susla72c510f2018-01-23 21:12:11 +00008461 mSource = (predecessor != null) ? predecessor : source;
8462 mChangeTypes |= changeType;
8463 return;
8464 }
8465 mSource = source;
8466 mChangeTypes = changeType;
Eugene Susla9af1378c2018-03-22 16:29:10 -07008467 if (AccessibilityEvent.DEBUG_ORIGIN) {
8468 mOrigin = Thread.currentThread().getStackTrace();
8469 }
Eugene Susla72c510f2018-01-23 21:12:11 +00008470 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
8471 final long minEventIntevalMillis =
8472 ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
8473 if (timeSinceLastMillis >= minEventIntevalMillis) {
8474 removeCallbacksAndRun();
8475 } else {
8476 mHandler.postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
8477 }
8478 }
8479
8480 public void removeCallbacksAndRun() {
8481 mHandler.removeCallbacks(this);
8482 run();
8483 }
8484 }
8485
Evan Rosky4807ae22018-03-22 16:04:15 -07008486 private static class UnhandledKeyManager {
Evan Rosky4807ae22018-03-22 16:04:15 -07008487 // This is used to ensure that unhandled events are only dispatched once. We attempt
Evan Rosky5e29c072017-06-02 17:31:22 -07008488 // to dispatch more than once in order to achieve a certain order. Specifically, if we
Evan Rosky4807ae22018-03-22 16:04:15 -07008489 // are in an Activity or Dialog (and have a Window.Callback), the unhandled events should
Evan Roskycd80e612018-05-17 17:46:09 -07008490 // be dispatched after the view hierarchy, but before the Callback. However, if we aren't
Evan Rosky4807ae22018-03-22 16:04:15 -07008491 // in an activity, we still want unhandled keys to be dispatched.
Evan Roskycd80e612018-05-17 17:46:09 -07008492 private boolean mDispatched = true;
Evan Rosky5e29c072017-06-02 17:31:22 -07008493
Evan Roskycd80e612018-05-17 17:46:09 -07008494 // Keeps track of which Views have unhandled key focus for which keys. This doesn't
8495 // include modifiers.
8496 private final SparseArray<WeakReference<View>> mCapturedKeys = new SparseArray<>();
Evan Rosky5e29c072017-06-02 17:31:22 -07008497
Evan Roskycd80e612018-05-17 17:46:09 -07008498 // The current receiver. This value is transient and used between the pre-dispatch and
8499 // pre-view phase to ensure that other input-stages don't interfere with tracking.
8500 private WeakReference<View> mCurrentReceiver = null;
8501
8502 boolean dispatch(View root, KeyEvent event) {
8503 if (mDispatched) {
8504 return false;
Evan Rosky5e29c072017-06-02 17:31:22 -07008505 }
Evan Roskycd80e612018-05-17 17:46:09 -07008506 View consumer;
8507 try {
8508 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "UnhandledKeyEvent dispatch");
8509 mDispatched = true;
8510
8511 consumer = root.dispatchUnhandledKeyEvent(event);
8512
8513 // If an unhandled listener handles one, then keep track of it so that the
8514 // consuming view is first to receive its repeats and release as well.
8515 if (event.getAction() == KeyEvent.ACTION_DOWN) {
8516 int keycode = event.getKeyCode();
8517 if (consumer != null && !KeyEvent.isModifierKey(keycode)) {
8518 mCapturedKeys.put(keycode, new WeakReference<>(consumer));
8519 }
8520 }
8521 } finally {
8522 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
8523 }
8524 return consumer != null;
8525 }
8526
8527 /**
8528 * Called before the event gets dispatched to anything
8529 */
8530 void preDispatch(KeyEvent event) {
8531 // Always clean-up 'up' events since it's possible for earlier dispatch stages to
8532 // consume them without consuming the corresponding 'down' event.
8533 mCurrentReceiver = null;
Evan Rosky5e29c072017-06-02 17:31:22 -07008534 if (event.getAction() == KeyEvent.ACTION_UP) {
Evan Roskycd80e612018-05-17 17:46:09 -07008535 int idx = mCapturedKeys.indexOfKey(event.getKeyCode());
8536 if (idx >= 0) {
8537 mCurrentReceiver = mCapturedKeys.valueAt(idx);
8538 mCapturedKeys.removeAt(idx);
8539 }
Evan Rosky5e29c072017-06-02 17:31:22 -07008540 }
8541 }
8542
Evan Roskycd80e612018-05-17 17:46:09 -07008543 /**
8544 * Called before the event gets dispatched to the view hierarchy
8545 * @return {@code true} if an unhandled handler has focus and consumed the event
8546 */
8547 boolean preViewDispatch(KeyEvent event) {
8548 mDispatched = false;
8549 if (mCurrentReceiver == null) {
8550 mCurrentReceiver = mCapturedKeys.get(event.getKeyCode());
8551 }
Evan Rosky4807ae22018-03-22 16:04:15 -07008552 if (mCurrentReceiver != null) {
8553 View target = mCurrentReceiver.get();
Evan Roskycd80e612018-05-17 17:46:09 -07008554 if (event.getAction() == KeyEvent.ACTION_UP) {
Evan Rosky4807ae22018-03-22 16:04:15 -07008555 mCurrentReceiver = null;
Evan Rosky5e29c072017-06-02 17:31:22 -07008556 }
8557 if (target != null && target.isAttachedToWindow()) {
Evan Rosky4807ae22018-03-22 16:04:15 -07008558 target.onUnhandledKeyEvent(event);
Evan Rosky5e29c072017-06-02 17:31:22 -07008559 }
8560 // consume anyways so that we don't feed uncaptured key events to other views
8561 return true;
8562 }
Evan Roskycd80e612018-05-17 17:46:09 -07008563 return false;
Evan Rosky5e29c072017-06-02 17:31:22 -07008564 }
8565 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008566}