blob: 65f0caa0ef243098e001e85e53bf8d48e1a7cdfd [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
Jorim Jaggic39c7b02016-03-24 10:47:07 -070019import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
20import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -080021import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
Jorim Jaggi2e95a482016-01-14 17:36:55 -080022import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
Chong Zhangf6525ce2016-01-14 17:09:56 -080023import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
24import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
25import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -080026
Romain Guy6b7bd242010-10-06 19:49:23 -070027import android.Manifest;
Chet Haasecca2c982011-05-20 14:34:18 -070028import android.animation.LayoutTransition;
Romain Guy6b7bd242010-10-06 19:49:23 -070029import android.app.ActivityManagerNative;
30import android.content.ClipDescription;
31import android.content.ComponentCallbacks;
32import android.content.Context;
33import android.content.pm.PackageManager;
34import android.content.res.CompatibilityInfo;
35import android.content.res.Configuration;
36import android.content.res.Resources;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.graphics.Canvas;
Alan Viverettefed3f722013-11-14 14:48:20 -080038import android.graphics.Matrix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.graphics.PixelFormat;
Christopher Tate2c095f32010-10-04 14:13:40 -070040import android.graphics.Point;
Christopher Tatea53146c2010-09-07 11:57:52 -070041import android.graphics.PointF;
Romain Guy6b7bd242010-10-06 19:49:23 -070042import android.graphics.PorterDuff;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.graphics.Rect;
44import android.graphics.Region;
Doris Liu718cd3e2016-05-17 16:50:31 -070045import android.graphics.drawable.AnimatedVectorDrawable;
Svetoslav Ganov42138042012-03-20 11:51:39 -070046import android.graphics.drawable.Drawable;
Jeff Brownd912e1f2014-04-11 18:46:22 -070047import android.hardware.display.DisplayManager;
48import android.hardware.display.DisplayManager.DisplayListener;
Jun Mukai347e5d42015-12-03 01:13:31 -080049import android.hardware.input.InputManager;
Romain Guy6b7bd242010-10-06 19:49:23 -070050import android.media.AudioManager;
51import android.os.Binder;
Michael Wright5bd69e62015-05-14 14:48:08 +010052import android.os.Build;
Romain Guy6b7bd242010-10-06 19:49:23 -070053import android.os.Bundle;
54import android.os.Debug;
55import android.os.Handler;
Romain Guy6b7bd242010-10-06 19:49:23 -070056import android.os.Looper;
57import android.os.Message;
58import android.os.ParcelFileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.os.Process;
Romain Guy6b7bd242010-10-06 19:49:23 -070060import android.os.RemoteException;
Romain Guy6b7bd242010-10-06 19:49:23 -070061import android.os.SystemClock;
Romain Guy59a12ca2011-06-09 17:48:21 -070062import android.os.SystemProperties;
Jeff Brown481c1572012-03-09 14:41:15 -080063import android.os.Trace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import android.util.AndroidRuntimeException;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070065import android.util.DisplayMetrics;
Romain Guy6b7bd242010-10-06 19:49:23 -070066import android.util.Log;
Chet Haase949dbf72010-08-11 18:41:06 -070067import android.util.Slog;
John Reckba6adf62015-02-19 14:36:50 -080068import android.util.TimeUtils;
Dianne Hackborn711e62a2010-11-29 16:38:22 -080069import android.util.TypedValue;
John Reck44fd8d22014-02-26 11:00:11 -080070import android.view.Surface.OutOfResourcesException;
Jeff Browna175a5b2012-02-15 19:18:31 -080071import android.view.View.AttachInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.view.View.MeasureSpec;
svetoslavganov75986cf2009-05-14 22:28:01 -070073import android.view.accessibility.AccessibilityEvent;
74import android.view.accessibility.AccessibilityManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070075import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
Chris Craikcce47eb2014-07-16 15:12:15 -070076import android.view.accessibility.AccessibilityManager.HighTextContrastChangeListener;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070077import android.view.accessibility.AccessibilityNodeInfo;
Alan Viverette25acc7e2015-05-19 11:32:08 -070078import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
Svetoslav Ganov02107852011-10-03 17:06:56 -070079import android.view.accessibility.AccessibilityNodeProvider;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070080import android.view.accessibility.IAccessibilityInteractionConnection;
81import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
Dianne Hackborn0f761d62010-11-30 22:06:10 -080082import android.view.animation.AccelerateDecelerateInterpolator;
83import android.view.animation.Interpolator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084import android.view.inputmethod.InputMethodManager;
85import android.widget.Scroller;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070086
Svetoslav Ganov42138042012-03-20 11:51:39 -070087import com.android.internal.R;
Jorim Jaggi16b63192016-03-25 18:32:19 -070088import com.android.internal.annotations.GuardedBy;
Clara Bayarri75e09792015-07-29 16:20:40 +010089import com.android.internal.os.IResultReceiver;
Svetoslav Ganov758143e2012-08-06 16:40:27 -070090import com.android.internal.os.SomeArgs;
Adam Powell6711f3b2015-05-06 15:57:09 -070091import com.android.internal.policy.PhoneFallbackEventHandler;
Romain Guy6b7bd242010-10-06 19:49:23 -070092import com.android.internal.view.BaseSurfaceHolder;
Romain Guy6b7bd242010-10-06 19:49:23 -070093import com.android.internal.view.RootViewSurfaceTaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094
Jeff Brown5182c782013-10-15 20:31:52 -070095import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096import java.io.IOException;
97import java.io.OutputStream;
Jeff Brown5182c782013-10-15 20:31:52 -070098import java.io.PrintWriter;
Romain Guy6b7bd242010-10-06 19:49:23 -070099import java.lang.ref.WeakReference;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100import java.util.ArrayList;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700101import java.util.HashSet;
Jorim Jaggic39c7b02016-03-24 10:47:07 -0700102import java.util.concurrent.CountDownLatch;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104/**
105 * The top of a view hierarchy, implementing the needed protocol between View
106 * and the WindowManager. This is for the most part an internal implementation
Jeff Brown98365d72012-08-19 20:30:52 -0700107 * detail of {@link WindowManagerGlobal}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 *
109 * {@hide}
110 */
Romain Guy812ccbe2010-06-01 14:07:24 -0700111@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
Jeff Browna175a5b2012-02-15 19:18:31 -0800112public final class ViewRootImpl implements ViewParent,
John Reck51aaf902015-12-02 15:08:07 -0800113 View.AttachInfo.Callbacks, ThreadedRenderer.HardwareDrawCallbacks {
Dianne Hackborn70a3f672011-08-08 14:32:41 -0700114 private static final String TAG = "ViewRootImpl";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 private static final boolean DBG = false;
Romain Guy812ccbe2010-06-01 14:07:24 -0700116 private static final boolean LOCAL_LOGV = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 /** @noinspection PointlessBooleanExpression*/
118 private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
119 private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800120 private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
122 private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
123 private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
124 private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700125 private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
Chet Haase2f2022a2011-10-11 06:41:59 -0700126 private static final boolean DEBUG_FPS = false;
Michael Wright06a79252014-05-05 17:45:29 -0700127 private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV;
Chong Zhang44aabe42016-05-10 11:20:14 -0700128 private static final boolean DEBUG_KEEP_SCREEN_ON = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129
Romain Guy59a12ca2011-06-09 17:48:21 -0700130 /**
Skuhneb8160872015-09-22 09:51:39 -0700131 * Set to false if we do not want to use the multi threaded renderer. Note that by disabling
132 * this, WindowCallbacks will not fire.
133 */
134 private static final boolean USE_MT_RENDERER = true;
135
136 /**
Romain Guy59a12ca2011-06-09 17:48:21 -0700137 * Set this system property to true to force the view hierarchy to render
138 * at 60 Hz. This can be used to measure the potential framerate.
139 */
Romain Guye9bc11f2013-05-23 12:47:26 -0700140 private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering";
Michael Chan53071d62009-05-13 17:29:48 -0700141
Griff Hazena0938022015-03-13 10:01:41 -0700142 // properties used by emulator to determine display shape
Griff Hazena0938022015-03-13 10:01:41 -0700143 public static final String PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX =
144 "ro.emu.win_outset_bottom_px";
Michael Kolb437d3132014-06-20 13:28:44 -0700145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 /**
147 * Maximum time we allow the user to roll the trackball enough to generate
148 * a key event, before resetting the counters.
149 */
150 static final int MAX_TRACKBALL_DELAY = 250;
151
Alan Viverettebea0c7da2015-09-01 16:00:20 -0400152 static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153
Skuhneb8160872015-09-22 09:51:39 -0700154 static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList();
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800155 static boolean sFirstDrawComplete = false;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700156
Skuhneb8160872015-09-22 09:51:39 -0700157 static final ArrayList<ComponentCallbacks> sConfigCallbacks = new ArrayList();
Romain Guy59a12ca2011-06-09 17:48:21 -0700158
Jorim Jaggi16b63192016-03-25 18:32:19 -0700159 /**
160 * This list must only be modified by the main thread, so a lock is only needed when changing
161 * the list or when accessing the list from a non-main thread.
162 */
163 @GuardedBy("mWindowCallbacks")
164 final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList<>();
Jeff Brownf9e989d2013-04-04 23:04:03 -0700165 final Context mContext;
Jeff Brown98365d72012-08-19 20:30:52 -0700166 final IWindowSession mWindowSession;
167 final Display mDisplay;
Jeff Brownd912e1f2014-04-11 18:46:22 -0700168 final DisplayManager mDisplayManager;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800169 final String mBasePackageName;
Jeff Brown98365d72012-08-19 20:30:52 -0700170
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 final int[] mTmpLocation = new int[2];
Romain Guy8506ab42009-06-11 17:35:47 -0700172
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800173 final TypedValue mTmpValue = new TypedValue();
Jeff Brownf9e989d2013-04-04 23:04:03 -0700174
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175 final Thread mThread;
176
177 final WindowLeaked mLocation;
178
179 final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
180
181 final W mWindow;
182
Dianne Hackborn180c4842011-09-13 12:39:25 -0700183 final int mTargetSdkVersion;
184
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700185 int mSeq;
186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 View mView;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700188
189 View mAccessibilityFocusedHost;
190 AccessibilityNodeInfo mAccessibilityFocusedVirtualView;
191
Jun Mukai347e5d42015-12-03 01:13:31 -0800192 // The view which captures mouse input, or null when no one is capturing.
193 View mCapturingView;
194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 int mViewVisibility;
196 boolean mAppVisible = true;
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800197 // For recents to freeform transition we need to keep drawing after the app receives information
198 // that it became invisible. This will ignore that information and depend on the decor view
199 // visibility to control drawing. The decor view visibility will get adjusted when the app get
200 // stopped and that's when the app will stop drawing further frames.
201 private boolean mForceDecorViewVisibility = false;
Dianne Hackborn180c4842011-09-13 12:39:25 -0700202 int mOrigWindowType = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203
Alan Viverette64bf97a2015-09-18 16:42:00 -0400204 /** Whether the window had focus during the most recent traversal. */
205 boolean mHadWindowFocus;
206
207 /**
208 * Whether the window lost focus during a previous traversal and has not
209 * yet gained it back. Used to determine whether a WINDOW_STATE_CHANGE
210 * accessibility events should be sent during traversal.
211 */
212 boolean mLostWindowFocus;
213
Dianne Hackbornce418e62011-03-01 14:31:38 -0800214 // Set to true if the owner of this window is in the stopped state,
215 // so the window should no longer be active.
216 boolean mStopped = false;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700217
Daniel Koulomzin087ae472015-12-16 17:52:25 -0500218 // Set to true if the owner of this window is in ambient mode,
219 // which means it won't receive input events.
220 boolean mIsAmbientMode = false;
221
George Mount41725de2015-04-09 08:23:05 -0700222 // Set to true to stop input during an Activity Transition.
223 boolean mPausedForTransition = false;
224
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700225 boolean mLastInCompatMode = false;
226
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700227 SurfaceHolder.Callback2 mSurfaceHolderCallback;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700228 BaseSurfaceHolder mSurfaceHolder;
229 boolean mIsCreating;
230 boolean mDrawingAllowed;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700231
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232 final Region mTransparentRegion;
233 final Region mPreviousTransparentRegion;
234
235 int mWidth;
236 int mHeight;
Romain Guy7d7b5492011-01-24 16:33:45 -0800237 Rect mDirty;
Romain Guybb93d552009-03-24 21:04:15 -0700238 boolean mIsAnimating;
Romain Guy8506ab42009-06-11 17:35:47 -0700239
Chong Zhang0275e392015-09-17 10:41:44 -0700240 private boolean mDragResizing;
Jorim Jaggic39c7b02016-03-24 10:47:07 -0700241 private boolean mInvalidateRootRequested;
Jorim Jaggi4846ee32016-01-07 17:39:12 +0100242 private int mResizeMode;
Chong Zhang0275e392015-09-17 10:41:44 -0700243 private int mCanvasOffsetX;
244 private int mCanvasOffsetY;
Jorim Jaggi4846ee32016-01-07 17:39:12 +0100245 private boolean mActivityRelaunched;
Chong Zhang0275e392015-09-17 10:41:44 -0700246
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700247 CompatibilityInfo.Translator mTranslator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248
249 final View.AttachInfo mAttachInfo;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700250 InputChannel mInputChannel;
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -0700251 InputQueue.Callback mInputQueueCallback;
252 InputQueue mInputQueue;
Joe Onorato86f67862010-11-05 18:57:34 -0700253 FallbackEventHandler mFallbackEventHandler;
Jeff Brown96e942d2011-11-30 19:55:01 -0800254 Choreographer mChoreographer;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256 final Rect mTempRect; // used in the transaction to not thrash the heap.
257 final Rect mVisRect; // used to retrieve visible rect of focused view.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258
259 boolean mTraversalScheduled;
Jeff Browne0dbd002012-02-15 19:34:58 -0800260 int mTraversalBarrier;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 boolean mWillDrawSoon;
Craig Mautnerdf2390a2012-08-29 20:59:22 -0700262 /** Set to true while in performTraversals for detecting when die(true) is called from internal
263 * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */
264 boolean mIsInTraversal;
Adrian Roosfa104232014-06-20 16:10:14 -0700265 boolean mApplyInsetsRequested;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 boolean mLayoutRequested;
267 boolean mFirst;
268 boolean mReportNextDraw;
269 boolean mFullRedrawNeeded;
270 boolean mNewSurfaceNeeded;
271 boolean mHasHadWindowFocus;
272 boolean mLastWasImTarget;
Jorim Jaggia4a58ef2016-01-27 02:10:08 -0800273 boolean mForceNextWindowRelayout;
Chong Zhang8dbd9ad2015-10-09 10:06:11 -0700274 CountDownLatch mWindowDrawCountDown;
Jorim Jaggi827e0fa2015-05-07 11:41:41 -0700275
Romain Guy1f59e5c2012-05-06 14:11:16 -0700276 boolean mIsDrawing;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700277 int mLastSystemUiVisibility;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700278 int mClientWindowLayoutFlags;
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800279 boolean mLastOverscanRequested;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800280
281 // Pool of queued input events.
282 private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
283 private QueuedInputEvent mQueuedInputEventPool;
284 private int mQueuedInputEventPoolSize;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800285
Michael Wrightc8a7e542013-03-20 17:58:33 -0700286 /* Input event queue.
Jeff Brownf9e989d2013-04-04 23:04:03 -0700287 * Pending input events are input events waiting to be delivered to the input stages
288 * and handled by the application.
Michael Wrightc8a7e542013-03-20 17:58:33 -0700289 */
290 QueuedInputEvent mPendingInputEventHead;
291 QueuedInputEvent mPendingInputEventTail;
Michael Wright95ae9422013-03-14 10:58:50 -0700292 int mPendingInputEventCount;
Jeff Brown96e942d2011-11-30 19:55:01 -0800293 boolean mProcessInputEventsScheduled;
Michael Wright9d744c72014-02-18 21:27:42 -0800294 boolean mUnbufferedInputDispatch;
Michael Wright95ae9422013-03-14 10:58:50 -0700295 String mPendingInputEventQueueLengthCounterName = "pq";
Jeff Brownf9e989d2013-04-04 23:04:03 -0700296
297 InputStage mFirstInputStage;
298 InputStage mFirstPostImeInputStage;
Michael Wright899d7052014-04-23 17:23:39 -0700299 InputStage mSyntheticInputStage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300
301 boolean mWindowAttributesChanged = false;
Romain Guyf21c9b02011-09-06 16:56:54 -0700302 int mWindowAttributesChangesFlag = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303
304 // These can be accessed by any thread, must be protected with a lock.
Mathias Agopian5583dc62009-07-09 16:28:11 -0700305 // Surface can never be reassigned or cleared (use Surface.clear()).
John Reckb13de072014-11-19 16:33:47 -0800306 final Surface mSurface = new Surface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307
308 boolean mAdded;
309 boolean mAddedTouchMode;
310
Craig Mautner48d0d182013-06-11 07:53:06 -0700311 final DisplayAdjustments mDisplayAdjustments;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313 // These are accessed by multiple threads.
314 final Rect mWinFrame; // frame given by window manager.
315
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800316 final Rect mPendingOverscanInsets = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317 final Rect mPendingVisibleInsets = new Rect();
Adrian Roosfa104232014-06-20 16:10:14 -0700318 final Rect mPendingStableInsets = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 final Rect mPendingContentInsets = new Rect();
Filip Gruszczynski2217f612015-05-26 11:32:08 -0700320 final Rect mPendingOutsets = new Rect();
Jorim Jaggia7262a82015-11-03 15:15:40 +0100321 final Rect mPendingBackDropFrame = new Rect();
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -0800322 boolean mPendingAlwaysConsumeNavBar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800323 final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
324 = new ViewTreeObserver.InternalInsetsInfo();
325
Adrian Roosfa104232014-06-20 16:10:14 -0700326 final Rect mDispatchContentInsets = new Rect();
327 final Rect mDispatchStableInsets = new Rect();
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700328
Filip Gruszczynski954289d2015-02-26 15:46:47 -0800329 private WindowInsets mLastWindowInsets;
330
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700331 final Configuration mLastConfiguration = new Configuration();
332 final Configuration mPendingConfiguration = new Configuration();
Romain Guy59a12ca2011-06-09 17:48:21 -0700333
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 boolean mScrollMayChange;
335 int mSoftInputMode;
Svetoslav Ganov149567f2013-01-08 15:23:34 -0800336 WeakReference<View> mLastScrolledFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 int mScrollY;
338 int mCurScrollY;
339 Scroller mScroller;
John Recke56e9df2014-02-21 15:45:10 -0800340 static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
Chet Haasecca2c982011-05-20 14:34:18 -0700341 private ArrayList<LayoutTransition> mPendingTransitions;
Romain Guy8506ab42009-06-11 17:35:47 -0700342
Romain Guy8506ab42009-06-11 17:35:47 -0700343 final ViewConfiguration mViewConfiguration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344
Christopher Tatea53146c2010-09-07 11:57:52 -0700345 /* Drag/drop */
346 ClipDescription mDragDescription;
347 View mCurrentDragView;
Christopher Tate7fb8b562011-01-20 13:46:41 -0800348 volatile Object mLocalDragState;
Christopher Tatea53146c2010-09-07 11:57:52 -0700349 final PointF mDragPoint = new PointF();
Christopher Tate2c095f32010-10-04 14:13:40 -0700350 final PointF mLastTouchPoint = new PointF();
Vladislav Kaznacheevba761122016-01-22 12:09:45 -0800351 int mLastTouchSource;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700352
353 private boolean mProfileRendering;
Romain Guyd0750312012-11-29 11:34:43 -0800354 private Choreographer.FrameCallback mRenderProfiler;
355 private boolean mRenderProfilingEnabled;
Christopher Tatea53146c2010-09-07 11:57:52 -0700356
Chet Haase2f2022a2011-10-11 06:41:59 -0700357 // Variables to track frames per second, enabled via DEBUG_FPS flag
358 private long mFpsStartTime = -1;
359 private long mFpsPrevTime = -1;
360 private int mFpsNumFrames;
361
Michael Wrightf9d9ce772016-05-13 17:44:16 +0100362 private int mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
Jun Mukaid4eaef72015-10-30 15:54:33 -0700363 private PointerIcon mCustomPointerIcon = null;
Jun Mukai1db53972015-09-11 18:08:31 -0700364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 /**
366 * see {@link #playSoundEffect(int)}
367 */
368 AudioManager mAudioManager;
369
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700370 final AccessibilityManager mAccessibilityManager;
371
Gilles Debunne5ac84422011-10-19 09:35:58 -0700372 AccessibilityInteractionController mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700373
374 AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager;
Chris Craikcce47eb2014-07-16 15:12:15 -0700375 HighContrastTextManager mHighContrastTextManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700376
Svetoslav Ganova0156172011-06-26 17:55:44 -0700377 SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700378
Svetoslav Ganov42138042012-03-20 11:51:39 -0700379 HashSet<View> mTempHashSet;
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800380
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700381 private final int mDensity;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700382 private final int mNoncompatDensity;
Adam Powellb08013c2010-09-16 16:28:11 -0700383
Chet Haase97140572012-09-13 14:56:47 -0700384 private boolean mInLayout = false;
385 ArrayList<View> mLayoutRequesters = new ArrayList<View>();
386 boolean mHandlingLayoutInLayoutRequest = false;
387
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700388 private int mViewLayoutDirectionInitial;
Chet Haase97140572012-09-13 14:56:47 -0700389
Craig Mautner8f303ad2013-06-14 11:32:22 -0700390 /** Set to true once doDie() has been called. */
391 private boolean mRemoved;
392
Robert Carr1bccabf2016-04-28 13:27:08 -0700393 private boolean mNeedsHwRendererSetup;
394
Jeff Brown21bc5c92011-02-28 18:27:14 -0800395 /**
396 * Consistency verifier for debugging purposes.
397 */
398 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
399 InputEventConsistencyVerifier.isInstrumentationEnabled() ?
400 new InputEventConsistencyVerifier(this, 0) : null;
401
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700402 static final class SystemUiVisibilityInfo {
403 int seq;
404 int globalVisibility;
405 int localValue;
406 int localChanges;
407 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700408
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800409 private String mTag = TAG;
410
Jeff Brown98365d72012-08-19 20:30:52 -0700411 public ViewRootImpl(Context context, Display display) {
Jeff Brownf9e989d2013-04-04 23:04:03 -0700412 mContext = context;
413 mWindowSession = WindowManagerGlobal.getWindowSession();
Jeff Brown98365d72012-08-19 20:30:52 -0700414 mDisplay = display;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800415 mBasePackageName = context.getBasePackageName();
Jeff Brown98365d72012-08-19 20:30:52 -0700416
Craig Mautner48d0d182013-06-11 07:53:06 -0700417 mDisplayAdjustments = display.getDisplayAdjustments();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700418
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 mThread = Thread.currentThread();
420 mLocation = new WindowLeaked(null);
421 mLocation.fillInStackTrace();
422 mWidth = -1;
423 mHeight = -1;
424 mDirty = new Rect();
425 mTempRect = new Rect();
426 mVisRect = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 mWinFrame = new Rect();
Romain Guyfb8b7632010-08-23 21:05:08 -0700428 mWindow = new W(this);
Dianne Hackborn180c4842011-09-13 12:39:25 -0700429 mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 mViewVisibility = View.GONE;
431 mTransparentRegion = new Region();
432 mPreviousTransparentRegion = new Region();
433 mFirst = true; // true for the first time the view is added
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434 mAdded = false;
Chris Craikcce47eb2014-07-16 15:12:15 -0700435 mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700436 mAccessibilityManager = AccessibilityManager.getInstance(context);
437 mAccessibilityInteractionConnectionManager =
438 new AccessibilityInteractionConnectionManager();
Svetoslav Ganov00d0c142012-02-24 11:30:49 -0800439 mAccessibilityManager.addAccessibilityStateChangeListener(
440 mAccessibilityInteractionConnectionManager);
Chris Craikcce47eb2014-07-16 15:12:15 -0700441 mHighContrastTextManager = new HighContrastTextManager();
442 mAccessibilityManager.addHighTextContrastStateChangeListener(
443 mHighContrastTextManager);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 mViewConfiguration = ViewConfiguration.get(context);
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700445 mDensity = context.getResources().getDisplayMetrics().densityDpi;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700446 mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
Jorim Jaggib10e33f2015-02-04 21:57:40 +0100447 mFallbackEventHandler = new PhoneFallbackEventHandler(context);
Jeff Brown96e942d2011-11-30 19:55:01 -0800448 mChoreographer = Choreographer.getInstance();
Jeff Brownd912e1f2014-04-11 18:46:22 -0700449 mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
Dianne Hackborna53de062012-05-08 18:53:51 -0700450 loadSystemProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451 }
452
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800453 public static void addFirstDrawHandler(Runnable callback) {
454 synchronized (sFirstDrawHandlers) {
455 if (!sFirstDrawComplete) {
456 sFirstDrawHandlers.add(callback);
457 }
458 }
459 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700460
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800461 public static void addConfigCallback(ComponentCallbacks callback) {
462 synchronized (sConfigCallbacks) {
463 sConfigCallbacks.add(callback);
464 }
465 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700466
Chong Zhangdcee1de2015-10-06 10:26:00 -0700467 public void addWindowCallbacks(WindowCallbacks callback) {
Skuhneb8160872015-09-22 09:51:39 -0700468 if (USE_MT_RENDERER) {
Chong Zhangdcee1de2015-10-06 10:26:00 -0700469 synchronized (mWindowCallbacks) {
470 mWindowCallbacks.add(callback);
Skuhneb8160872015-09-22 09:51:39 -0700471 }
472 }
473 }
474
Chong Zhangdcee1de2015-10-06 10:26:00 -0700475 public void removeWindowCallbacks(WindowCallbacks callback) {
Skuhneb8160872015-09-22 09:51:39 -0700476 if (USE_MT_RENDERER) {
Chong Zhangdcee1de2015-10-06 10:26:00 -0700477 synchronized (mWindowCallbacks) {
478 mWindowCallbacks.remove(callback);
Skuhneb8160872015-09-22 09:51:39 -0700479 }
480 }
481 }
482
Chong Zhang8dbd9ad2015-10-09 10:06:11 -0700483 public void reportDrawFinish() {
484 if (mWindowDrawCountDown != null) {
485 mWindowDrawCountDown.countDown();
486 }
487 }
488
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 // FIXME for perf testing only
490 private boolean mProfile = false;
491
492 /**
493 * Call this to profile the next traversal call.
494 * FIXME for perf testing only. Remove eventually
495 */
496 public void profile() {
497 mProfile = true;
498 }
499
500 /**
501 * Indicates whether we are in touch mode. Calling this method triggers an IPC
502 * call and should be avoided whenever possible.
503 *
504 * @return True, if the device is in touch mode, false otherwise.
505 *
506 * @hide
507 */
508 static boolean isInTouchMode() {
Jeff Brown98365d72012-08-19 20:30:52 -0700509 IWindowSession windowSession = WindowManagerGlobal.peekWindowSession();
510 if (windowSession != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 try {
Jeff Brown98365d72012-08-19 20:30:52 -0700512 return windowSession.getInTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 } catch (RemoteException e) {
514 }
515 }
516 return false;
517 }
518
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519 /**
Robert Carrb2594852016-04-25 16:21:13 -0700520 * Notifies us that our child has been rebuilt, following
521 * a window preservation operation. In these cases we
522 * keep the same DecorView, but the activity controlling it
523 * is a different instance, and we need to update our
524 * callbacks.
525 *
526 * @hide
527 */
528 public void notifyChildRebuilt() {
529 if (mView instanceof RootViewSurfaceTaker) {
530 mSurfaceHolderCallback =
531 ((RootViewSurfaceTaker)mView).willYouTakeTheSurface();
532 if (mSurfaceHolderCallback != null) {
533 mSurfaceHolder = new TakenSurfaceHolder();
534 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
535 } else {
536 mSurfaceHolder = null;
537 }
538
539 mInputQueueCallback =
540 ((RootViewSurfaceTaker)mView).willYouTakeTheInputQueue();
541 if (mInputQueueCallback != null) {
542 mInputQueueCallback.onInputQueueCreated(mInputQueue);
543 }
544 }
545 }
546
547 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 * We have one child
549 */
Romain Guye4d01122010-06-16 18:44:05 -0700550 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 synchronized (this) {
552 if (mView == null) {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700553 mView = view;
Jeff Brownd912e1f2014-04-11 18:46:22 -0700554
555 mAttachInfo.mDisplayState = mDisplay.getState();
556 mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
557
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700558 mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
Joe Onorato86f67862010-11-05 18:57:34 -0700559 mFallbackEventHandler.setView(view);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700560 mWindowAttributes.copyFrom(attrs);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800561 if (mWindowAttributes.packageName == null) {
562 mWindowAttributes.packageName = mBasePackageName;
563 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700564 attrs = mWindowAttributes;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800565 setTag();
Chong Zhang4ffc3182016-05-04 15:06:02 -0700566
Chong Zhang44aabe42016-05-10 11:20:14 -0700567 if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
568 & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
Chong Zhang4ffc3182016-05-04 15:06:02 -0700569 && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) {
Chong Zhang44aabe42016-05-10 11:20:14 -0700570 Slog.d(mTag, "setView: FLAG_KEEP_SCREEN_ON changed from true to false!");
Chong Zhang4ffc3182016-05-04 15:06:02 -0700571 }
Dianne Hackborn9d090892012-06-11 18:35:41 -0700572 // Keep track of the actual window flags supplied by the client.
573 mClientWindowLayoutFlags = attrs.flags;
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700574
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700575 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700576
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700577 if (view instanceof RootViewSurfaceTaker) {
578 mSurfaceHolderCallback =
579 ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
580 if (mSurfaceHolderCallback != null) {
581 mSurfaceHolder = new TakenSurfaceHolder();
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700582 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700583 }
584 }
Romain Guy1aec9a22011-01-05 09:37:12 -0800585
Alan Viverette49a22e82014-07-12 20:01:27 -0700586 // Compute surface insets required to draw at specified Z value.
587 // TODO: Use real shadow insets for a constant max Z.
Alan Viverette5435a302015-01-29 10:25:34 -0800588 if (!attrs.hasManualSurfaceInsets) {
Wale Ogunwale246c2092016-04-07 14:12:44 -0700589 attrs.setSurfaceInsets(view, false /*manual*/, true /*preservePrevious*/);
Alan Viverette5435a302015-01-29 10:25:34 -0800590 }
Alan Viverette49a22e82014-07-12 20:01:27 -0700591
Craig Mautner48d0d182013-06-11 07:53:06 -0700592 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
Romain Guy856d4e12011-10-14 15:47:55 -0700593 mTranslator = compatibilityInfo.getTranslator();
594
Romain Guy1aec9a22011-01-05 09:37:12 -0800595 // If the application owns the surface, don't enable hardware acceleration
596 if (mSurfaceHolder == null) {
Romain Guy3b748a42013-04-17 18:54:38 -0700597 enableHardwareAcceleration(attrs);
Romain Guy1aec9a22011-01-05 09:37:12 -0800598 }
599
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700600 boolean restore = false;
Romain Guy35b38ce2009-10-07 13:38:55 -0700601 if (mTranslator != null) {
Romain Guy856d4e12011-10-14 15:47:55 -0700602 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700603 restore = true;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700604 attrs.backup();
605 mTranslator.translateWindowLayout(attrs);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700606 }
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800607 if (DEBUG_LAYOUT) Log.d(mTag, "WindowLayout in setView:" + attrs);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700608
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700609 if (!compatibilityInfo.supportsScreen()) {
Adam Lesinski95c42972013-10-02 10:13:27 -0700610 attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700611 mLastInCompatMode = true;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700612 }
613
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614 mSoftInputMode = attrs.softInputMode;
615 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -0700616 mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800617 mAttachInfo.mRootView = view;
Romain Guy35b38ce2009-10-07 13:38:55 -0700618 mAttachInfo.mScalingRequired = mTranslator != null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700619 mAttachInfo.mApplicationScale =
620 mTranslator == null ? 1.0f : mTranslator.applicationScale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800621 if (panelParentView != null) {
622 mAttachInfo.mPanelParentWindowToken
623 = panelParentView.getApplicationWindowToken();
624 }
625 mAdded = true;
626 int res; /* = WindowManagerImpl.ADD_OKAY; */
Romain Guy8506ab42009-06-11 17:35:47 -0700627
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628 // Schedule the first layout -before- adding to the window
629 // manager, to make sure we do the relayout before receiving
630 // any other events from the system.
631 requestLayout();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700632 if ((mWindowAttributes.inputFeatures
633 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
634 mInputChannel = new InputChannel();
635 }
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800636 mForceDecorViewVisibility = (mWindowAttributes.privateFlags
637 & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800638 try {
Dianne Hackborn180c4842011-09-13 12:39:25 -0700639 mOrigWindowType = mWindowAttributes.type;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700640 mAttachInfo.mRecomputeGlobalAttributes = true;
641 collectViewAttributes();
Jeff Brown98365d72012-08-19 20:30:52 -0700642 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
643 getHostVisibility(), mDisplay.getDisplayId(),
Filip Gruszczynski0ec13282015-06-25 11:26:01 -0700644 mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
645 mAttachInfo.mOutsets, mInputChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646 } catch (RemoteException e) {
647 mAdded = false;
648 mView = null;
649 mAttachInfo.mRootView = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700650 mInputChannel = null;
Joe Onorato86f67862010-11-05 18:57:34 -0700651 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700653 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654 throw new RuntimeException("Adding window failed", e);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700655 } finally {
656 if (restore) {
657 attrs.restore();
658 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700660
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700661 if (mTranslator != null) {
662 mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700663 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800664 mPendingOverscanInsets.set(0, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 mPendingContentInsets.set(mAttachInfo.mContentInsets);
Adrian Roosfa104232014-06-20 16:10:14 -0700666 mPendingStableInsets.set(mAttachInfo.mStableInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 mPendingVisibleInsets.set(0, 0, 0, 0);
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -0800668 mAttachInfo.mAlwaysConsumeNavBar =
669 (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR) != 0;
670 mPendingAlwaysConsumeNavBar = mAttachInfo.mAlwaysConsumeNavBar;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800671 if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
Jeff Brown98365d72012-08-19 20:30:52 -0700672 if (res < WindowManagerGlobal.ADD_OKAY) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800673 mAttachInfo.mRootView = null;
674 mAdded = false;
Joe Onorato86f67862010-11-05 18:57:34 -0700675 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700677 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 switch (res) {
Jeff Brown98365d72012-08-19 20:30:52 -0700679 case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
680 case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
681 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800682 "Unable to add window -- token " + attrs.token
683 + " is not valid; is your activity running?");
Jeff Brown98365d72012-08-19 20:30:52 -0700684 case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
685 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800686 "Unable to add window -- token " + attrs.token
687 + " is not for an application");
Jeff Brown98365d72012-08-19 20:30:52 -0700688 case WindowManagerGlobal.ADD_APP_EXITING:
689 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800690 "Unable to add window -- app for token " + attrs.token
691 + " is exiting");
Jeff Brown98365d72012-08-19 20:30:52 -0700692 case WindowManagerGlobal.ADD_DUPLICATE_ADD:
693 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800694 "Unable to add window -- window " + mWindow
695 + " has already been added");
Jeff Brown98365d72012-08-19 20:30:52 -0700696 case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800697 // Silently ignore -- we would have just removed it
698 // right away, anyway.
699 return;
Jeff Brown98365d72012-08-19 20:30:52 -0700700 case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
Alan Viverette73f6d602015-09-14 16:01:19 -0400701 throw new WindowManager.BadTokenException("Unable to add window "
702 + mWindow + " -- another window of type "
703 + mWindowAttributes.type + " already exists");
Jeff Brown98365d72012-08-19 20:30:52 -0700704 case WindowManagerGlobal.ADD_PERMISSION_DENIED:
Alan Viverette73f6d602015-09-14 16:01:19 -0400705 throw new WindowManager.BadTokenException("Unable to add window "
706 + mWindow + " -- permission denied for window type "
707 + mWindowAttributes.type);
Craig Mautner6018aee2012-10-23 14:27:49 -0700708 case WindowManagerGlobal.ADD_INVALID_DISPLAY:
Alan Viverette73f6d602015-09-14 16:01:19 -0400709 throw new WindowManager.InvalidDisplayException("Unable to add window "
710 + mWindow + " -- the specified display can not be found");
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800711 case WindowManagerGlobal.ADD_INVALID_TYPE:
Alan Viverette73f6d602015-09-14 16:01:19 -0400712 throw new WindowManager.InvalidDisplayException("Unable to add window "
713 + mWindow + " -- the specified window type "
714 + mWindowAttributes.type + " is not valid");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 }
716 throw new RuntimeException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800717 "Unable to add window -- unknown error code " + res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800718 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700719
Jeff Brown00fa7bd2010-07-02 15:37:36 -0700720 if (view instanceof RootViewSurfaceTaker) {
721 mInputQueueCallback =
722 ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
723 }
Jeff Browncc4f7db2011-08-30 20:34:48 -0700724 if (mInputChannel != null) {
725 if (mInputQueueCallback != null) {
Michael Wrighta44dd262013-04-10 21:12:00 -0700726 mInputQueue = new InputQueue();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700727 mInputQueueCallback.onInputQueueCreated(mInputQueue);
Jeff Browncc4f7db2011-08-30 20:34:48 -0700728 }
Michael Wrighta44dd262013-04-10 21:12:00 -0700729 mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
730 Looper.myLooper());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700731 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700732
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800733 view.assignParent(this);
Jeff Brown98365d72012-08-19 20:30:52 -0700734 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
735 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700736
737 if (mAccessibilityManager.isEnabled()) {
738 mAccessibilityInteractionConnectionManager.ensureConnection();
739 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700740
741 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
742 view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
743 }
Michael Wright95ae9422013-03-14 10:58:50 -0700744
Jeff Brownf9e989d2013-04-04 23:04:03 -0700745 // Set up the input pipeline.
746 CharSequence counterSuffix = attrs.getTitle();
Michael Wright899d7052014-04-23 17:23:39 -0700747 mSyntheticInputStage = new SyntheticInputStage();
748 InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
Jeff Brownf9e989d2013-04-04 23:04:03 -0700749 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
750 "aq:native-post-ime:" + counterSuffix);
751 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
752 InputStage imeStage = new ImeInputStage(earlyPostImeStage,
753 "aq:ime:" + counterSuffix);
754 InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
755 InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
756 "aq:native-pre-ime:" + counterSuffix);
757
758 mFirstInputStage = nativePreImeStage;
759 mFirstPostImeInputStage = earlyPostImeStage;
760 mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 }
762 }
763 }
764
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -0800765 private void setTag() {
766 final String[] split = mWindowAttributes.getTitle().toString().split("\\.");
767 if (split.length > 0) {
768 mTag = TAG + "[" + split[split.length - 1] + "]";
769 }
770 }
771
keunyoung30f420f2013-08-02 14:23:10 -0700772 /** Whether the window is in local focus mode or not */
773 private boolean isInLocalFocusMode() {
774 return (mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0;
775 }
776
Dianne Hackborn49b043f2015-05-07 14:21:38 -0700777 public int getWindowFlags() {
778 return mWindowAttributes.flags;
779 }
780
Dianne Hackbornece0f4f2015-06-11 13:29:01 -0700781 public int getDisplayId() {
782 return mDisplay.getDisplayId();
783 }
784
Dianne Hackborna7bb6fb2015-02-03 18:13:40 -0800785 public CharSequence getTitle() {
786 return mWindowAttributes.getTitle();
787 }
788
Romain Guy8ff6b9e2011-11-09 20:10:18 -0800789 void destroyHardwareResources() {
Romain Guy31f2c2e2011-11-21 10:55:41 -0800790 if (mAttachInfo.mHardwareRenderer != null) {
791 mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
John Reckf47a5942014-06-30 16:20:04 -0700792 mAttachInfo.mHardwareRenderer.destroy();
Romain Guy31f2c2e2011-11-21 10:55:41 -0800793 }
794 }
795
Bo Liu845535a2014-03-21 12:06:23 -0700796 public void detachFunctor(long functor) {
John Reck44ac42a2014-05-16 14:46:07 -0700797 if (mAttachInfo.mHardwareRenderer != null) {
798 // Fence so that any pending invokeFunctor() messages will be processed
799 // before we return from detachFunctor.
John Reckf47a5942014-06-30 16:20:04 -0700800 mAttachInfo.mHardwareRenderer.stopDrawing();
John Reck44ac42a2014-05-16 14:46:07 -0700801 }
Romain Guyba6be8a2012-04-23 18:22:09 -0700802 }
803
John Reck3b202512014-06-23 13:13:08 -0700804 /**
805 * Schedules the functor for execution in either kModeProcess or
806 * kModeProcessNoContext, depending on whether or not there is an EGLContext.
807 *
808 * @param functor The native functor to invoke
809 * @param waitForCompletion If true, this will not return until the functor
810 * has invoked. If false, the functor may be invoked
811 * asynchronously.
812 */
John Reck44b49f02016-03-25 14:29:48 -0700813 public static void invokeFunctor(long functor, boolean waitForCompletion) {
John Reck3b202512014-06-23 13:13:08 -0700814 ThreadedRenderer.invokeFunctor(functor, waitForCompletion);
Bo Liuae738a72014-04-27 16:22:04 -0700815 }
816
John Reck119907c2014-08-14 09:02:01 -0700817 public void registerAnimatingRenderNode(RenderNode animator) {
818 if (mAttachInfo.mHardwareRenderer != null) {
819 mAttachInfo.mHardwareRenderer.registerAnimatingRenderNode(animator);
820 } else {
821 if (mAttachInfo.mPendingAnimatingRenderNodes == null) {
822 mAttachInfo.mPendingAnimatingRenderNodes = new ArrayList<RenderNode>();
823 }
824 mAttachInfo.mPendingAnimatingRenderNodes.add(animator);
825 }
826 }
827
Doris Liu718cd3e2016-05-17 16:50:31 -0700828 public void registerVectorDrawableAnimator(
829 AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) {
830 if (mAttachInfo.mHardwareRenderer != null) {
831 mAttachInfo.mHardwareRenderer.registerVectorDrawableAnimator(animator);
832 }
833 }
834
Romain Guy3b748a42013-04-17 18:54:38 -0700835 private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800836 mAttachInfo.mHardwareAccelerated = false;
837 mAttachInfo.mHardwareAccelerationRequested = false;
Romain Guy4f6aff32011-01-12 16:21:41 -0800838
Romain Guy856d4e12011-10-14 15:47:55 -0700839 // Don't enable hardware acceleration when the application is in compatibility mode
John Reckdd58e792014-04-02 16:54:28 +0000840 if (mTranslator != null) return;
Romain Guy856d4e12011-10-14 15:47:55 -0700841
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800842 // Try to enable hardware acceleration if requested
Igor Murashkina86ab6402013-08-30 12:58:36 -0700843 final boolean hardwareAccelerated =
Jim Miller1b365922011-03-09 19:38:07 -0800844 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
845
John Reckdd58e792014-04-02 16:54:28 +0000846 if (hardwareAccelerated) {
John Reck51aaf902015-12-02 15:08:07 -0800847 if (!ThreadedRenderer.isAvailable()) {
Romain Guy1af23a32011-03-24 16:03:55 -0700848 return;
849 }
850
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700851 // Persistent processes (including the system) should not do
852 // accelerated rendering on low-end devices. In that case,
853 // sRendererDisabled will be set. In addition, the system process
854 // itself should never do accelerated rendering. In that case, both
855 // sRendererDisabled and sSystemRendererDisabled are set. When
856 // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
857 // can be used by code on the system process to escape that and enable
858 // HW accelerated drawing. (This is basically for the lock screen.)
Jim Miller1b365922011-03-09 19:38:07 -0800859
John Reck61375a82014-09-18 19:27:48 +0000860 final boolean fakeHwAccelerated = (attrs.privateFlags &
861 WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700862 final boolean forceHwAccelerated = (attrs.privateFlags &
863 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
Jim Miller1b365922011-03-09 19:38:07 -0800864
John Reck61375a82014-09-18 19:27:48 +0000865 if (fakeHwAccelerated) {
866 // This is exclusively for the preview windows the window manager
867 // shows for launching applications, so they will look more like
868 // the app being launched.
869 mAttachInfo.mHardwareAccelerationRequested = true;
John Reck51aaf902015-12-02 15:08:07 -0800870 } else if (!ThreadedRenderer.sRendererDisabled
871 || (ThreadedRenderer.sSystemRendererDisabled && forceHwAccelerated)) {
Romain Guyb051e892010-09-28 19:09:36 -0700872 if (mAttachInfo.mHardwareRenderer != null) {
John Reckf47a5942014-06-30 16:20:04 -0700873 mAttachInfo.mHardwareRenderer.destroy();
Romain Guy211370f2012-02-01 16:10:55 -0800874 }
875
Alan Viverette2b12b582014-10-29 11:11:40 -0700876 final Rect insets = attrs.surfaceInsets;
Alan Viverette2cd23e62014-11-04 17:04:02 -0800877 final boolean hasSurfaceInsets = insets.left != 0 || insets.right != 0
878 || insets.top != 0 || insets.bottom != 0;
Alan Viverette2b12b582014-10-29 11:11:40 -0700879 final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;
John Reck51aaf902015-12-02 15:08:07 -0800880 mAttachInfo.mHardwareRenderer = ThreadedRenderer.create(mContext, translucent);
Romain Guye55945e2013-04-04 15:26:04 -0700881 if (mAttachInfo.mHardwareRenderer != null) {
882 mAttachInfo.mHardwareRenderer.setName(attrs.getTitle().toString());
883 mAttachInfo.mHardwareAccelerated =
884 mAttachInfo.mHardwareAccelerationRequested = true;
885 }
Romain Guye4d01122010-06-16 18:44:05 -0700886 }
887 }
888 }
889
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800890 public View getView() {
891 return mView;
892 }
893
894 final WindowLeaked getLocation() {
895 return mLocation;
896 }
897
898 void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
899 synchronized (this) {
Alan Viverettedbed8932014-08-06 17:54:52 -0700900 final int oldInsetLeft = mWindowAttributes.surfaceInsets.left;
901 final int oldInsetTop = mWindowAttributes.surfaceInsets.top;
902 final int oldInsetRight = mWindowAttributes.surfaceInsets.right;
903 final int oldInsetBottom = mWindowAttributes.surfaceInsets.bottom;
904 final int oldSoftInputMode = mWindowAttributes.softInputMode;
Alan Viverette5435a302015-01-29 10:25:34 -0800905 final boolean oldHasManualSurfaceInsets = mWindowAttributes.hasManualSurfaceInsets;
Chong Zhang44aabe42016-05-10 11:20:14 -0700906
907 if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
908 & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
Chong Zhang4ffc3182016-05-04 15:06:02 -0700909 && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) {
Chong Zhang44aabe42016-05-10 11:20:14 -0700910 Slog.d(mTag, "setLayoutParams: FLAG_KEEP_SCREEN_ON from true to false!");
Chong Zhang4ffc3182016-05-04 15:06:02 -0700911 }
Alan Viverettedbed8932014-08-06 17:54:52 -0700912
Dianne Hackborn9d090892012-06-11 18:35:41 -0700913 // Keep track of the actual window flags supplied by the client.
914 mClientWindowLayoutFlags = attrs.flags;
Alan Viverettedbed8932014-08-06 17:54:52 -0700915
916 // Preserve compatible window flag if exists.
917 final int compatibleWindowFlag = mWindowAttributes.privateFlags
Adam Lesinski95c42972013-10-02 10:13:27 -0700918 & WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Alan Viverettedbed8932014-08-06 17:54:52 -0700919
920 // Transfer over system UI visibility values as they carry current state.
Craig Mautner3fe38c02012-05-03 17:28:09 -0700921 attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
922 attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
Alan Viverettedbed8932014-08-06 17:54:52 -0700923
Romain Guyf21c9b02011-09-06 16:56:54 -0700924 mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
John Spurlockbd957402013-10-03 11:38:39 -0400925 if ((mWindowAttributesChangesFlag
926 & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) {
927 // Recompute system ui visibility.
928 mAttachInfo.mRecomputeGlobalAttributes = true;
929 }
Teng-Hui Zhu27571282016-05-12 15:53:53 -0700930 if ((mWindowAttributesChangesFlag
931 & WindowManager.LayoutParams.LAYOUT_CHANGED) != 0) {
932 // Request to update light center.
933 mAttachInfo.mNeedsUpdateLightCenter = true;
934 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800935 if (mWindowAttributes.packageName == null) {
936 mWindowAttributes.packageName = mBasePackageName;
937 }
Adam Lesinski95c42972013-10-02 10:13:27 -0700938 mWindowAttributes.privateFlags |= compatibleWindowFlag;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700939
Wale Ogunwale246c2092016-04-07 14:12:44 -0700940 if (mWindowAttributes.preservePreviousSurfaceInsets) {
941 // Restore old surface insets.
942 mWindowAttributes.surfaceInsets.set(
943 oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
944 mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
Robert Carr1bccabf2016-04-28 13:27:08 -0700945 } else if (mWindowAttributes.surfaceInsets.left != oldInsetLeft
946 || mWindowAttributes.surfaceInsets.top != oldInsetTop
947 || mWindowAttributes.surfaceInsets.right != oldInsetRight
948 || mWindowAttributes.surfaceInsets.bottom != oldInsetBottom) {
949 mNeedsHwRendererSetup = true;
Wale Ogunwale246c2092016-04-07 14:12:44 -0700950 }
Alan Viverettedbed8932014-08-06 17:54:52 -0700951
Dianne Hackborn9d090892012-06-11 18:35:41 -0700952 applyKeepScreenOnFlag(mWindowAttributes);
953
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 if (newView) {
955 mSoftInputMode = attrs.softInputMode;
956 requestLayout();
957 }
Alan Viverettedbed8932014-08-06 17:54:52 -0700958
The Android Open Source Project10592532009-03-18 17:39:46 -0700959 // Don't lose the mode we last auto-computed.
Alan Viverettedbed8932014-08-06 17:54:52 -0700960 if ((attrs.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
The Android Open Source Project10592532009-03-18 17:39:46 -0700961 == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
962 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
963 & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
Alan Viverettedbed8932014-08-06 17:54:52 -0700964 | (oldSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
The Android Open Source Project10592532009-03-18 17:39:46 -0700965 }
Alan Viverettedbed8932014-08-06 17:54:52 -0700966
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967 mWindowAttributesChanged = true;
968 scheduleTraversals();
969 }
970 }
971
972 void handleAppVisibility(boolean visible) {
973 if (mAppVisible != visible) {
974 mAppVisible = visible;
975 scheduleTraversals();
John Reck73840ea2014-09-22 07:39:18 -0700976 if (!mAppVisible) {
977 WindowManagerGlobal.trimForeground();
978 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 }
980 }
981
982 void handleGetNewSurface() {
983 mNewSurfaceNeeded = true;
984 mFullRedrawNeeded = true;
985 scheduleTraversals();
986 }
987
Jeff Brownd912e1f2014-04-11 18:46:22 -0700988 private final DisplayListener mDisplayListener = new DisplayListener() {
989 @Override
990 public void onDisplayChanged(int displayId) {
991 if (mView != null && mDisplay.getDisplayId() == displayId) {
992 final int oldDisplayState = mAttachInfo.mDisplayState;
993 final int newDisplayState = mDisplay.getState();
994 if (oldDisplayState != newDisplayState) {
995 mAttachInfo.mDisplayState = newDisplayState;
Jeff Brownc2932a12014-11-20 18:04:05 -0800996 pokeDrawLockIfNeeded();
Jeff Brownd912e1f2014-04-11 18:46:22 -0700997 if (oldDisplayState != Display.STATE_UNKNOWN) {
998 final int oldScreenState = toViewScreenState(oldDisplayState);
999 final int newScreenState = toViewScreenState(newDisplayState);
1000 if (oldScreenState != newScreenState) {
1001 mView.dispatchScreenStateChanged(newScreenState);
1002 }
1003 if (oldDisplayState == Display.STATE_OFF) {
1004 // Draw was suppressed so we need to for it to happen here.
1005 mFullRedrawNeeded = true;
1006 scheduleTraversals();
1007 }
1008 }
1009 }
Romain Guy7e4e5612012-03-05 14:37:29 -08001010 }
1011 }
Jeff Brownd912e1f2014-04-11 18:46:22 -07001012
1013 @Override
1014 public void onDisplayRemoved(int displayId) {
1015 }
1016
1017 @Override
1018 public void onDisplayAdded(int displayId) {
1019 }
1020
1021 private int toViewScreenState(int displayState) {
1022 return displayState == Display.STATE_OFF ?
1023 View.SCREEN_STATE_OFF : View.SCREEN_STATE_ON;
1024 }
1025 };
Romain Guy7e4e5612012-03-05 14:37:29 -08001026
Jeff Brownc2932a12014-11-20 18:04:05 -08001027 void pokeDrawLockIfNeeded() {
1028 final int displayState = mAttachInfo.mDisplayState;
1029 if (mView != null && mAdded && mTraversalScheduled
1030 && (displayState == Display.STATE_DOZE
1031 || displayState == Display.STATE_DOZE_SUSPEND)) {
1032 try {
1033 mWindowSession.pokeDrawLock(mWindow);
1034 } catch (RemoteException ex) {
1035 // System server died, oh well.
1036 }
1037 }
1038 }
1039
Craig Mautner6018aee2012-10-23 14:27:49 -07001040 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001041 public void requestFitSystemWindows() {
1042 checkThread();
Adrian Roosfa104232014-06-20 16:10:14 -07001043 mApplyInsetsRequested = true;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001044 scheduleTraversals();
1045 }
1046
Craig Mautner6018aee2012-10-23 14:27:49 -07001047 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 public void requestLayout() {
Chet Haase3efa7b52012-12-03 08:33:17 -08001049 if (!mHandlingLayoutInLayoutRequest) {
1050 checkThread();
1051 mLayoutRequested = true;
1052 scheduleTraversals();
1053 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001054 }
1055
Craig Mautner6018aee2012-10-23 14:27:49 -07001056 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 public boolean isLayoutRequested() {
1058 return mLayoutRequested;
1059 }
1060
Romain Guycfef1232012-02-23 13:50:37 -08001061 void invalidate() {
1062 mDirty.set(0, 0, mWidth, mHeight);
John Recke4267ea2014-06-03 15:53:15 -07001063 if (!mWillDrawSoon) {
1064 scheduleTraversals();
1065 }
Romain Guycfef1232012-02-23 13:50:37 -08001066 }
1067
Dianne Hackborna53de062012-05-08 18:53:51 -07001068 void invalidateWorld(View view) {
1069 view.invalidate();
1070 if (view instanceof ViewGroup) {
Romain Guyf84208f2012-09-13 22:50:18 -07001071 ViewGroup parent = (ViewGroup) view;
1072 for (int i = 0; i < parent.getChildCount(); i++) {
Dianne Hackborna53de062012-05-08 18:53:51 -07001073 invalidateWorld(parent.getChildAt(i));
1074 }
1075 }
1076 }
1077
Craig Mautner6018aee2012-10-23 14:27:49 -07001078 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079 public void invalidateChild(View child, Rect dirty) {
Romain Guycfef1232012-02-23 13:50:37 -08001080 invalidateChildInParent(null, dirty);
1081 }
1082
Craig Mautner8f303ad2013-06-14 11:32:22 -07001083 @Override
Romain Guycfef1232012-02-23 13:50:37 -08001084 public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001085 checkThread();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001086 if (DEBUG_DRAW) Log.v(mTag, "Invalidate child: " + dirty);
Romain Guycfef1232012-02-23 13:50:37 -08001087
Chet Haase70d4ba12010-10-06 09:46:45 -07001088 if (dirty == null) {
Chet Haase70d4ba12010-10-06 09:46:45 -07001089 invalidate();
Romain Guycfef1232012-02-23 13:50:37 -08001090 return null;
Chet Haase3561d062012-10-23 12:54:51 -07001091 } else if (dirty.isEmpty() && !mIsAnimating) {
Chet Haase05e91ed2012-07-03 14:17:57 -07001092 return null;
Chet Haase70d4ba12010-10-06 09:46:45 -07001093 }
Romain Guycfef1232012-02-23 13:50:37 -08001094
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001095 if (mCurScrollY != 0 || mTranslator != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 mTempRect.set(dirty);
Romain Guy1e095972009-07-07 11:22:45 -07001097 dirty = mTempRect;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001098 if (mCurScrollY != 0) {
Romain Guycfef1232012-02-23 13:50:37 -08001099 dirty.offset(0, -mCurScrollY);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001100 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001101 if (mTranslator != null) {
Romain Guy1e095972009-07-07 11:22:45 -07001102 mTranslator.translateRectInAppWindowToScreen(dirty);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001103 }
Romain Guy1e095972009-07-07 11:22:45 -07001104 if (mAttachInfo.mScalingRequired) {
1105 dirty.inset(-1, -1);
1106 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107 }
Romain Guycfef1232012-02-23 13:50:37 -08001108
Alan Viverettea7ea65e2015-05-15 11:30:21 -07001109 invalidateRectOnScreen(dirty);
1110
1111 return null;
1112 }
1113
1114 private void invalidateRectOnScreen(Rect dirty) {
Romain Guycfef1232012-02-23 13:50:37 -08001115 final Rect localDirty = mDirty;
1116 if (!localDirty.isEmpty() && !localDirty.contains(dirty)) {
Romain Guy02ccac62011-06-24 13:20:23 -07001117 mAttachInfo.mSetIgnoreDirtyState = true;
Romain Guy7d695942010-12-01 17:22:29 -08001118 mAttachInfo.mIgnoreDirtyState = true;
1119 }
Romain Guycfef1232012-02-23 13:50:37 -08001120
1121 // Add the new dirty rect to the current one
1122 localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
1123 // Intersect with the bounds of the window to skip
1124 // updates that lie outside of the visible region
Romain Guy7b2f8b82012-03-19 17:18:54 -07001125 final float appScale = mAttachInfo.mApplicationScale;
Chet Haase3561d062012-10-23 12:54:51 -07001126 final boolean intersected = localDirty.intersect(0, 0,
1127 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
1128 if (!intersected) {
Chet Haaseb78ee0e2012-10-17 11:32:01 -07001129 localDirty.setEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001130 }
Chet Haase3561d062012-10-23 12:54:51 -07001131 if (!mWillDrawSoon && (intersected || mIsAnimating)) {
1132 scheduleTraversals();
1133 }
Romain Guy0d9275e2010-10-26 14:22:30 -07001134 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001135
Daniel Koulomzin087ae472015-12-16 17:52:25 -05001136 public void setIsAmbientMode(boolean ambient) {
1137 mIsAmbientMode = ambient;
1138 }
1139
George Mount41725de2015-04-09 08:23:05 -07001140 void setWindowStopped(boolean stopped) {
Dianne Hackbornce418e62011-03-01 14:31:38 -08001141 if (mStopped != stopped) {
1142 mStopped = stopped;
John Reck8afcc762016-04-13 10:24:06 -07001143 final ThreadedRenderer renderer = mAttachInfo.mHardwareRenderer;
1144 if (renderer != null) {
1145 if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped);
1146 renderer.setStopped(mStopped);
1147 }
George Mount41725de2015-04-09 08:23:05 -07001148 if (!mStopped) {
Dianne Hackbornce418e62011-03-01 14:31:38 -08001149 scheduleTraversals();
John Reckd9b16072016-02-23 10:35:19 -08001150 } else {
John Reck8afcc762016-04-13 10:24:06 -07001151 if (renderer != null) {
1152 renderer.destroyHardwareResources(mView);
John Reckf4db3d22016-02-26 12:58:17 -08001153 }
Dianne Hackbornce418e62011-03-01 14:31:38 -08001154 }
1155 }
1156 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157
George Mount41725de2015-04-09 08:23:05 -07001158 /**
1159 * Block the input events during an Activity Transition. The KEYCODE_BACK event is allowed
1160 * through to allow quick reversal of the Activity Transition.
1161 *
1162 * @param paused true to pause, false to resume.
1163 */
1164 public void setPausedForTransition(boolean paused) {
1165 mPausedForTransition = paused;
1166 }
1167
Craig Mautner8f303ad2013-06-14 11:32:22 -07001168 @Override
Romain Guycfef1232012-02-23 13:50:37 -08001169 public ViewParent getParent() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001170 return null;
1171 }
1172
Craig Mautner8f303ad2013-06-14 11:32:22 -07001173 @Override
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001174 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001175 if (child != mView) {
1176 throw new RuntimeException("child is not mine, honest!");
1177 }
1178 // Note: don't apply scroll offset, because we want to know its
1179 // visibility in the virtual canvas being given to the view hierarchy.
1180 return r.intersect(0, 0, mWidth, mHeight);
1181 }
1182
Igor Murashkina86ab6402013-08-30 12:58:36 -07001183 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 public void bringChildToFront(View child) {
1185 }
1186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001187 int getHostVisibility() {
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08001188 return (mAppVisible || mForceDecorViewVisibility) ? mView.getVisibility() : View.GONE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001189 }
Romain Guy8506ab42009-06-11 17:35:47 -07001190
Chet Haasecca2c982011-05-20 14:34:18 -07001191 /**
1192 * Add LayoutTransition to the list of transitions to be started in the next traversal.
1193 * This list will be cleared after the transitions on the list are start()'ed. These
1194 * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
1195 * happens during the layout phase of traversal, which we want to complete before any of the
1196 * animations are started (because those animations may side-effect properties that layout
1197 * depends upon, like the bounding rectangles of the affected views). So we add the transition
1198 * to the list and it is started just prior to starting the drawing phase of traversal.
1199 *
1200 * @param transition The LayoutTransition to be started on the next traversal.
1201 *
1202 * @hide
1203 */
1204 public void requestTransitionStart(LayoutTransition transition) {
1205 if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
1206 if (mPendingTransitions == null) {
1207 mPendingTransitions = new ArrayList<LayoutTransition>();
1208 }
1209 mPendingTransitions.add(transition);
1210 }
1211 }
1212
John Recka5dda642014-05-22 15:43:54 -07001213 /**
1214 * Notifies the HardwareRenderer that a new frame will be coming soon.
1215 * Currently only {@link ThreadedRenderer} cares about this, and uses
1216 * this knowledge to adjust the scheduling of off-thread animations
1217 */
1218 void notifyRendererOfFramePending() {
1219 if (mAttachInfo.mHardwareRenderer != null) {
1220 mAttachInfo.mHardwareRenderer.notifyFramePending();
1221 }
1222 }
1223
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001224 void scheduleTraversals() {
1225 if (!mTraversalScheduled) {
1226 mTraversalScheduled = true;
Jeff Brown3d4e7efe2015-02-26 15:34:16 -08001227 mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001228 mChoreographer.postCallback(
1229 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
Michael Wright9d744c72014-02-18 21:27:42 -08001230 if (!mUnbufferedInputDispatch) {
1231 scheduleConsumeBatchedInput();
1232 }
John Recka5dda642014-05-22 15:43:54 -07001233 notifyRendererOfFramePending();
Jeff Brownc2932a12014-11-20 18:04:05 -08001234 pokeDrawLockIfNeeded();
Jeff Brown96e942d2011-11-30 19:55:01 -08001235 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001236 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001237
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001238 void unscheduleTraversals() {
1239 if (mTraversalScheduled) {
1240 mTraversalScheduled = false;
Jeff Brown3d4e7efe2015-02-26 15:34:16 -08001241 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001242 mChoreographer.removeCallbacks(
1243 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
1244 }
1245 }
1246
1247 void doTraversal() {
1248 if (mTraversalScheduled) {
1249 mTraversalScheduled = false;
Jeff Brown3d4e7efe2015-02-26 15:34:16 -08001250 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001251
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001252 if (mProfile) {
1253 Debug.startMethodTracing("ViewAncestor");
Jeff Brown96e942d2011-11-30 19:55:01 -08001254 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001255
Chris Craike22c59b2015-05-21 18:33:37 -07001256 performTraversals();
Jeff Brown96e942d2011-11-30 19:55:01 -08001257
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001258 if (mProfile) {
1259 Debug.stopMethodTracing();
1260 mProfile = false;
1261 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001262 }
1263 }
1264
Dianne Hackborn9d090892012-06-11 18:35:41 -07001265 private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) {
1266 // Update window's global keep screen on flag: if a view has requested
1267 // that the screen be kept on, then it is always set; otherwise, it is
1268 // set to whatever the client last requested for the global state.
1269 if (mAttachInfo.mKeepScreenOn) {
1270 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
1271 } else {
1272 params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
1273 | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1274 }
1275 }
1276
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001277 private boolean collectViewAttributes() {
Chris Craikd36a81f2014-07-17 10:16:51 -07001278 if (mAttachInfo.mRecomputeGlobalAttributes) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001279 //Log.i(mTag, "Computing view hierarchy attributes!");
Chris Craikd36a81f2014-07-17 10:16:51 -07001280 mAttachInfo.mRecomputeGlobalAttributes = false;
1281 boolean oldScreenOn = mAttachInfo.mKeepScreenOn;
1282 mAttachInfo.mKeepScreenOn = false;
1283 mAttachInfo.mSystemUiVisibility = 0;
1284 mAttachInfo.mHasSystemUiListeners = false;
1285 mView.dispatchCollectViewAttributes(mAttachInfo, 0);
1286 mAttachInfo.mSystemUiVisibility &= ~mAttachInfo.mDisabledSystemUiVisibility;
Craig Mautner7eac0f52012-09-13 13:14:14 -07001287 WindowManager.LayoutParams params = mWindowAttributes;
Chris Craikd36a81f2014-07-17 10:16:51 -07001288 mAttachInfo.mSystemUiVisibility |= getImpliedSystemUiVisibility(params);
1289 if (mAttachInfo.mKeepScreenOn != oldScreenOn
1290 || mAttachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
1291 || mAttachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
Dianne Hackborn9d090892012-06-11 18:35:41 -07001292 applyKeepScreenOnFlag(params);
Chris Craikd36a81f2014-07-17 10:16:51 -07001293 params.subtreeSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
1294 params.hasSystemUiListeners = mAttachInfo.mHasSystemUiListeners;
1295 mView.dispatchWindowSystemUiVisiblityChanged(mAttachInfo.mSystemUiVisibility);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001296 return true;
1297 }
1298 }
1299 return false;
1300 }
1301
John Spurlockbd957402013-10-03 11:38:39 -04001302 private int getImpliedSystemUiVisibility(WindowManager.LayoutParams params) {
1303 int vis = 0;
1304 // Translucent decor window flags imply stable system ui visibility.
1305 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) != 0) {
1306 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
1307 }
1308 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) != 0) {
1309 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
1310 }
1311 return vis;
1312 }
1313
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001314 private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
1315 final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
1316 int childWidthMeasureSpec;
1317 int childHeightMeasureSpec;
1318 boolean windowSizeMayChange = false;
1319
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001320 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(mTag,
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001321 "Measuring " + host + " in display " + desiredWindowWidth
1322 + "x" + desiredWindowHeight + "...");
1323
1324 boolean goodMeasure = false;
1325 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
1326 // On large screens, we don't want to allow dialogs to just
1327 // stretch to fill the entire width of the screen to display
1328 // one line of text. First try doing the layout at a smaller
1329 // size to see if it will fit.
1330 final DisplayMetrics packageMetrics = res.getDisplayMetrics();
1331 res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
1332 int baseSize = 0;
1333 if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
1334 baseSize = (int)mTmpValue.getDimension(packageMetrics);
1335 }
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08001336 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": baseSize=" + baseSize
1337 + ", desiredWindowWidth=" + desiredWindowWidth);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001338 if (baseSize != 0 && desiredWindowWidth > baseSize) {
1339 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
1340 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001341 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001342 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
Filip Gruszczynski1937a4c2016-01-19 16:17:13 -08001343 + host.getMeasuredWidth() + "," + host.getMeasuredHeight()
1344 + ") from width spec: " + MeasureSpec.toString(childWidthMeasureSpec)
1345 + " and height spec: " + MeasureSpec.toString(childHeightMeasureSpec));
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001346 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1347 goodMeasure = true;
1348 } else {
1349 // Didn't fit in that size... try expanding a bit.
1350 baseSize = (baseSize+desiredWindowWidth)/2;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001351 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": next baseSize="
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001352 + baseSize);
1353 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001354 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001355 if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001356 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1357 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001358 if (DEBUG_DIALOG) Log.v(mTag, "Good!");
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001359 goodMeasure = true;
1360 }
1361 }
1362 }
1363 }
1364
1365 if (!goodMeasure) {
1366 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
1367 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001368 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001369 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
1370 windowSizeMayChange = true;
1371 }
1372 }
1373
1374 if (DBG) {
1375 System.out.println("======================================");
1376 System.out.println("performTraversals -- after measure");
1377 host.debug();
1378 }
1379
1380 return windowSizeMayChange;
1381 }
1382
Alan Viverettefed3f722013-11-14 14:48:20 -08001383 /**
1384 * Modifies the input matrix such that it maps view-local coordinates to
1385 * on-screen coordinates.
1386 *
1387 * @param m input matrix to modify
1388 */
1389 void transformMatrixToGlobal(Matrix m) {
Dake Gu7bf379c2014-07-15 16:29:38 -07001390 m.preTranslate(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
Alan Viverettefed3f722013-11-14 14:48:20 -08001391 }
1392
1393 /**
1394 * Modifies the input matrix such that it maps on-screen coordinates to
1395 * view-local coordinates.
1396 *
1397 * @param m input matrix to modify
1398 */
1399 void transformMatrixToLocal(Matrix m) {
Dake Gu7bf379c2014-07-15 16:29:38 -07001400 m.postTranslate(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
Alan Viverettefed3f722013-11-14 14:48:20 -08001401 }
1402
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001403 /* package */ WindowInsets getWindowInsets(boolean forceConstruct) {
1404 if (mLastWindowInsets == null || forceConstruct) {
1405 mDispatchContentInsets.set(mAttachInfo.mContentInsets);
1406 mDispatchStableInsets.set(mAttachInfo.mStableInsets);
1407 Rect contentInsets = mDispatchContentInsets;
1408 Rect stableInsets = mDispatchStableInsets;
1409 // For dispatch we preserve old logic, but for direct requests from Views we allow to
1410 // immediately use pending insets.
1411 if (!forceConstruct
1412 && (!mPendingContentInsets.equals(contentInsets) ||
1413 !mPendingStableInsets.equals(stableInsets))) {
1414 contentInsets = mPendingContentInsets;
1415 stableInsets = mPendingStableInsets;
1416 }
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001417 Rect outsets = mAttachInfo.mOutsets;
1418 if (outsets.left > 0 || outsets.top > 0 || outsets.right > 0 || outsets.bottom > 0) {
1419 contentInsets = new Rect(contentInsets.left + outsets.left,
1420 contentInsets.top + outsets.top, contentInsets.right + outsets.right,
1421 contentInsets.bottom + outsets.bottom);
1422 }
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001423 mLastWindowInsets = new WindowInsets(contentInsets,
Adam Powell01f280d2015-05-18 16:07:42 -07001424 null /* windowDecorInsets */, stableInsets,
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08001425 mContext.getResources().getConfiguration().isScreenRound(),
1426 mAttachInfo.mAlwaysConsumeNavBar);
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001427 }
1428 return mLastWindowInsets;
1429 }
1430
Adam Powell2accbf92014-04-16 23:14:57 +00001431 void dispatchApplyInsets(View host) {
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001432 host.dispatchApplyWindowInsets(getWindowInsets(true /* forceConstruct */));
Adam Powell2accbf92014-04-16 23:14:57 +00001433 }
1434
Chong Zhangf6525ce2016-01-14 17:09:56 -08001435 private static boolean shouldUseDisplaySize(final WindowManager.LayoutParams lp) {
1436 return lp.type == TYPE_STATUS_BAR_PANEL
1437 || lp.type == TYPE_INPUT_METHOD
1438 || lp.type == TYPE_VOLUME_OVERLAY;
1439 }
1440
1441 private int dipToPx(int dip) {
1442 final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
1443 return (int) (displayMetrics.density * dip + 0.5f);
1444 }
1445
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001446 private void performTraversals() {
1447 // cache mView since it is used so much below...
1448 final View host = mView;
1449
1450 if (DBG) {
1451 System.out.println("======================================");
1452 System.out.println("performTraversals");
1453 host.debug();
1454 }
1455
1456 if (host == null || !mAdded)
1457 return;
1458
Craig Mautnerdf2390a2012-08-29 20:59:22 -07001459 mIsInTraversal = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 mWillDrawSoon = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001461 boolean windowSizeMayChange = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001462 boolean newSurface = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001463 boolean surfaceChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001464 WindowManager.LayoutParams lp = mWindowAttributes;
1465
1466 int desiredWindowWidth;
1467 int desiredWindowHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001469 final int viewVisibility = getHostVisibility();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001470 final boolean viewVisibilityChanged = !mFirst
1471 && (mViewVisibility != viewVisibility || mNewSurfaceNeeded);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472
1473 WindowManager.LayoutParams params = null;
1474 if (mWindowAttributesChanged) {
1475 mWindowAttributesChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001476 surfaceChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001477 params = lp;
1478 }
Craig Mautner48d0d182013-06-11 07:53:06 -07001479 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001480 if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
1481 params = lp;
Jeff Brown96e942d2011-11-30 19:55:01 -08001482 mFullRedrawNeeded = true;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001483 mLayoutRequested = true;
1484 if (mLastInCompatMode) {
Adam Lesinski95c42972013-10-02 10:13:27 -07001485 params.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001486 mLastInCompatMode = false;
1487 } else {
Adam Lesinski95c42972013-10-02 10:13:27 -07001488 params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001489 mLastInCompatMode = true;
1490 }
1491 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001492
Romain Guyf21c9b02011-09-06 16:56:54 -07001493 mWindowAttributesChangesFlag = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -07001494
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001495 Rect frame = mWinFrame;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001496 if (mFirst) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001497 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001498 mLayoutRequested = true;
1499
Chong Zhangf6525ce2016-01-14 17:09:56 -08001500 if (shouldUseDisplaySize(lp)) {
Dianne Hackborna239c842011-06-01 12:28:20 -07001501 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001502 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001503 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001504 desiredWindowWidth = size.x;
1505 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001506 } else {
Chong Zhangf6525ce2016-01-14 17:09:56 -08001507 Configuration config = mContext.getResources().getConfiguration();
1508 desiredWindowWidth = dipToPx(config.screenWidthDp);
1509 desiredWindowHeight = dipToPx(config.screenHeightDp);
Dianne Hackborna239c842011-06-01 12:28:20 -07001510 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001511
Romain Guyc5d55862011-01-21 19:01:46 -08001512 // We used to use the following condition to choose 32 bits drawing caches:
1513 // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
1514 // However, windows are now always 32 bits by default, so choose 32 bits
Chris Craikd36a81f2014-07-17 10:16:51 -07001515 mAttachInfo.mUse32BitDrawingCache = true;
1516 mAttachInfo.mHasWindowFocus = false;
1517 mAttachInfo.mWindowVisibility = viewVisibility;
1518 mAttachInfo.mRecomputeGlobalAttributes = false;
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001519 mLastConfiguration.setTo(host.getResources().getConfiguration());
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001520 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Fabrice Di Megliob003e282012-10-17 17:20:19 -07001521 // Set the layout direction if it has not been set before (inherit is the default)
1522 if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
1523 host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
1524 }
Chris Craikd36a81f2014-07-17 10:16:51 -07001525 host.dispatchAttachedToWindow(mAttachInfo, 0);
1526 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
Adam Powell2accbf92014-04-16 23:14:57 +00001527 dispatchApplyInsets(host);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001528 //Log.i(mTag, "Screen on initialized: " + attachInfo.mKeepScreenOn);
svetoslavganov75986cf2009-05-14 22:28:01 -07001529
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001530 } else {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001531 desiredWindowWidth = frame.width();
1532 desiredWindowHeight = frame.height();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001533 if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001534 if (DEBUG_ORIENTATION) Log.v(mTag, "View " + host + " resized to: " + frame);
Jeff Brown96e942d2011-11-30 19:55:01 -08001535 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001536 mLayoutRequested = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001537 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001538 }
1539 }
1540
1541 if (viewVisibilityChanged) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001542 mAttachInfo.mWindowVisibility = viewVisibility;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001543 host.dispatchWindowVisibilityChanged(viewVisibility);
Adam Powell9c146bf2016-03-15 17:35:00 -07001544 host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001545 if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
Skuhneb8160872015-09-22 09:51:39 -07001546 endDragResizing();
Romain Guy65b345f2011-07-27 18:51:50 -07001547 destroyHardwareResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001548 }
1549 if (viewVisibility == View.GONE) {
1550 // After making a window gone, we will count it as being
1551 // shown for the first time the next time it gets focus.
1552 mHasHadWindowFocus = false;
1553 }
1554 }
1555
Alan Viverette7dbc3bf2015-01-28 16:14:36 -08001556 // Non-visible windows can't hold accessibility focus.
1557 if (mAttachInfo.mWindowVisibility != View.VISIBLE) {
1558 host.clearAccessibilityFocus();
1559 }
1560
Chet Haaseb78c2842012-04-19 13:39:50 -07001561 // Execute enqueued actions on every traversal in case a detached view enqueued an action
Chris Craikd36a81f2014-07-17 10:16:51 -07001562 getRunQueue().executeActions(mAttachInfo.mHandler);
Chet Haaseb78c2842012-04-19 13:39:50 -07001563
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001564 boolean insetsChanged = false;
Romain Guy8506ab42009-06-11 17:35:47 -07001565
Craig Mautner72d6f212015-02-19 16:33:09 -08001566 boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001567 if (layoutRequested) {
Romain Guy15df6702009-08-17 20:17:30 -07001568
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001569 final Resources res = mView.getContext().getResources();
1570
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001571 if (mFirst) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001572 // make sure touch mode code executes by setting cached value
1573 // to opposite of the added touch mode.
1574 mAttachInfo.mInTouchMode = !mAddedTouchMode;
Romain Guy2d4cff62010-04-09 15:39:00 -07001575 ensureTouchModeLocally(mAddedTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001576 } else {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001577 if (!mPendingOverscanInsets.equals(mAttachInfo.mOverscanInsets)) {
1578 insetsChanged = true;
1579 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001580 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001581 insetsChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001582 }
Adrian Roosfa104232014-06-20 16:10:14 -07001583 if (!mPendingStableInsets.equals(mAttachInfo.mStableInsets)) {
1584 insetsChanged = true;
1585 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001586 if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001587 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001588 if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001589 + mAttachInfo.mVisibleInsets);
1590 }
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001591 if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) {
1592 insetsChanged = true;
1593 }
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08001594 if (mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar) {
1595 insetsChanged = true;
1596 }
Chong Zhangf6525ce2016-01-14 17:09:56 -08001597 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
1598 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001599 windowSizeMayChange = true;
Chong Zhangf6525ce2016-01-14 17:09:56 -08001600
1601 if (shouldUseDisplaySize(lp)) {
1602 // NOTE -- system code, won't try to do compat mode.
1603 Point size = new Point();
1604 mDisplay.getRealSize(size);
1605 desiredWindowWidth = size.x;
1606 desiredWindowHeight = size.y;
1607 } else {
1608 Configuration config = res.getConfiguration();
1609 desiredWindowWidth = dipToPx(config.screenWidthDp);
1610 desiredWindowHeight = dipToPx(config.screenHeightDp);
1611 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001612 }
1613 }
1614
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001615 // Ask host how big it wants to be
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001616 windowSizeMayChange |= measureHierarchy(host, lp, res,
1617 desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001618 }
1619
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001620 if (collectViewAttributes()) {
1621 params = lp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001622 }
Chris Craikd36a81f2014-07-17 10:16:51 -07001623 if (mAttachInfo.mForceReportNewAttributes) {
1624 mAttachInfo.mForceReportNewAttributes = false;
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001625 params = lp;
1626 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001627
Chris Craikd36a81f2014-07-17 10:16:51 -07001628 if (mFirst || mAttachInfo.mViewVisibilityChanged) {
1629 mAttachInfo.mViewVisibilityChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001630 int resizeMode = mSoftInputMode &
1631 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
1632 // If we are in auto resize mode, then we need to determine
1633 // what mode to use now.
1634 if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001635 final int N = mAttachInfo.mScrollContainers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001636 for (int i=0; i<N; i++) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001637 if (mAttachInfo.mScrollContainers.get(i).isShown()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001638 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
1639 }
1640 }
1641 if (resizeMode == 0) {
1642 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
1643 }
1644 if ((lp.softInputMode &
1645 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
1646 lp.softInputMode = (lp.softInputMode &
1647 ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
1648 resizeMode;
1649 params = lp;
1650 }
1651 }
1652 }
Romain Guy8506ab42009-06-11 17:35:47 -07001653
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001654 if (params != null) {
1655 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
1656 if (!PixelFormat.formatHasAlpha(params.format)) {
1657 params.format = PixelFormat.TRANSLUCENT;
1658 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001659 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001660 mAttachInfo.mOverscanRequested = (params.flags
1661 & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001662 }
1663
Adrian Roosfa104232014-06-20 16:10:14 -07001664 if (mApplyInsetsRequested) {
1665 mApplyInsetsRequested = false;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001666 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Adam Powell2accbf92014-04-16 23:14:57 +00001667 dispatchApplyInsets(host);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001668 if (mLayoutRequested) {
1669 // Short-circuit catching a new layout request here, so
1670 // we don't need to go through two layout passes when things
1671 // change due to fitting system windows, which can happen a lot.
1672 windowSizeMayChange |= measureHierarchy(host, lp,
1673 mView.getContext().getResources(),
1674 desiredWindowWidth, desiredWindowHeight);
1675 }
1676 }
1677
1678 if (layoutRequested) {
1679 // Clear this now, so that if anything requests a layout in the
1680 // rest of this function we will catch it and re-run a full
1681 // layout pass.
1682 mLayoutRequested = false;
1683 }
1684
1685 boolean windowShouldResize = layoutRequested && windowSizeMayChange
Dianne Hackborn189ee182010-12-02 21:48:53 -08001686 && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
Romain Guy2e4f4262010-04-06 11:07:52 -07001687 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
1688 frame.width() < desiredWindowWidth && frame.width() != mWidth)
1689 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
1690 frame.height() < desiredWindowHeight && frame.height() != mHeight));
Jorim Jaggi4846ee32016-01-07 17:39:12 +01001691 windowShouldResize |= mDragResizing && mResizeMode == RESIZE_MODE_FREEFORM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692
Jorim Jaggi4846ee32016-01-07 17:39:12 +01001693 // If the activity was just relaunched, it might have unfrozen the task bounds (while
1694 // relaunching), so we need to force a call into window manager to pick up the latest
1695 // bounds.
1696 windowShouldResize |= mActivityRelaunched;
1697
Jeff Brown2e05ec32013-09-30 15:57:43 -07001698 // Determine whether to compute insets.
1699 // If there are no inset listeners remaining then we may still need to compute
1700 // insets in case the old insets were non-empty and must be reset.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701 final boolean computesInternalInsets =
Chris Craikd36a81f2014-07-17 10:16:51 -07001702 mAttachInfo.mTreeObserver.hasComputeInternalInsetsListeners()
1703 || mAttachInfo.mHasNonEmptyGivenInternalInsets;
Romain Guy812ccbe2010-06-01 14:07:24 -07001704
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001705 boolean insetsPending = false;
1706 int relayoutResult = 0;
Chet Haased86fb2c2016-05-04 07:26:02 -07001707 boolean updatedConfiguration = false;
Romain Guy812ccbe2010-06-01 14:07:24 -07001708
Robert Carrb2594852016-04-25 16:21:13 -07001709 final int surfaceGenerationId = mSurface.getGenerationId();
1710
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08001711 final boolean isViewVisible = viewVisibility == View.VISIBLE;
Romain Guy812ccbe2010-06-01 14:07:24 -07001712 if (mFirst || windowShouldResize || insetsChanged ||
Jorim Jaggia4a58ef2016-01-27 02:10:08 -08001713 viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
1714 mForceNextWindowRelayout = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001715
Alan Viverette64bf97a2015-09-18 16:42:00 -04001716 if (isViewVisible) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 // If this window is giving internal insets to the window
1718 // manager, and it is being added or changing its visibility,
1719 // then we want to first give the window manager "fake"
1720 // insets to cause it to effectively ignore the content of
1721 // the window during layout. This avoids it briefly causing
1722 // other windows to resize/move based on the raw frame of the
1723 // window, waiting until we can finish laying out this window
1724 // and get back to the window manager with the ultimately
1725 // computed insets.
Romain Guy812ccbe2010-06-01 14:07:24 -07001726 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001727 }
1728
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001729 if (mSurfaceHolder != null) {
1730 mSurfaceHolder.mSurfaceLock.lock();
1731 mDrawingAllowed = true;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001732 }
Romain Guy812ccbe2010-06-01 14:07:24 -07001733
Romain Guyc361da82010-10-25 15:29:10 -07001734 boolean hwInitialized = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001735 boolean contentInsetsChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001736 boolean hadSurface = mSurface.isValid();
Romain Guy812ccbe2010-06-01 14:07:24 -07001737
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001738 try {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001739 if (DEBUG_LAYOUT) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001740 Log.i(mTag, "host=w:" + host.getMeasuredWidth() + ", h:" +
Dianne Hackborn189ee182010-12-02 21:48:53 -08001741 host.getMeasuredHeight() + ", params=" + params);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001742 }
Romain Guy2a83f002011-01-18 18:28:21 -08001743
John Reckf7d9c1d2014-04-09 10:01:03 -07001744 if (mAttachInfo.mHardwareRenderer != null) {
1745 // relayoutWindow may decide to destroy mSurface. As that decision
1746 // happens in WindowManager service, we need to be defensive here
1747 // and stop using the surface in case it gets destroyed.
John Reck01a5ea32014-12-03 13:01:07 -08001748 if (mAttachInfo.mHardwareRenderer.pauseSurface(mSurface)) {
1749 // Animations were running so we need to push a frame
1750 // to resume them
1751 mDirty.set(0, 0, mWidth, mHeight);
1752 }
John Reckba6adf62015-02-19 14:36:50 -08001753 mChoreographer.mFrameInfo.addFlags(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED);
John Reckf7d9c1d2014-04-09 10:01:03 -07001754 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001755 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
1756
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001757 if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001758 + " overscan=" + mPendingOverscanInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001759 + " content=" + mPendingContentInsets.toShortString()
1760 + " visible=" + mPendingVisibleInsets.toShortString()
Adrian Roosfa104232014-06-20 16:10:14 -07001761 + " visible=" + mPendingStableInsets.toShortString()
Filip Gruszczynski0ec13282015-06-25 11:26:01 -07001762 + " outsets=" + mPendingOutsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001763 + " surface=" + mSurface);
Romain Guy8506ab42009-06-11 17:35:47 -07001764
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001765 if (mPendingConfiguration.seq != 0) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001766 if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: "
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001767 + mPendingConfiguration);
riddle_hsu164725c2015-11-12 14:07:12 +08001768 updateConfiguration(new Configuration(mPendingConfiguration), !mFirst);
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001769 mPendingConfiguration.seq = 0;
Chet Haased86fb2c2016-05-04 07:26:02 -07001770 updatedConfiguration = true;
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001771 }
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001772
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001773 final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
1774 mAttachInfo.mOverscanInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001775 contentInsetsChanged = !mPendingContentInsets.equals(
1776 mAttachInfo.mContentInsets);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001777 final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001778 mAttachInfo.mVisibleInsets);
Adrian Roosfa104232014-06-20 16:10:14 -07001779 final boolean stableInsetsChanged = !mPendingStableInsets.equals(
1780 mAttachInfo.mStableInsets);
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001781 final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets);
Chong Zhangf4abc2b2015-11-12 23:40:58 -08001782 final boolean surfaceSizeChanged = (relayoutResult
1783 & WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08001784 final boolean alwaysConsumeNavBarChanged =
1785 mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001786 if (contentInsetsChanged) {
1787 mAttachInfo.mContentInsets.set(mPendingContentInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001788 if (DEBUG_LAYOUT) Log.v(mTag, "Content insets changing to: "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001789 + mAttachInfo.mContentInsets);
1790 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001791 if (overscanInsetsChanged) {
1792 mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001793 if (DEBUG_LAYOUT) Log.v(mTag, "Overscan insets changing to: "
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001794 + mAttachInfo.mOverscanInsets);
1795 // Need to relayout with content insets.
1796 contentInsetsChanged = true;
1797 }
Adrian Roosfa104232014-06-20 16:10:14 -07001798 if (stableInsetsChanged) {
1799 mAttachInfo.mStableInsets.set(mPendingStableInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001800 if (DEBUG_LAYOUT) Log.v(mTag, "Decor insets changing to: "
Adrian Roosfa104232014-06-20 16:10:14 -07001801 + mAttachInfo.mStableInsets);
1802 // Need to relayout with content insets.
1803 contentInsetsChanged = true;
1804 }
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08001805 if (alwaysConsumeNavBarChanged) {
1806 mAttachInfo.mAlwaysConsumeNavBar = mPendingAlwaysConsumeNavBar;
1807 contentInsetsChanged = true;
1808 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001809 if (contentInsetsChanged || mLastSystemUiVisibility !=
Adrian Roosfa104232014-06-20 16:10:14 -07001810 mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001811 || mLastOverscanRequested != mAttachInfo.mOverscanRequested
1812 || outsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001813 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001814 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001815 mAttachInfo.mOutsets.set(mPendingOutsets);
Adrian Roosfa104232014-06-20 16:10:14 -07001816 mApplyInsetsRequested = false;
Adam Powell2accbf92014-04-16 23:14:57 +00001817 dispatchApplyInsets(host);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001818 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001819 if (visibleInsetsChanged) {
1820 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08001821 if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001822 + mAttachInfo.mVisibleInsets);
1823 }
1824
1825 if (!hadSurface) {
1826 if (mSurface.isValid()) {
1827 // If we are creating a new surface, then we need to
1828 // completely redraw it. Also, when we get to the
1829 // point of drawing it we will hold off and schedule
1830 // a new traversal instead. This is so we can tell the
1831 // window manager about all of the windows being displayed
1832 // before actually drawing them, so it can display then
1833 // all at once.
1834 newSurface = true;
Jeff Brown96e942d2011-11-30 19:55:01 -08001835 mFullRedrawNeeded = true;
Jack Palevich61a6e682009-10-09 17:37:50 -07001836 mPreviousTransparentRegion.setEmpty();
Romain Guy8506ab42009-06-11 17:35:47 -07001837
John Reck63005e62015-05-19 15:00:13 -07001838 // Only initialize up-front if transparent regions are not
1839 // requested, otherwise defer to see if the entire window
1840 // will be transparent
Romain Guyb051e892010-09-28 19:09:36 -07001841 if (mAttachInfo.mHardwareRenderer != null) {
Dianne Hackborn64825172011-03-02 21:32:58 -08001842 try {
Romain Guy786fc932012-07-24 16:24:56 -07001843 hwInitialized = mAttachInfo.mHardwareRenderer.initialize(
John Reck79d81e62013-11-05 13:26:57 -08001844 mSurface);
John Reck63005e62015-05-19 15:00:13 -07001845 if (hwInitialized && (host.mPrivateFlags
1846 & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
1847 // Don't pre-allocate if transparent regions
1848 // are requested as they may not be needed
1849 mSurface.allocateBuffers();
1850 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001851 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08001852 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08001853 return;
1854 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001855 }
1856 }
1857 } else if (!mSurface.isValid()) {
1858 // If the surface has been removed, then reset the scroll
1859 // positions.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001860 if (mLastScrolledFocus != null) {
1861 mLastScrolledFocus.clear();
1862 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001863 mScrollY = mCurScrollY = 0;
Adrian Roos0e7ae4e2014-10-01 15:33:22 +02001864 if (mView instanceof RootViewSurfaceTaker) {
1865 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
1866 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001867 if (mScroller != null) {
1868 mScroller.abortAnimation();
1869 }
Romain Guy1d0c7082011-08-03 16:22:24 -07001870 // Our surface is gone
1871 if (mAttachInfo.mHardwareRenderer != null &&
1872 mAttachInfo.mHardwareRenderer.isEnabled()) {
John Reckf47a5942014-06-30 16:20:04 -07001873 mAttachInfo.mHardwareRenderer.destroy();
Romain Guy1d0c7082011-08-03 16:22:24 -07001874 }
Chong Zhangf4abc2b2015-11-12 23:40:58 -08001875 } else if ((surfaceGenerationId != mSurface.getGenerationId()
1876 || surfaceSizeChanged)
1877 && mSurfaceHolder == null
1878 && mAttachInfo.mHardwareRenderer != null) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001879 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08001880 try {
Chong Zhangf4abc2b2015-11-12 23:40:58 -08001881 // Need to do updateSurface (which leads to CanvasContext::setSurface and
1882 // re-create the EGLSurface) if either the Surface changed (as indicated by
1883 // generation id), or WindowManager changed the surface size. The latter is
1884 // because on some chips, changing the consumer side's BufferQueue size may
1885 // not take effect immediately unless we create a new EGLSurface.
1886 // Note that frame size change doesn't always imply surface size change (eg.
1887 // drag resizing uses fullscreen surface), need to check surfaceSizeChanged
1888 // flag from WindowManager.
John Reck79d81e62013-11-05 13:26:57 -08001889 mAttachInfo.mHardwareRenderer.updateSurface(mSurface);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001890 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08001891 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08001892 return;
1893 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001894 }
Chong Zhang0275e392015-09-17 10:41:44 -07001895
Jorim Jaggi4846ee32016-01-07 17:39:12 +01001896 final boolean freeformResizing = (relayoutResult
1897 & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFORM) != 0;
1898 final boolean dockedResizing = (relayoutResult
1899 & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_DOCKED) != 0;
1900 final boolean dragResizing = freeformResizing || dockedResizing;
Chong Zhang0275e392015-09-17 10:41:44 -07001901 if (mDragResizing != dragResizing) {
Skuhneb8160872015-09-22 09:51:39 -07001902 if (dragResizing) {
Jorim Jaggi4846ee32016-01-07 17:39:12 +01001903 mResizeMode = freeformResizing
1904 ? RESIZE_MODE_FREEFORM
1905 : RESIZE_MODE_DOCKED_DIVIDER;
Jorim Jaggic39c7b02016-03-24 10:47:07 -07001906 startDragResizing(mPendingBackDropFrame,
1907 mWinFrame.equals(mPendingBackDropFrame), mPendingVisibleInsets,
1908 mPendingStableInsets, mResizeMode);
Skuhneb8160872015-09-22 09:51:39 -07001909 } else {
1910 // We shouldn't come here, but if we come we should end the resize.
1911 endDragResizing();
1912 }
Chong Zhang0275e392015-09-17 10:41:44 -07001913 }
Skuhneb8160872015-09-22 09:51:39 -07001914 if (!USE_MT_RENDERER) {
1915 if (dragResizing) {
1916 mCanvasOffsetX = mWinFrame.left;
1917 mCanvasOffsetY = mWinFrame.top;
1918 } else {
1919 mCanvasOffsetX = mCanvasOffsetY = 0;
1920 }
Chong Zhang0275e392015-09-17 10:41:44 -07001921 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001922 } catch (RemoteException e) {
1923 }
Romain Guy1d0c7082011-08-03 16:22:24 -07001924
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001925 if (DEBUG_ORIENTATION) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07001926 TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001927
Chris Craikd36a81f2014-07-17 10:16:51 -07001928 mAttachInfo.mWindowLeft = frame.left;
1929 mAttachInfo.mWindowTop = frame.top;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001930
1931 // !!FIXME!! This next section handles the case where we did not get the
1932 // window size we asked for. We should avoid this by getting a maximum size from
1933 // the window session beforehand.
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001934 if (mWidth != frame.width() || mHeight != frame.height()) {
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001935 mWidth = frame.width();
1936 mHeight = frame.height();
1937 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001938
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001939 if (mSurfaceHolder != null) {
1940 // The app owns the surface; tell it about what is going on.
1941 if (mSurface.isValid()) {
1942 // XXX .copyFrom() doesn't work!
1943 //mSurfaceHolder.mSurface.copyFrom(mSurface);
1944 mSurfaceHolder.mSurface = mSurface;
1945 }
Jeff Brown30bc34f2011-01-25 12:56:56 -08001946 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001947 mSurfaceHolder.mSurfaceLock.unlock();
1948 if (mSurface.isValid()) {
John Reck208c47c2016-06-09 16:26:21 -07001949 if (!hadSurface) {
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001950 mSurfaceHolder.ungetCallbacks();
1951
1952 mIsCreating = true;
1953 mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder);
1954 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1955 if (callbacks != null) {
1956 for (SurfaceHolder.Callback c : callbacks) {
1957 c.surfaceCreated(mSurfaceHolder);
1958 }
1959 }
1960 surfaceChanged = true;
1961 }
John Reck208c47c2016-06-09 16:26:21 -07001962 if (surfaceChanged || surfaceGenerationId != mSurface.getGenerationId()) {
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001963 mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
1964 lp.format, mWidth, mHeight);
1965 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1966 if (callbacks != null) {
1967 for (SurfaceHolder.Callback c : callbacks) {
1968 c.surfaceChanged(mSurfaceHolder, lp.format,
1969 mWidth, mHeight);
1970 }
1971 }
1972 }
1973 mIsCreating = false;
1974 } else if (hadSurface) {
1975 mSurfaceHolder.ungetCallbacks();
1976 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1977 mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
1978 if (callbacks != null) {
1979 for (SurfaceHolder.Callback c : callbacks) {
1980 c.surfaceDestroyed(mSurfaceHolder);
1981 }
1982 }
1983 mSurfaceHolder.mSurfaceLock.lock();
Jozef BABJAK93c5b6a2011-02-22 09:33:19 +01001984 try {
1985 mSurfaceHolder.mSurface = new Surface();
1986 } finally {
1987 mSurfaceHolder.mSurfaceLock.unlock();
1988 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001989 }
1990 }
Romain Guy53389bd2010-09-07 17:16:32 -07001991
John Reck51aaf902015-12-02 15:08:07 -08001992 final ThreadedRenderer hardwareRenderer = mAttachInfo.mHardwareRenderer;
Alan Viverette50210d92015-05-14 18:05:36 -07001993 if (hardwareRenderer != null && hardwareRenderer.isEnabled()) {
1994 if (hwInitialized
1995 || mWidth != hardwareRenderer.getWidth()
Robert Carr1bccabf2016-04-28 13:27:08 -07001996 || mHeight != hardwareRenderer.getHeight()
1997 || mNeedsHwRendererSetup) {
Alan Viverette50210d92015-05-14 18:05:36 -07001998 hardwareRenderer.setup(mWidth, mHeight, mAttachInfo,
1999 mWindowAttributes.surfaceInsets);
Robert Carr1bccabf2016-04-28 13:27:08 -07002000 mNeedsHwRendererSetup = false;
Romain Guy03985752011-07-11 15:33:51 -07002001 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002002 }
2003
Craig Mautner72d6f212015-02-19 16:33:09 -08002004 if (!mStopped || mReportNextDraw) {
Dianne Hackbornce418e62011-03-01 14:31:38 -08002005 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
Jeff Brown98365d72012-08-19 20:30:52 -07002006 (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
Dianne Hackbornce418e62011-03-01 14:31:38 -08002007 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
Chet Haased86fb2c2016-05-04 07:26:02 -07002008 || mHeight != host.getMeasuredHeight() || contentInsetsChanged ||
2009 updatedConfiguration) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002010 int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
2011 int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
Igor Murashkina86ab6402013-08-30 12:58:36 -07002012
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002013 if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed! mWidth="
Dianne Hackbornce418e62011-03-01 14:31:38 -08002014 + mWidth + " measuredWidth=" + host.getMeasuredWidth()
2015 + " mHeight=" + mHeight
2016 + " measuredHeight=" + host.getMeasuredHeight()
2017 + " coveredInsetsChanged=" + contentInsetsChanged);
Igor Murashkina86ab6402013-08-30 12:58:36 -07002018
Dianne Hackbornce418e62011-03-01 14:31:38 -08002019 // Ask host how big it wants to be
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002020 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Igor Murashkina86ab6402013-08-30 12:58:36 -07002021
Dianne Hackbornce418e62011-03-01 14:31:38 -08002022 // Implementation of weights from WindowManager.LayoutParams
2023 // We just grow the dimensions as needed and re-measure if
2024 // needs be
2025 int width = host.getMeasuredWidth();
2026 int height = host.getMeasuredHeight();
2027 boolean measureAgain = false;
Igor Murashkina86ab6402013-08-30 12:58:36 -07002028
Dianne Hackbornce418e62011-03-01 14:31:38 -08002029 if (lp.horizontalWeight > 0.0f) {
2030 width += (int) ((mWidth - width) * lp.horizontalWeight);
2031 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
2032 MeasureSpec.EXACTLY);
2033 measureAgain = true;
2034 }
2035 if (lp.verticalWeight > 0.0f) {
2036 height += (int) ((mHeight - height) * lp.verticalWeight);
2037 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
2038 MeasureSpec.EXACTLY);
2039 measureAgain = true;
2040 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07002041
Dianne Hackbornce418e62011-03-01 14:31:38 -08002042 if (measureAgain) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002043 if (DEBUG_LAYOUT) Log.v(mTag,
Dianne Hackbornce418e62011-03-01 14:31:38 -08002044 "And hey let's measure once more: width=" + width
2045 + " height=" + height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002046 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackbornce418e62011-03-01 14:31:38 -08002047 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07002048
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002049 layoutRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002050 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002051 }
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07002052 } else {
2053 // Not the first pass and no window/insets/visibility change but the window
2054 // may have moved and we need check that and if so to update the left and right
2055 // in the attach info. We translate only the window frame since on window move
2056 // the window manager tells us only for the new frame but the insets are the
2057 // same and we do not want to translate them more than once.
Jorim Jaggi2e95a482016-01-14 17:36:55 -08002058 maybeHandleWindowMove(frame);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002059 }
2060
Craig Mautner72d6f212015-02-19 16:33:09 -08002061 final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002062 boolean triggerGlobalLayoutListener = didLayout
Chris Craikd36a81f2014-07-17 10:16:51 -07002063 || mAttachInfo.mRecomputeGlobalAttributes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002064 if (didLayout) {
Jorim Jaggi26d02d22016-02-24 18:37:51 -05002065 performLayout(lp, mWidth, mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002066
Mathias Agopian54e3d3842013-04-12 15:13:12 -07002067 // By this point all views have been sized and positioned
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002068 // We can compute the transparent area
2069
Dianne Hackborn4702a852012-08-17 15:18:29 -07002070 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002071 // start out transparent
2072 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
2073 host.getLocationInWindow(mTmpLocation);
2074 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
2075 mTmpLocation[0] + host.mRight - host.mLeft,
2076 mTmpLocation[1] + host.mBottom - host.mTop);
2077
2078 host.gatherTransparentRegion(mTransparentRegion);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07002079 if (mTranslator != null) {
2080 mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
2081 }
2082
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002083 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
2084 mPreviousTransparentRegion.set(mTransparentRegion);
Mathias Agopian54e3d3842013-04-12 15:13:12 -07002085 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002086 // reconfigure window manager
2087 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002088 mWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002089 } catch (RemoteException e) {
2090 }
2091 }
2092 }
2093
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002094 if (DBG) {
2095 System.out.println("======================================");
Chet Haase4610eef2015-12-03 07:38:11 -08002096 System.out.println("performTraversals -- after setFrame");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002097 host.debug();
2098 }
2099 }
2100
2101 if (triggerGlobalLayoutListener) {
Chris Craikd36a81f2014-07-17 10:16:51 -07002102 mAttachInfo.mRecomputeGlobalAttributes = false;
2103 mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002104 }
2105
2106 if (computesInternalInsets) {
Jeff Brownfbf09772011-01-16 14:06:57 -08002107 // Clear the original insets.
Chris Craikd36a81f2014-07-17 10:16:51 -07002108 final ViewTreeObserver.InternalInsetsInfo insets = mAttachInfo.mGivenInternalInsets;
Jeff Brownfbf09772011-01-16 14:06:57 -08002109 insets.reset();
2110
2111 // Compute new insets in place.
Chris Craikd36a81f2014-07-17 10:16:51 -07002112 mAttachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
2113 mAttachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty();
Jeff Brownfbf09772011-01-16 14:06:57 -08002114
2115 // Tell the window manager.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002116 if (insetsPending || !mLastGivenInsets.equals(insets)) {
2117 mLastGivenInsets.set(insets);
Jeff Brownfbf09772011-01-16 14:06:57 -08002118
2119 // Translate insets to screen coordinates if needed.
2120 final Rect contentInsets;
2121 final Rect visibleInsets;
2122 final Region touchableRegion;
2123 if (mTranslator != null) {
2124 contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
2125 visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
2126 touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
2127 } else {
2128 contentInsets = insets.contentInsets;
2129 visibleInsets = insets.visibleInsets;
2130 touchableRegion = insets.touchableRegion;
2131 }
2132
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002133 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002134 mWindowSession.setInsets(mWindow, insets.mTouchableInsets,
Jeff Brownfbf09772011-01-16 14:06:57 -08002135 contentInsets, visibleInsets, touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002136 } catch (RemoteException e) {
2137 }
2138 }
2139 }
Romain Guy8506ab42009-06-11 17:35:47 -07002140
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002141 if (mFirst) {
2142 // handle first focus request
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002143 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: mView.hasFocus()="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002144 + mView.hasFocus());
2145 if (mView != null) {
2146 if (!mView.hasFocus()) {
2147 mView.requestFocus(View.FOCUS_FORWARD);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002148 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: requested focused view="
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002149 + mView.findFocus());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002150 } else {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002151 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: existing focused view="
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002152 + mView.findFocus());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002153 }
2154 }
2155 }
2156
Alan Viverette64bf97a2015-09-18 16:42:00 -04002157 final boolean changedVisibility = (viewVisibilityChanged || mFirst) && isViewVisible;
2158 final boolean hasWindowFocus = mAttachInfo.mHasWindowFocus && isViewVisible;
2159 final boolean regainedFocus = hasWindowFocus && mLostWindowFocus;
2160 if (regainedFocus) {
2161 mLostWindowFocus = false;
2162 } else if (!hasWindowFocus && mHadWindowFocus) {
2163 mLostWindowFocus = true;
2164 }
2165
2166 if (changedVisibility || regainedFocus) {
2167 host.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
2168 }
2169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002170 mFirst = false;
2171 mWillDrawSoon = false;
2172 mNewSurfaceNeeded = false;
Jorim Jaggi4846ee32016-01-07 17:39:12 +01002173 mActivityRelaunched = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002174 mViewVisibility = viewVisibility;
Alan Viverette64bf97a2015-09-18 16:42:00 -04002175 mHadWindowFocus = hasWindowFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002176
Alan Viverette64bf97a2015-09-18 16:42:00 -04002177 if (hasWindowFocus && !isInLocalFocusMode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002178 final boolean imTarget = WindowManager.LayoutParams
2179 .mayUseInputMethod(mWindowAttributes.flags);
2180 if (imTarget != mLastWasImTarget) {
2181 mLastWasImTarget = imTarget;
2182 InputMethodManager imm = InputMethodManager.peekInstance();
2183 if (imm != null && imTarget) {
Alan Viverette64bf97a2015-09-18 16:42:00 -04002184 imm.onPreWindowFocus(mView, hasWindowFocus);
Yohei Yukawa5f059652015-05-14 22:16:41 -07002185 imm.onPostWindowFocus(mView, mView.findFocus(),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002186 mWindowAttributes.softInputMode,
2187 !mHasHadWindowFocus, mWindowAttributes.flags);
2188 }
2189 }
2190 }
Romain Guy8506ab42009-06-11 17:35:47 -07002191
Jeff Brown96e942d2011-11-30 19:55:01 -08002192 // Remember if we must report the next draw.
Jeff Brown98365d72012-08-19 20:30:52 -07002193 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
Jeff Brown96e942d2011-11-30 19:55:01 -08002194 mReportNextDraw = true;
2195 }
2196
Alan Viverette64bf97a2015-09-18 16:42:00 -04002197 boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002198
Jorim Jaggi75c21ca2016-03-28 19:26:09 -04002199 if (!cancelDraw && !newSurface) {
Chet Haase9c450412015-10-01 13:25:58 -07002200 if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
2201 for (int i = 0; i < mPendingTransitions.size(); ++i) {
2202 mPendingTransitions.get(i).startChangingAnimations();
Chet Haased56c6952011-09-07 08:46:23 -07002203 }
Chet Haase9c450412015-10-01 13:25:58 -07002204 mPendingTransitions.clear();
Chet Haased56c6952011-09-07 08:46:23 -07002205 }
Chet Haase9c450412015-10-01 13:25:58 -07002206
2207 performDraw();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002208 } else {
Alan Viverette64bf97a2015-09-18 16:42:00 -04002209 if (isViewVisible) {
Chris Wren78cb7cf2012-05-15 12:36:44 -04002210 // Try again
2211 scheduleTraversals();
2212 } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
Chet Haased56c6952011-09-07 08:46:23 -07002213 for (int i = 0; i < mPendingTransitions.size(); ++i) {
2214 mPendingTransitions.get(i).endChangingAnimations();
2215 }
2216 mPendingTransitions.clear();
2217 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002218 }
Craig Mautnerdf2390a2012-08-29 20:59:22 -07002219
2220 mIsInTraversal = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002221 }
2222
Jorim Jaggi2e95a482016-01-14 17:36:55 -08002223 private void maybeHandleWindowMove(Rect frame) {
2224
2225 // TODO: Well, we are checking whether the frame has changed similarly
2226 // to how this is done for the insets. This is however incorrect since
2227 // the insets and the frame are translated. For example, the old frame
2228 // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new
2229 // reported frame is (2, 2 - 2, 2) which implies no change but this is not
2230 // true since we are comparing a not translated value to a translated one.
2231 // This scenario is rare but we may want to fix that.
2232
2233 final boolean windowMoved = mAttachInfo.mWindowLeft != frame.left
2234 || mAttachInfo.mWindowTop != frame.top;
2235 if (windowMoved) {
2236 if (mTranslator != null) {
2237 mTranslator.translateRectInScreenToAppWinFrame(frame);
2238 }
2239 mAttachInfo.mWindowLeft = frame.left;
2240 mAttachInfo.mWindowTop = frame.top;
Teng-Hui Zhu27571282016-05-12 15:53:53 -07002241 }
2242 if (windowMoved || mAttachInfo.mNeedsUpdateLightCenter) {
2243 // Update the light position for the new offsets.
Jorim Jaggi2e95a482016-01-14 17:36:55 -08002244 if (mAttachInfo.mHardwareRenderer != null) {
2245 mAttachInfo.mHardwareRenderer.setLightCenter(mAttachInfo);
2246 }
Teng-Hui Zhu27571282016-05-12 15:53:53 -07002247 mAttachInfo.mNeedsUpdateLightCenter = false;
Jorim Jaggi2e95a482016-01-14 17:36:55 -08002248 }
2249 }
Teng-Hui Zhu27571282016-05-12 15:53:53 -07002250
Romain Guy3696779b2013-01-28 14:04:07 -08002251 private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002252 Log.e(mTag, "OutOfResourcesException initializing HW surface", e);
Romain Guy3696779b2013-01-28 14:04:07 -08002253 try {
2254 if (!mWindowSession.outOfMemory(mWindow) &&
2255 Process.myUid() != Process.SYSTEM_UID) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002256 Slog.w(mTag, "No processes killed for memory; killing self");
Romain Guy3696779b2013-01-28 14:04:07 -08002257 Process.killProcess(Process.myPid());
2258 }
2259 } catch (RemoteException ex) {
2260 }
2261 mLayoutRequested = true; // ask wm for a new surface next time.
2262 }
2263
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002264 private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
2265 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
2266 try {
2267 mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
2268 } finally {
2269 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2270 }
2271 }
2272
Chet Haase97140572012-09-13 14:56:47 -07002273 /**
2274 * Called by {@link android.view.View#isInLayout()} to determine whether the view hierarchy
2275 * is currently undergoing a layout pass.
2276 *
2277 * @return whether the view hierarchy is currently undergoing a layout pass
2278 */
2279 boolean isInLayout() {
2280 return mInLayout;
2281 }
2282
2283 /**
Chet Haasecc699b42012-12-13 09:06:55 -08002284 * Called by {@link android.view.View#requestLayout()} if the view hierarchy is currently
2285 * undergoing a layout pass. requestLayout() should not generally be called during layout,
2286 * unless the container hierarchy knows what it is doing (i.e., it is fine as long as
2287 * all children in that container hierarchy are measured and laid out at the end of the layout
2288 * pass for that container). If requestLayout() is called anyway, we handle it correctly
2289 * by registering all requesters during a frame as it proceeds. At the end of the frame,
2290 * we check all of those views to see if any still have pending layout requests, which
2291 * indicates that they were not correctly handled by their container hierarchy. If that is
2292 * the case, we clear all such flags in the tree, to remove the buggy flag state that leads
2293 * to blank containers, and force a second request/measure/layout pass in this frame. If
Chet Haase97140572012-09-13 14:56:47 -07002294 * more requestLayout() calls are received during that second layout pass, we post those
Chet Haasecc699b42012-12-13 09:06:55 -08002295 * requests to the next frame to avoid possible infinite loops.
2296 *
2297 * <p>The return value from this method indicates whether the request should proceed
2298 * (if it is a request during the first layout pass) or should be skipped and posted to the
2299 * next frame (if it is a request during the second layout pass).</p>
Chet Haase97140572012-09-13 14:56:47 -07002300 *
2301 * @param view the view that requested the layout.
Chet Haasecc699b42012-12-13 09:06:55 -08002302 *
2303 * @return true if request should proceed, false otherwise.
Chet Haase97140572012-09-13 14:56:47 -07002304 */
Chet Haasecc699b42012-12-13 09:06:55 -08002305 boolean requestLayoutDuringLayout(final View view) {
2306 if (view.mParent == null || view.mAttachInfo == null) {
2307 // Would not normally trigger another layout, so just let it pass through as usual
2308 return true;
2309 }
Chet Haase107a4822013-03-13 06:46:50 -07002310 if (!mLayoutRequesters.contains(view)) {
2311 mLayoutRequesters.add(view);
2312 }
Chet Haase97140572012-09-13 14:56:47 -07002313 if (!mHandlingLayoutInLayoutRequest) {
Chet Haase107a4822013-03-13 06:46:50 -07002314 // Let the request proceed normally; it will be processed in a second layout pass
2315 // if necessary
Chet Haasecc699b42012-12-13 09:06:55 -08002316 return true;
Chet Haase97140572012-09-13 14:56:47 -07002317 } else {
Chet Haase107a4822013-03-13 06:46:50 -07002318 // Don't let the request proceed during the second layout pass.
2319 // It will post to the next frame instead.
Chet Haasecc699b42012-12-13 09:06:55 -08002320 return false;
Chet Haase97140572012-09-13 14:56:47 -07002321 }
2322 }
2323
Chet Haase3efa7b52012-12-03 08:33:17 -08002324 private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
2325 int desiredWindowHeight) {
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002326 mLayoutRequested = false;
2327 mScrollMayChange = true;
Chet Haase97140572012-09-13 14:56:47 -07002328 mInLayout = true;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002329
2330 final View host = mView;
2331 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002332 Log.v(mTag, "Laying out " + host + " to (" +
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002333 host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
2334 }
2335
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002336 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
2337 try {
2338 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haasecc699b42012-12-13 09:06:55 -08002339
Chet Haased5a83522012-11-21 16:24:44 -08002340 mInLayout = false;
Chet Haase97140572012-09-13 14:56:47 -07002341 int numViewsRequestingLayout = mLayoutRequesters.size();
2342 if (numViewsRequestingLayout > 0) {
Chet Haasecc699b42012-12-13 09:06:55 -08002343 // requestLayout() was called during layout.
2344 // If no layout-request flags are set on the requesting views, there is no problem.
2345 // If some requests are still pending, then we need to clear those flags and do
2346 // a full request/measure/layout pass to handle this situation.
Chet Haase107a4822013-03-13 06:46:50 -07002347 ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
2348 false);
2349 if (validLayoutRequesters != null) {
2350 // Set this flag to indicate that any further requests are happening during
2351 // the second pass, which may result in posting those requests to the next
2352 // frame instead
Chet Haasecc699b42012-12-13 09:06:55 -08002353 mHandlingLayoutInLayoutRequest = true;
Chet Haase107a4822013-03-13 06:46:50 -07002354
2355 // Process fresh layout requests, then measure and layout
2356 int numValidRequests = validLayoutRequesters.size();
Chet Haasecc699b42012-12-13 09:06:55 -08002357 for (int i = 0; i < numValidRequests; ++i) {
Chet Haase107a4822013-03-13 06:46:50 -07002358 final View view = validLayoutRequesters.get(i);
2359 Log.w("View", "requestLayout() improperly called by " + view +
2360 " during layout: running second layout pass");
2361 view.requestLayout();
Chet Haasecc699b42012-12-13 09:06:55 -08002362 }
2363 measureHierarchy(host, lp, mView.getContext().getResources(),
2364 desiredWindowWidth, desiredWindowHeight);
2365 mInLayout = true;
2366 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haase107a4822013-03-13 06:46:50 -07002367
Chet Haasecc699b42012-12-13 09:06:55 -08002368 mHandlingLayoutInLayoutRequest = false;
Chet Haase107a4822013-03-13 06:46:50 -07002369
2370 // Check the valid requests again, this time without checking/clearing the
2371 // layout flags, since requests happening during the second pass get noop'd
2372 validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);
2373 if (validLayoutRequesters != null) {
2374 final ArrayList<View> finalRequesters = validLayoutRequesters;
2375 // Post second-pass requests to the next frame
2376 getRunQueue().post(new Runnable() {
2377 @Override
2378 public void run() {
2379 int numValidRequests = finalRequesters.size();
2380 for (int i = 0; i < numValidRequests; ++i) {
2381 final View view = finalRequesters.get(i);
2382 Log.w("View", "requestLayout() improperly called by " + view +
2383 " during second layout pass: posting in next frame");
2384 view.requestLayout();
2385 }
2386 }
2387 });
2388 }
Chet Haasecc699b42012-12-13 09:06:55 -08002389 }
Chet Haase107a4822013-03-13 06:46:50 -07002390
Chet Haase97140572012-09-13 14:56:47 -07002391 }
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002392 } finally {
2393 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2394 }
Chet Haase97140572012-09-13 14:56:47 -07002395 mInLayout = false;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002396 }
2397
Chet Haase107a4822013-03-13 06:46:50 -07002398 /**
2399 * This method is called during layout when there have been calls to requestLayout() during
2400 * layout. It walks through the list of views that requested layout to determine which ones
2401 * still need it, based on visibility in the hierarchy and whether they have already been
2402 * handled (as is usually the case with ListView children).
2403 *
2404 * @param layoutRequesters The list of views that requested layout during layout
2405 * @param secondLayoutRequests Whether the requests were issued during the second layout pass.
2406 * If so, the FORCE_LAYOUT flag was not set on requesters.
2407 * @return A list of the actual views that still need to be laid out.
2408 */
2409 private ArrayList<View> getValidLayoutRequesters(ArrayList<View> layoutRequesters,
2410 boolean secondLayoutRequests) {
2411
2412 int numViewsRequestingLayout = layoutRequesters.size();
2413 ArrayList<View> validLayoutRequesters = null;
2414 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2415 View view = layoutRequesters.get(i);
2416 if (view != null && view.mAttachInfo != null && view.mParent != null &&
2417 (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) ==
2418 View.PFLAG_FORCE_LAYOUT)) {
2419 boolean gone = false;
2420 View parent = view;
2421 // Only trigger new requests for views in a non-GONE hierarchy
2422 while (parent != null) {
2423 if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) {
2424 gone = true;
2425 break;
2426 }
2427 if (parent.mParent instanceof View) {
2428 parent = (View) parent.mParent;
2429 } else {
2430 parent = null;
2431 }
2432 }
2433 if (!gone) {
2434 if (validLayoutRequesters == null) {
2435 validLayoutRequesters = new ArrayList<View>();
2436 }
2437 validLayoutRequesters.add(view);
2438 }
2439 }
2440 }
2441 if (!secondLayoutRequests) {
2442 // If we're checking the layout flags, then we need to clean them up also
2443 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2444 View view = layoutRequesters.get(i);
2445 while (view != null &&
2446 (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
2447 view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
2448 if (view.mParent instanceof View) {
2449 view = (View) view.mParent;
2450 } else {
2451 view = null;
2452 }
2453 }
2454 }
2455 }
2456 layoutRequesters.clear();
2457 return validLayoutRequesters;
2458 }
2459
Igor Murashkina86ab6402013-08-30 12:58:36 -07002460 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002461 public void requestTransparentRegion(View child) {
2462 // the test below should not fail unless someone is messing with us
2463 checkThread();
2464 if (mView == child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002465 mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002466 // Need to make sure we re-evaluate the window attributes next
2467 // time around, to ensure the window has the correct format.
2468 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -07002469 mWindowAttributesChangesFlag = 0;
Mathias Agopian1bd80ad2010-11-04 17:13:39 -07002470 requestLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002471 }
2472 }
2473
2474 /**
2475 * Figures out the measure spec for the root view in a window based on it's
2476 * layout params.
2477 *
2478 * @param windowSize
2479 * The available width or height of the window
2480 *
2481 * @param rootDimension
2482 * The layout params for one dimension (width or height) of the
2483 * window.
2484 *
2485 * @return The measure spec to use to measure the root view.
2486 */
Romain Guya998dff2012-03-23 18:58:36 -07002487 private static int getRootMeasureSpec(int windowSize, int rootDimension) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002488 int measureSpec;
2489 switch (rootDimension) {
2490
Romain Guy980a9382010-01-08 15:06:28 -08002491 case ViewGroup.LayoutParams.MATCH_PARENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002492 // Window can't resize. Force root view to be windowSize.
2493 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
2494 break;
2495 case ViewGroup.LayoutParams.WRAP_CONTENT:
2496 // Window can resize. Set max size for root view.
2497 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
2498 break;
2499 default:
2500 // Window wants to be an exact size. Force root view to be that size.
2501 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
2502 break;
2503 }
2504 return measureSpec;
2505 }
2506
Alan Viveretteccb11e12014-07-08 16:04:02 -07002507 int mHardwareXOffset;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002508 int mHardwareYOffset;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002509
Igor Murashkina86ab6402013-08-30 12:58:36 -07002510 @Override
Chris Craikf6829a02015-03-10 10:28:59 -07002511 public void onHardwarePreDraw(DisplayListCanvas canvas) {
Alan Viveretteccb11e12014-07-08 16:04:02 -07002512 canvas.translate(-mHardwareXOffset, -mHardwareYOffset);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002513 }
2514
Igor Murashkina86ab6402013-08-30 12:58:36 -07002515 @Override
Chris Craikf6829a02015-03-10 10:28:59 -07002516 public void onHardwarePostDraw(DisplayListCanvas canvas) {
Alan Viverette632af842014-10-28 13:45:11 -07002517 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Jorim Jaggi16b63192016-03-25 18:32:19 -07002518 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
2519 mWindowCallbacks.get(i).onPostDraw(canvas);
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002520 }
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002521 }
2522
Chet Haaseed30fd82011-04-22 16:18:45 -07002523 /**
2524 * @hide
2525 */
2526 void outputDisplayList(View view) {
Chris Craik356b5fe2015-07-07 10:39:36 -07002527 view.mRenderNode.output();
John Recke248bd12015-08-05 13:53:53 -07002528 if (mAttachInfo.mHardwareRenderer != null) {
2529 ((ThreadedRenderer)mAttachInfo.mHardwareRenderer).serializeDisplayListTree();
2530 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002531 }
2532
2533 /**
2534 * @see #PROPERTY_PROFILE_RENDERING
2535 */
2536 private void profileRendering(boolean enabled) {
2537 if (mProfileRendering) {
2538 mRenderProfilingEnabled = enabled;
Chris Craikae4f32042013-02-07 12:57:10 -08002539
2540 if (mRenderProfiler != null) {
2541 mChoreographer.removeFrameCallback(mRenderProfiler);
2542 }
2543 if (mRenderProfilingEnabled) {
2544 if (mRenderProfiler == null) {
2545 mRenderProfiler = new Choreographer.FrameCallback() {
2546 @Override
2547 public void doFrame(long frameTimeNanos) {
2548 mDirty.set(0, 0, mWidth, mHeight);
2549 scheduleTraversals();
2550 if (mRenderProfilingEnabled) {
2551 mChoreographer.postFrameCallback(mRenderProfiler);
2552 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002553 }
Chris Craikae4f32042013-02-07 12:57:10 -08002554 };
2555 }
Romain Guy5bb3c732012-11-29 17:52:58 -08002556 mChoreographer.postFrameCallback(mRenderProfiler);
Romain Guy59a12ca2011-06-09 17:48:21 -07002557 } else {
Romain Guy59a12ca2011-06-09 17:48:21 -07002558 mRenderProfiler = null;
Chet Haaseed30fd82011-04-22 16:18:45 -07002559 }
2560 }
2561 }
2562
Chet Haase2f2022a2011-10-11 06:41:59 -07002563 /**
2564 * Called from draw() when DEBUG_FPS is enabled
2565 */
2566 private void trackFPS() {
2567 // Tracks frames per second drawn. First value in a series of draws may be bogus
2568 // because it down not account for the intervening idle time
2569 long nowTime = System.currentTimeMillis();
2570 if (mFpsStartTime < 0) {
2571 mFpsStartTime = mFpsPrevTime = nowTime;
2572 mFpsNumFrames = 0;
2573 } else {
2574 ++mFpsNumFrames;
2575 String thisHash = Integer.toHexString(System.identityHashCode(this));
2576 long frameTime = nowTime - mFpsPrevTime;
2577 long totalTime = nowTime - mFpsStartTime;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002578 Log.v(mTag, "0x" + thisHash + "\tFrame time:\t" + frameTime);
Chet Haase2f2022a2011-10-11 06:41:59 -07002579 mFpsPrevTime = nowTime;
2580 if (totalTime > 1000) {
2581 float fps = (float) mFpsNumFrames * 1000 / totalTime;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002582 Log.v(mTag, "0x" + thisHash + "\tFPS:\t" + fps);
Chet Haase2f2022a2011-10-11 06:41:59 -07002583 mFpsStartTime = nowTime;
2584 mFpsNumFrames = 0;
2585 }
2586 }
2587 }
2588
Jeff Brown96e942d2011-11-30 19:55:01 -08002589 private void performDraw() {
Jeff Brownd912e1f2014-04-11 18:46:22 -07002590 if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
Craig Mautner006f0e42012-03-21 11:00:32 -07002591 return;
2592 }
Romain Guy7e4e5612012-03-05 14:37:29 -08002593
Jeff Brown96e942d2011-11-30 19:55:01 -08002594 final boolean fullRedrawNeeded = mFullRedrawNeeded;
2595 mFullRedrawNeeded = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002596
Romain Guy1f59e5c2012-05-06 14:11:16 -07002597 mIsDrawing = true;
Jeff Brown481c1572012-03-09 14:41:15 -08002598 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
2599 try {
2600 draw(fullRedrawNeeded);
2601 } finally {
Romain Guy1f59e5c2012-05-06 14:11:16 -07002602 mIsDrawing = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002603 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2604 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002605
John Reck119907c2014-08-14 09:02:01 -07002606 // For whatever reason we didn't create a HardwareRenderer, end any
2607 // hardware animations that are now dangling
2608 if (mAttachInfo.mPendingAnimatingRenderNodes != null) {
2609 final int count = mAttachInfo.mPendingAnimatingRenderNodes.size();
2610 for (int i = 0; i < count; i++) {
2611 mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators();
2612 }
2613 mAttachInfo.mPendingAnimatingRenderNodes.clear();
2614 }
2615
Jeff Brown96e942d2011-11-30 19:55:01 -08002616 if (mReportNextDraw) {
2617 mReportNextDraw = false;
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07002618
2619 // if we're using multi-thread renderer, wait for the window frame draws
2620 if (mWindowDrawCountDown != null) {
2621 try {
2622 mWindowDrawCountDown.await();
2623 } catch (InterruptedException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002624 Log.e(mTag, "Window redraw count down interruped!");
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07002625 }
2626 mWindowDrawCountDown = null;
2627 }
2628
John Reck28ad7b52014-04-07 16:59:25 -07002629 if (mAttachInfo.mHardwareRenderer != null) {
2630 mAttachInfo.mHardwareRenderer.fence();
John Reck8afcc762016-04-13 10:24:06 -07002631 mAttachInfo.mHardwareRenderer.setStopped(mStopped);
John Reck28ad7b52014-04-07 16:59:25 -07002632 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002633
2634 if (LOCAL_LOGV) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002635 Log.v(mTag, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
Jeff Brown96e942d2011-11-30 19:55:01 -08002636 }
2637 if (mSurfaceHolder != null && mSurface.isValid()) {
2638 mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
2639 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
2640 if (callbacks != null) {
2641 for (SurfaceHolder.Callback c : callbacks) {
2642 if (c instanceof SurfaceHolder.Callback2) {
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08002643 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(mSurfaceHolder);
Jeff Brown96e942d2011-11-30 19:55:01 -08002644 }
2645 }
2646 }
2647 }
2648 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002649 mWindowSession.finishDrawing(mWindow);
Jeff Brown96e942d2011-11-30 19:55:01 -08002650 } catch (RemoteException e) {
2651 }
2652 }
2653 }
2654
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002655 private void draw(boolean fullRedrawNeeded) {
2656 Surface surface = mSurface;
Romain Guyfbb93fa2012-12-03 18:50:35 -08002657 if (!surface.isValid()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002658 return;
2659 }
2660
Chet Haase2f2022a2011-10-11 06:41:59 -07002661 if (DEBUG_FPS) {
2662 trackFPS();
2663 }
2664
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002665 if (!sFirstDrawComplete) {
2666 synchronized (sFirstDrawHandlers) {
2667 sFirstDrawComplete = true;
Romain Guy812ccbe2010-06-01 14:07:24 -07002668 final int count = sFirstDrawHandlers.size();
2669 for (int i = 0; i< count; i++) {
Jeff Browna175a5b2012-02-15 19:18:31 -08002670 mHandler.post(sFirstDrawHandlers.get(i));
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002671 }
2672 }
2673 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002674
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002675 scrollToRectOrFocus(null, false);
2676
Chris Craikd36a81f2014-07-17 10:16:51 -07002677 if (mAttachInfo.mViewScrollChanged) {
2678 mAttachInfo.mViewScrollChanged = false;
2679 mAttachInfo.mTreeObserver.dispatchOnScrollChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002680 }
Romain Guy8506ab42009-06-11 17:35:47 -07002681
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002682 boolean animating = mScroller != null && mScroller.computeScrollOffset();
Alan Viveretteccb11e12014-07-08 16:04:02 -07002683 final int curScrollY;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002684 if (animating) {
Alan Viveretteccb11e12014-07-08 16:04:02 -07002685 curScrollY = mScroller.getCurrY();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002686 } else {
Alan Viveretteccb11e12014-07-08 16:04:02 -07002687 curScrollY = mScrollY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002688 }
Alan Viveretteccb11e12014-07-08 16:04:02 -07002689 if (mCurScrollY != curScrollY) {
2690 mCurScrollY = curScrollY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002691 fullRedrawNeeded = true;
Adrian Roos0e7ae4e2014-10-01 15:33:22 +02002692 if (mView instanceof RootViewSurfaceTaker) {
2693 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
2694 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002695 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002696
Chris Craikd36a81f2014-07-17 10:16:51 -07002697 final float appScale = mAttachInfo.mApplicationScale;
2698 final boolean scalingRequired = mAttachInfo.mScalingRequired;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002699
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002700 int resizeAlpha = 0;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002701
Jeff Brown96e942d2011-11-30 19:55:01 -08002702 final Rect dirty = mDirty;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002703 if (mSurfaceHolder != null) {
2704 // The app owns the surface, we won't draw.
2705 dirty.setEmpty();
Derek Sollenberger8d948352015-07-16 09:27:59 -04002706 if (animating && mScroller != null) {
2707 mScroller.abortAnimation();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002708 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002709 return;
2710 }
Romain Guy58ef7fb2010-09-13 12:52:37 -07002711
2712 if (fullRedrawNeeded) {
Chris Craikd36a81f2014-07-17 10:16:51 -07002713 mAttachInfo.mIgnoreDirtyState = true;
Romain Guyc3166e12011-08-08 15:00:03 -07002714 dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
Romain Guy58ef7fb2010-09-13 12:52:37 -07002715 }
Chet Haasead4f7032011-06-22 09:18:31 -07002716
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002717 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002718 Log.v(mTag, "Draw " + mView + "/"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002719 + mWindowAttributes.getTitle()
2720 + ": dirty={" + dirty.left + "," + dirty.top
2721 + "," + dirty.right + "," + dirty.bottom + "} surface="
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002722 + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
2723 appScale + ", width=" + mWidth + ", height=" + mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002724 }
2725
Chris Craikd36a81f2014-07-17 10:16:51 -07002726 mAttachInfo.mTreeObserver.dispatchOnDraw();
Romain Guy25eba5c2012-04-04 17:29:03 -07002727
Chong Zhang0275e392015-09-17 10:41:44 -07002728 int xOffset = -mCanvasOffsetX;
2729 int yOffset = -mCanvasOffsetY + curScrollY;
Alan Viverettea51cab92014-07-16 15:15:49 -07002730 final WindowManager.LayoutParams params = mWindowAttributes;
2731 final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
2732 if (surfaceInsets != null) {
2733 xOffset -= surfaceInsets.left;
2734 yOffset -= surfaceInsets.top;
2735
2736 // Offset dirty rect for surface insets.
2737 dirty.offset(surfaceInsets.left, surfaceInsets.right);
2738 }
2739
Alan Viverette632af842014-10-28 13:45:11 -07002740 boolean accessibilityFocusDirty = false;
2741 final Drawable drawable = mAttachInfo.mAccessibilityFocusDrawable;
2742 if (drawable != null) {
2743 final Rect bounds = mAttachInfo.mTmpInvalRect;
2744 final boolean hasFocus = getAccessibilityFocusedRect(bounds);
2745 if (!hasFocus) {
2746 bounds.setEmpty();
2747 }
2748 if (!bounds.equals(drawable.getBounds())) {
2749 accessibilityFocusDirty = true;
2750 }
2751 }
2752
John Reckba6adf62015-02-19 14:36:50 -08002753 mAttachInfo.mDrawingTime =
2754 mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
2755
Alan Viverette632af842014-10-28 13:45:11 -07002756 if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
Chris Craikd36a81f2014-07-17 10:16:51 -07002757 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
Alan Viverette632af842014-10-28 13:45:11 -07002758 // If accessibility focus moved, always invalidate the root.
Jorim Jaggic39c7b02016-03-24 10:47:07 -07002759 boolean invalidateRoot = accessibilityFocusDirty || mInvalidateRootRequested;
2760 mInvalidateRootRequested = false;
Alan Viverette632af842014-10-28 13:45:11 -07002761
Jeff Brown96e942d2011-11-30 19:55:01 -08002762 // Draw with hardware renderer.
2763 mIsAnimating = false;
Alan Viverette632af842014-10-28 13:45:11 -07002764
John Reck0a973302014-07-16 13:29:45 -07002765 if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
2766 mHardwareYOffset = yOffset;
2767 mHardwareXOffset = xOffset;
Alan Viverette632af842014-10-28 13:45:11 -07002768 invalidateRoot = true;
Alan Viverettef6cf1a02014-08-11 14:13:02 -07002769 }
2770
Alan Viverette632af842014-10-28 13:45:11 -07002771 if (invalidateRoot) {
2772 mAttachInfo.mHardwareRenderer.invalidateRoot();
2773 }
2774
Jeff Brown96e942d2011-11-30 19:55:01 -08002775 dirty.setEmpty();
2776
Skuhne980ee472015-10-06 11:31:31 -07002777 // Stage the content drawn size now. It will be transferred to the renderer
2778 // shortly before the draw commands get send to the renderer.
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07002779 final boolean updated = updateContentDrawBounds();
2780
John Reck8afcc762016-04-13 10:24:06 -07002781 if (mReportNextDraw) {
2782 // report next draw overrides setStopped()
2783 // This value is re-sync'd to the value of mStopped
2784 // in the handling of mReportNextDraw post-draw.
2785 mAttachInfo.mHardwareRenderer.setStopped(false);
2786 }
2787
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07002788 if (updated) {
2789 requestDrawWindow();
2790 }
Jorim Jaggi0d6222d2016-04-18 20:42:10 -07002791
2792 mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this);
Romain Guy3696779b2013-01-28 14:04:07 -08002793 } else {
2794 // If we get here with a disabled & requested hardware renderer, something went
2795 // wrong (an invalidate posted right before we destroyed the hardware surface
2796 // for instance) so we should just bail out. Locking the surface with software
2797 // rendering at this point would lock it forever and prevent hardware renderer
2798 // from doing its job when it comes back.
2799 // Before we request a new frame we must however attempt to reinitiliaze the
2800 // hardware renderer if it's in requested state. This would happen after an
2801 // eglTerminate() for instance.
Chris Craikd36a81f2014-07-17 10:16:51 -07002802 if (mAttachInfo.mHardwareRenderer != null &&
2803 !mAttachInfo.mHardwareRenderer.isEnabled() &&
2804 mAttachInfo.mHardwareRenderer.isRequested()) {
Romain Guy3696779b2013-01-28 14:04:07 -08002805
2806 try {
Chris Craikd36a81f2014-07-17 10:16:51 -07002807 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
Alan Viverette50210d92015-05-14 18:05:36 -07002808 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
Igor Murashkina86ab6402013-08-30 12:58:36 -07002809 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002810 handleOutOfResourcesException(e);
2811 return;
2812 }
2813
2814 mFullRedrawNeeded = true;
2815 scheduleTraversals();
2816 return;
2817 }
2818
Chris Craikd36a81f2014-07-17 10:16:51 -07002819 if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
Romain Guy3696779b2013-01-28 14:04:07 -08002820 return;
2821 }
Jeff Brown95db2b22011-11-30 19:54:41 -08002822 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002823 }
Romain Guy8506ab42009-06-11 17:35:47 -07002824
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002825 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002826 mFullRedrawNeeded = true;
2827 scheduleTraversals();
2828 }
2829 }
2830
Romain Guy25eba5c2012-04-04 17:29:03 -07002831 /**
Alan Viveretteccb11e12014-07-08 16:04:02 -07002832 * @return true if drawing was successful, false if an error occurred
Romain Guy25eba5c2012-04-04 17:29:03 -07002833 */
Alan Viveretteccb11e12014-07-08 16:04:02 -07002834 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
Romain Guy25eba5c2012-04-04 17:29:03 -07002835 boolean scalingRequired, Rect dirty) {
2836
2837 // Draw with software renderer.
Alan Viverettea51cab92014-07-16 15:15:49 -07002838 final Canvas canvas;
Romain Guy25eba5c2012-04-04 17:29:03 -07002839 try {
Alan Viverettea51cab92014-07-16 15:15:49 -07002840 final int left = dirty.left;
2841 final int top = dirty.top;
2842 final int right = dirty.right;
2843 final int bottom = dirty.bottom;
Romain Guy25eba5c2012-04-04 17:29:03 -07002844
Romain Guy25eba5c2012-04-04 17:29:03 -07002845 canvas = mSurface.lockCanvas(dirty);
2846
Romain Guye55945e2013-04-04 15:26:04 -07002847 // The dirty rectangle can be modified by Surface.lockCanvas()
2848 //noinspection ConstantConditions
Alan Viverettea51cab92014-07-16 15:15:49 -07002849 if (left != dirty.left || top != dirty.top || right != dirty.right
2850 || bottom != dirty.bottom) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002851 attachInfo.mIgnoreDirtyState = true;
2852 }
2853
2854 // TODO: Do this in native
2855 canvas.setDensity(mDensity);
2856 } catch (Surface.OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002857 handleOutOfResourcesException(e);
Romain Guy25eba5c2012-04-04 17:29:03 -07002858 return false;
2859 } catch (IllegalArgumentException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002860 Log.e(mTag, "Could not lock surface", e);
Romain Guy25eba5c2012-04-04 17:29:03 -07002861 // Don't assume this is due to out of memory, it could be
2862 // something else, and if it is something else then we could
2863 // kill stuff (or ourself) for no reason.
2864 mLayoutRequested = true; // ask wm for a new surface next time.
2865 return false;
2866 }
2867
2868 try {
2869 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002870 Log.v(mTag, "Surface " + surface + " drawing to bitmap w="
Romain Guy25eba5c2012-04-04 17:29:03 -07002871 + canvas.getWidth() + ", h=" + canvas.getHeight());
2872 //canvas.drawARGB(255, 255, 0, 0);
2873 }
2874
Romain Guy25eba5c2012-04-04 17:29:03 -07002875 // If this bitmap's format includes an alpha channel, we
2876 // need to clear it before drawing so that the child will
2877 // properly re-composite its drawing on a transparent
2878 // background. This automatically respects the clip/dirty region
2879 // or
2880 // If we are applying an offset, we need to clear the area
2881 // where the offset doesn't appear to avoid having garbage
2882 // left in the blank areas.
Alan Viveretteccb11e12014-07-08 16:04:02 -07002883 if (!canvas.isOpaque() || yoff != 0 || xoff != 0) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002884 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
2885 }
2886
2887 dirty.setEmpty();
2888 mIsAnimating = false;
Dianne Hackborn4702a852012-08-17 15:18:29 -07002889 mView.mPrivateFlags |= View.PFLAG_DRAWN;
Romain Guy25eba5c2012-04-04 17:29:03 -07002890
2891 if (DEBUG_DRAW) {
2892 Context cxt = mView.getContext();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002893 Log.i(mTag, "Drawing: package:" + cxt.getPackageName() +
Romain Guy25eba5c2012-04-04 17:29:03 -07002894 ", metrics=" + cxt.getResources().getDisplayMetrics() +
2895 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
2896 }
2897 try {
Alan Viveretteccb11e12014-07-08 16:04:02 -07002898 canvas.translate(-xoff, -yoff);
Romain Guy25eba5c2012-04-04 17:29:03 -07002899 if (mTranslator != null) {
2900 mTranslator.translateCanvas(canvas);
2901 }
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002902 canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
Romain Guy25eba5c2012-04-04 17:29:03 -07002903 attachInfo.mSetIgnoreDirtyState = false;
2904
Romain Guy25eba5c2012-04-04 17:29:03 -07002905 mView.draw(canvas);
Alan Viverette632af842014-10-28 13:45:11 -07002906
2907 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Romain Guy25eba5c2012-04-04 17:29:03 -07002908 } finally {
2909 if (!attachInfo.mSetIgnoreDirtyState) {
2910 // Only clear the flag if it was not set during the mView.draw() call
2911 attachInfo.mIgnoreDirtyState = false;
2912 }
2913 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002914 } finally {
Romain Guydddcd222012-05-18 15:33:57 -07002915 try {
2916 surface.unlockCanvasAndPost(canvas);
2917 } catch (IllegalArgumentException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002918 Log.e(mTag, "Could not unlock surface", e);
Romain Guydddcd222012-05-18 15:33:57 -07002919 mLayoutRequested = true; // ask wm for a new surface next time.
2920 //noinspection ReturnInsideFinallyBlock
2921 return false;
2922 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002923
Romain Guy25eba5c2012-04-04 17:29:03 -07002924 if (LOCAL_LOGV) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08002925 Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost");
Romain Guy25eba5c2012-04-04 17:29:03 -07002926 }
2927 }
2928 return true;
2929 }
2930
Alan Viverette632af842014-10-28 13:45:11 -07002931 /**
2932 * We want to draw a highlight around the current accessibility focused.
2933 * Since adding a style for all possible view is not a viable option we
2934 * have this specialized drawing method.
2935 *
2936 * Note: We are doing this here to be able to draw the highlight for
2937 * virtual views in addition to real ones.
2938 *
2939 * @param canvas The canvas on which to draw.
2940 */
2941 private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
2942 final Rect bounds = mAttachInfo.mTmpInvalRect;
2943 if (getAccessibilityFocusedRect(bounds)) {
2944 final Drawable drawable = getAccessibilityFocusedDrawable();
2945 if (drawable != null) {
2946 drawable.setBounds(bounds);
2947 drawable.draw(canvas);
2948 }
2949 } else if (mAttachInfo.mAccessibilityFocusDrawable != null) {
2950 mAttachInfo.mAccessibilityFocusDrawable.setBounds(0, 0, 0, 0);
2951 }
2952 }
2953
2954 private boolean getAccessibilityFocusedRect(Rect bounds) {
2955 final AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
2956 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
2957 return false;
2958 }
2959
2960 final View host = mAccessibilityFocusedHost;
2961 if (host == null || host.mAttachInfo == null) {
2962 return false;
2963 }
2964
2965 final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
2966 if (provider == null) {
Svetoslavded133c2015-01-30 20:28:41 -08002967 host.getBoundsOnScreen(bounds, true);
Alan Viverette632af842014-10-28 13:45:11 -07002968 } else if (mAccessibilityFocusedVirtualView != null) {
2969 mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
2970 } else {
2971 return false;
2972 }
2973
Alan Viverette2232add2015-05-26 15:24:18 -07002974 // Transform the rect into window-relative coordinates.
Alan Viverette632af842014-10-28 13:45:11 -07002975 final AttachInfo attachInfo = mAttachInfo;
Alan Viverette2232add2015-05-26 15:24:18 -07002976 bounds.offset(0, attachInfo.mViewRootImpl.mScrollY);
Alan Viverette632af842014-10-28 13:45:11 -07002977 bounds.offset(-attachInfo.mWindowLeft, -attachInfo.mWindowTop);
Doris Liu9607fbe2015-05-28 17:17:28 -07002978 if (!bounds.intersect(0, 0, attachInfo.mViewRootImpl.mWidth,
2979 attachInfo.mViewRootImpl.mHeight)) {
2980 // If no intersection, set bounds to empty.
2981 bounds.setEmpty();
2982 }
Alan Viverette632af842014-10-28 13:45:11 -07002983 return !bounds.isEmpty();
2984 }
2985
2986 private Drawable getAccessibilityFocusedDrawable() {
Chris Craikd36a81f2014-07-17 10:16:51 -07002987 // Lazily load the accessibility focus drawable.
2988 if (mAttachInfo.mAccessibilityFocusDrawable == null) {
Alan Viverettef6cf1a02014-08-11 14:13:02 -07002989 final TypedValue value = new TypedValue();
Chris Craikd36a81f2014-07-17 10:16:51 -07002990 final boolean resolved = mView.mContext.getTheme().resolveAttribute(
2991 R.attr.accessibilityFocusedDrawable, value, true);
2992 if (resolved) {
2993 mAttachInfo.mAccessibilityFocusDrawable =
Alan Viverette8eea3ea2014-02-03 18:40:20 -08002994 mView.mContext.getDrawable(value.resourceId);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002995 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002996 }
Chris Craikd36a81f2014-07-17 10:16:51 -07002997 return mAttachInfo.mAccessibilityFocusDrawable;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002998 }
2999
Jorim Jaggic39c7b02016-03-24 10:47:07 -07003000 /**
3001 * Requests that the root render node is invalidated next time we perform a draw, such that
3002 * {@link WindowCallbacks#onPostDraw} gets called.
3003 */
3004 public void requestInvalidateRootRenderNode() {
3005 mInvalidateRootRequested = true;
3006 }
3007
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003008 boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
Chris Craikd36a81f2014-07-17 10:16:51 -07003009 final Rect ci = mAttachInfo.mContentInsets;
3010 final Rect vi = mAttachInfo.mVisibleInsets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003011 int scrollY = 0;
3012 boolean handled = false;
Romain Guy8506ab42009-06-11 17:35:47 -07003013
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003014 if (vi.left > ci.left || vi.top > ci.top
3015 || vi.right > ci.right || vi.bottom > ci.bottom) {
3016 // We'll assume that we aren't going to change the scroll
3017 // offset, since we want to avoid that unless it is actually
3018 // going to make the focus visible... otherwise we scroll
3019 // all over the place.
3020 scrollY = mScrollY;
3021 // We can be called for two different situations: during a draw,
3022 // to update the scroll position if the focus has changed (in which
3023 // case 'rectangle' is null), or in response to a
3024 // requestChildRectangleOnScreen() call (in which case 'rectangle'
3025 // is non-null and we just want to scroll to whatever that
3026 // rectangle is).
Craig Mautner26a84df2013-04-11 19:09:05 -07003027 final View focus = mView.findFocus();
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003028 if (focus == null) {
Romain Guye8b16522009-07-14 13:06:42 -07003029 return false;
3030 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003031 View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null;
Craig Mautner26a84df2013-04-11 19:09:05 -07003032 if (focus != lastScrolledFocus) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003033 // If the focus has changed, then ignore any requests to scroll
3034 // to a rectangle; first we want to make sure the entire focus
3035 // view is visible.
3036 rectangle = null;
3037 }
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003038 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Eval scroll: focus=" + focus
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003039 + " rectangle=" + rectangle + " ci=" + ci
3040 + " vi=" + vi);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003041 if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003042 // Optimization: if the focus hasn't changed since last
3043 // time, and no layout has happened, then just leave things
3044 // as they are.
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003045 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Keeping scroll y="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003046 + mScrollY + " vi=" + vi.toShortString());
Craig Mautner26a84df2013-04-11 19:09:05 -07003047 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003048 // We need to determine if the currently focused view is
3049 // within the visible part of the window and, if not, apply
3050 // a pan so it can be seen.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003051 mLastScrolledFocus = new WeakReference<View>(focus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003052 mScrollMayChange = false;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003053 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Need to scroll?");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003054 // Try to find the rectangle from the focus view.
3055 if (focus.getGlobalVisibleRect(mVisRect, null)) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003056 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Root w="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003057 + mView.getWidth() + " h=" + mView.getHeight()
3058 + " ci=" + ci.toShortString()
3059 + " vi=" + vi.toShortString());
3060 if (rectangle == null) {
3061 focus.getFocusedRect(mTempRect);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003062 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Focus " + focus
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003063 + ": focusRect=" + mTempRect.toShortString());
Dianne Hackborn1c6a8942010-03-23 16:34:20 -07003064 if (mView instanceof ViewGroup) {
3065 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
3066 focus, mTempRect);
3067 }
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003068 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003069 "Focus in window: focusRect="
3070 + mTempRect.toShortString()
3071 + " visRect=" + mVisRect.toShortString());
3072 } else {
3073 mTempRect.set(rectangle);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003074 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003075 "Request scroll to rect: "
3076 + mTempRect.toShortString()
3077 + " visRect=" + mVisRect.toShortString());
3078 }
3079 if (mTempRect.intersect(mVisRect)) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003080 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003081 "Focus window visible rect: "
3082 + mTempRect.toShortString());
3083 if (mTempRect.height() >
3084 (mView.getHeight()-vi.top-vi.bottom)) {
3085 // If the focus simply is not going to fit, then
3086 // best is probably just to leave things as-is.
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003087 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003088 "Too tall; leaving scrollY=" + scrollY);
Chong Zhang67254722016-06-02 12:56:54 -07003089 }
3090 // Next, check whether top or bottom is covered based on the non-scrolled
3091 // position, and calculate new scrollY (or set it to 0).
3092 // We can't keep using mScrollY here. For example mScrollY is non-zero
3093 // due to IME, then IME goes away. The current value of mScrollY leaves top
3094 // and bottom both visible, but we still need to scroll it back to 0.
3095 else if (mTempRect.top < vi.top) {
3096 scrollY = mTempRect.top - vi.top;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003097 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003098 "Top covered; scrollY=" + scrollY);
Chong Zhang67254722016-06-02 12:56:54 -07003099 } else if (mTempRect.bottom > (mView.getHeight()-vi.bottom)) {
3100 scrollY = mTempRect.bottom - (mView.getHeight()-vi.bottom);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003101 if (DEBUG_INPUT_RESIZE) Log.v(mTag,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003102 "Bottom covered; scrollY=" + scrollY);
Chong Zhang67254722016-06-02 12:56:54 -07003103 } else {
3104 scrollY = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003105 }
3106 handled = true;
3107 }
3108 }
3109 }
3110 }
Romain Guy8506ab42009-06-11 17:35:47 -07003111
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003112 if (scrollY != mScrollY) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003113 if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Pan scroll changed: old="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003114 + mScrollY + " , new=" + scrollY);
Derek Sollenberger8d948352015-07-16 09:27:59 -04003115 if (!immediate) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003116 if (mScroller == null) {
3117 mScroller = new Scroller(mView.getContext());
3118 }
3119 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
3120 } else if (mScroller != null) {
3121 mScroller.abortAnimation();
3122 }
3123 mScrollY = scrollY;
3124 }
Romain Guy8506ab42009-06-11 17:35:47 -07003125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003126 return handled;
3127 }
Romain Guy8506ab42009-06-11 17:35:47 -07003128
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07003129 /**
3130 * @hide
3131 */
3132 public View getAccessibilityFocusedHost() {
3133 return mAccessibilityFocusedHost;
3134 }
3135
3136 /**
3137 * @hide
3138 */
3139 public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
3140 return mAccessibilityFocusedVirtualView;
3141 }
3142
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003143 void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003144 // If we have a virtual view with accessibility focus we need
3145 // to clear the focus and invalidate the virtual view bounds.
3146 if (mAccessibilityFocusedVirtualView != null) {
3147
3148 AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
3149 View focusHost = mAccessibilityFocusedHost;
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003150
3151 // Wipe the state of the current accessibility focus since
3152 // the call into the provider to clear accessibility focus
3153 // will fire an accessibility event which will end up calling
3154 // this method and we want to have clean state when this
3155 // invocation happens.
3156 mAccessibilityFocusedHost = null;
3157 mAccessibilityFocusedVirtualView = null;
3158
Alan Viverette239a0c02013-05-07 17:17:35 -07003159 // Clear accessibility focus on the host after clearing state since
3160 // this method may be reentrant.
Phil Weavere37cfab2016-04-07 21:01:57 -07003161 focusHost.clearAccessibilityFocusNoCallbacks(
3162 AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
Alan Viverette239a0c02013-05-07 17:17:35 -07003163
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003164 AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
3165 if (provider != null) {
3166 // Invalidate the area of the cleared accessibility focus.
3167 focusNode.getBoundsInParent(mTempRect);
3168 focusHost.invalidate(mTempRect);
3169 // Clear accessibility focus in the virtual node.
3170 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
3171 focusNode.getSourceNodeId());
3172 provider.performAction(virtualNodeId,
3173 AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
3174 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003175 focusNode.recycle();
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003176 }
3177 if (mAccessibilityFocusedHost != null) {
3178 // Clear accessibility focus in the view.
Phil Weavere37cfab2016-04-07 21:01:57 -07003179 mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks(
3180 AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
Svetoslav Ganov42138042012-03-20 11:51:39 -07003181 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003182
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003183 // Set the new focus host and node.
3184 mAccessibilityFocusedHost = view;
3185 mAccessibilityFocusedVirtualView = node;
John Reck0a973302014-07-16 13:29:45 -07003186
3187 if (mAttachInfo.mHardwareRenderer != null) {
3188 mAttachInfo.mHardwareRenderer.invalidateRoot();
3189 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07003190 }
3191
Igor Murashkina86ab6402013-08-30 12:58:36 -07003192 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003193 public void requestChildFocus(View child, View focused) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003194 if (DEBUG_INPUT_RESIZE) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003195 Log.v(mTag, "Request child focus: focus now " + focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003196 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003197 checkThread();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003198 scheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003199 }
3200
Igor Murashkina86ab6402013-08-30 12:58:36 -07003201 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003202 public void clearChildFocus(View child) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003203 if (DEBUG_INPUT_RESIZE) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003204 Log.v(mTag, "Clearing child focus");
Amith Yamasani73eb97f2012-02-14 15:45:15 -08003205 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003206 checkThread();
3207 scheduleTraversals();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003208 }
Amith Yamasani73eb97f2012-02-14 15:45:15 -08003209
Svetoslav Ganov42138042012-03-20 11:51:39 -07003210 @Override
3211 public ViewParent getParentForAccessibility() {
3212 return null;
3213 }
3214
Igor Murashkina86ab6402013-08-30 12:58:36 -07003215 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003216 public void focusableViewAvailable(View v) {
3217 checkThread();
Romain Guy1c90f032011-05-24 14:59:50 -07003218 if (mView != null) {
3219 if (!mView.hasFocus()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003220 v.requestFocus();
Romain Guy1c90f032011-05-24 14:59:50 -07003221 } else {
3222 // the one case where will transfer focus away from the current one
3223 // is if the current view is a view group that prefers to give focus
3224 // to its children first AND the view is a descendant of it.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003225 View focused = mView.findFocus();
3226 if (focused instanceof ViewGroup) {
3227 ViewGroup group = (ViewGroup) focused;
3228 if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
3229 && isViewDescendantOf(v, focused)) {
3230 v.requestFocus();
3231 }
Romain Guy1c90f032011-05-24 14:59:50 -07003232 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003233 }
3234 }
3235 }
3236
Igor Murashkina86ab6402013-08-30 12:58:36 -07003237 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003238 public void recomputeViewAttributes(View child) {
3239 checkThread();
3240 if (mView == child) {
3241 mAttachInfo.mRecomputeGlobalAttributes = true;
3242 if (!mWillDrawSoon) {
3243 scheduleTraversals();
3244 }
3245 }
3246 }
3247
3248 void dispatchDetachedFromWindow() {
Romain Guy90fc03b2011-01-16 13:07:15 -08003249 if (mView != null && mView.mAttachInfo != null) {
Dianne Hackborn961cae92013-03-20 14:59:43 -07003250 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003251 mView.dispatchDetachedFromWindow();
3252 }
3253
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003254 mAccessibilityInteractionConnectionManager.ensureNoConnection();
3255 mAccessibilityManager.removeAccessibilityStateChangeListener(
3256 mAccessibilityInteractionConnectionManager);
Chris Craikcce47eb2014-07-16 15:12:15 -07003257 mAccessibilityManager.removeHighTextContrastStateChangeListener(
3258 mHighContrastTextManager);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07003259 removeSendWindowContentChangedCallback();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003260
Romain Guya998dff2012-03-23 18:58:36 -07003261 destroyHardwareRenderer();
3262
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003263 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003264
Craig Mautner8f303ad2013-06-14 11:32:22 -07003265 mView.assignParent(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003266 mView = null;
3267 mAttachInfo.mRootView = null;
3268
Dianne Hackborn0586a1b2009-09-06 21:08:27 -07003269 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003270
Jeff Browncc4f7db2011-08-30 20:34:48 -07003271 if (mInputQueueCallback != null && mInputQueue != null) {
3272 mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
Michael Wrighta44dd262013-04-10 21:12:00 -07003273 mInputQueue.dispose();
Jeff Browncc4f7db2011-08-30 20:34:48 -07003274 mInputQueueCallback = null;
3275 mInputQueue = null;
Michael Wrighta44dd262013-04-10 21:12:00 -07003276 }
3277 if (mInputEventReceiver != null) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08003278 mInputEventReceiver.dispose();
3279 mInputEventReceiver = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -07003280 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003281 try {
Jeff Brown98365d72012-08-19 20:30:52 -07003282 mWindowSession.remove(mWindow);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003283 } catch (RemoteException e) {
3284 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003285
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003286 // Dispose the input channel after removing the window so the Window Manager
3287 // doesn't interpret the input channel being closed as an abnormal termination.
3288 if (mInputChannel != null) {
3289 mInputChannel.dispose();
3290 mInputChannel = null;
Jeff Brown349703e2010-06-22 01:27:15 -07003291 }
Jeff Brown96e942d2011-11-30 19:55:01 -08003292
Jeff Brownd912e1f2014-04-11 18:46:22 -07003293 mDisplayManager.unregisterDisplayListener(mDisplayListener);
3294
Jeff Brownebb2d8d2012-03-23 17:14:34 -07003295 unscheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003296 }
Romain Guy8506ab42009-06-11 17:35:47 -07003297
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003298 void updateConfiguration(Configuration config, boolean force) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003299 if (DEBUG_CONFIGURATION) Log.v(mTag,
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003300 "Applying new config to window "
3301 + mWindowAttributes.getTitle()
3302 + ": " + config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07003303
Craig Mautner48d0d182013-06-11 07:53:06 -07003304 CompatibilityInfo ci = mDisplayAdjustments.getCompatibilityInfo();
3305 if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
Dianne Hackborn5fd21692011-06-07 14:09:47 -07003306 config = new Configuration(config);
Dianne Hackborn908aecc2012-07-31 16:37:34 -07003307 ci.applyToConfiguration(mNoncompatDensity, config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07003308 }
3309
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003310 synchronized (sConfigCallbacks) {
3311 for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
3312 sConfigCallbacks.get(i).onConfigurationChanged(config);
3313 }
3314 }
3315 if (mView != null) {
3316 // At this point the resources have been updated to
3317 // have the most recent config, whatever that is. Use
Dianne Hackborn908aecc2012-07-31 16:37:34 -07003318 // the one in them which may be newer.
Romain Guy1c90f032011-05-24 14:59:50 -07003319 config = mView.getResources().getConfiguration();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003320 if (force || mLastConfiguration.diff(config) != 0) {
Fabrice Di Megliocf128972012-10-16 20:51:12 -07003321 final int lastLayoutDirection = mLastConfiguration.getLayoutDirection();
3322 final int currentLayoutDirection = config.getLayoutDirection();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003323 mLastConfiguration.setTo(config);
Fabrice Di Megliob003e282012-10-17 17:20:19 -07003324 if (lastLayoutDirection != currentLayoutDirection &&
3325 mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
Fabrice Di Megliocf128972012-10-16 20:51:12 -07003326 mView.setLayoutDirection(currentLayoutDirection);
3327 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003328 mView.dispatchConfigurationChanged(config);
3329 }
3330 }
3331 }
John Reck05e85842014-04-23 14:48:28 -07003332
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003333 /**
3334 * Return true if child is an ancestor of parent, (or equal to the parent).
3335 */
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07003336 public static boolean isViewDescendantOf(View child, View parent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003337 if (child == parent) {
3338 return true;
3339 }
3340
3341 final ViewParent theParent = child.getParent();
3342 return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
3343 }
3344
Yohei Yukawad2e56472015-07-28 17:00:33 -07003345 private static void forceLayout(View view) {
3346 view.forceLayout();
3347 if (view instanceof ViewGroup) {
3348 ViewGroup group = (ViewGroup) view;
3349 final int count = group.getChildCount();
3350 for (int i = 0; i < count; i++) {
3351 forceLayout(group.getChildAt(i));
3352 }
3353 }
3354 }
3355
Jeff Browna175a5b2012-02-15 19:18:31 -08003356 private final static int MSG_INVALIDATE = 1;
3357 private final static int MSG_INVALIDATE_RECT = 2;
3358 private final static int MSG_DIE = 3;
3359 private final static int MSG_RESIZED = 4;
3360 private final static int MSG_RESIZED_REPORT = 5;
3361 private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
keunyoung30f420f2013-08-02 14:23:10 -07003362 private final static int MSG_DISPATCH_INPUT_EVENT = 7;
Jeff Browna175a5b2012-02-15 19:18:31 -08003363 private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
3364 private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
Jeff Browna175a5b2012-02-15 19:18:31 -08003365 private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
Jeff Browna175a5b2012-02-15 19:18:31 -08003366 private final static int MSG_CHECK_FOCUS = 13;
3367 private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
3368 private final static int MSG_DISPATCH_DRAG_EVENT = 15;
3369 private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
3370 private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
3371 private final static int MSG_UPDATE_CONFIGURATION = 18;
Svetoslav Ganov42138042012-03-20 11:51:39 -07003372 private final static int MSG_PROCESS_INPUT_EVENTS = 19;
Romain Guyfbb93fa2012-12-03 18:50:35 -08003373 private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
Jorim Jaggi827e0fa2015-05-07 11:41:41 -07003374 private final static int MSG_INVALIDATE_WORLD = 22;
3375 private final static int MSG_WINDOW_MOVED = 23;
3376 private final static int MSG_SYNTHESIZE_INPUT_EVENT = 24;
3377 private final static int MSG_DISPATCH_WINDOW_SHOWN = 25;
Clara Bayarri75e09792015-07-29 16:20:40 +01003378 private final static int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26;
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08003379 private final static int MSG_UPDATE_POINTER_ICON = 27;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003380
Jeff Browna175a5b2012-02-15 19:18:31 -08003381 final class ViewRootHandler extends Handler {
3382 @Override
3383 public String getMessageName(Message message) {
3384 switch (message.what) {
3385 case MSG_INVALIDATE:
3386 return "MSG_INVALIDATE";
3387 case MSG_INVALIDATE_RECT:
3388 return "MSG_INVALIDATE_RECT";
3389 case MSG_DIE:
3390 return "MSG_DIE";
3391 case MSG_RESIZED:
3392 return "MSG_RESIZED";
3393 case MSG_RESIZED_REPORT:
3394 return "MSG_RESIZED_REPORT";
3395 case MSG_WINDOW_FOCUS_CHANGED:
3396 return "MSG_WINDOW_FOCUS_CHANGED";
keunyoung30f420f2013-08-02 14:23:10 -07003397 case MSG_DISPATCH_INPUT_EVENT:
3398 return "MSG_DISPATCH_INPUT_EVENT";
Jeff Browna175a5b2012-02-15 19:18:31 -08003399 case MSG_DISPATCH_APP_VISIBILITY:
3400 return "MSG_DISPATCH_APP_VISIBILITY";
3401 case MSG_DISPATCH_GET_NEW_SURFACE:
3402 return "MSG_DISPATCH_GET_NEW_SURFACE";
Jeff Browna175a5b2012-02-15 19:18:31 -08003403 case MSG_DISPATCH_KEY_FROM_IME:
3404 return "MSG_DISPATCH_KEY_FROM_IME";
Jeff Browna175a5b2012-02-15 19:18:31 -08003405 case MSG_CHECK_FOCUS:
3406 return "MSG_CHECK_FOCUS";
3407 case MSG_CLOSE_SYSTEM_DIALOGS:
3408 return "MSG_CLOSE_SYSTEM_DIALOGS";
3409 case MSG_DISPATCH_DRAG_EVENT:
3410 return "MSG_DISPATCH_DRAG_EVENT";
3411 case MSG_DISPATCH_DRAG_LOCATION_EVENT:
3412 return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
3413 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
3414 return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
3415 case MSG_UPDATE_CONFIGURATION:
3416 return "MSG_UPDATE_CONFIGURATION";
Jeff Browna175a5b2012-02-15 19:18:31 -08003417 case MSG_PROCESS_INPUT_EVENTS:
3418 return "MSG_PROCESS_INPUT_EVENTS";
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003419 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
3420 return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
Craig Mautner5702d4d2012-06-30 14:10:16 -07003421 case MSG_WINDOW_MOVED:
3422 return "MSG_WINDOW_MOVED";
Michael Wright899d7052014-04-23 17:23:39 -07003423 case MSG_SYNTHESIZE_INPUT_EVENT:
3424 return "MSG_SYNTHESIZE_INPUT_EVENT";
Craig Mautner9c795042014-10-28 19:59:59 -07003425 case MSG_DISPATCH_WINDOW_SHOWN:
3426 return "MSG_DISPATCH_WINDOW_SHOWN";
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08003427 case MSG_UPDATE_POINTER_ICON:
3428 return "MSG_UPDATE_POINTER_ICON";
Jeff Browna175a5b2012-02-15 19:18:31 -08003429 }
3430 return super.getMessageName(message);
Romain Guyf9284692011-07-13 18:46:21 -07003431 }
Romain Guyf9284692011-07-13 18:46:21 -07003432
Jeff Browna175a5b2012-02-15 19:18:31 -08003433 @Override
Michael Wright53b854a2016-04-12 19:22:41 -04003434 public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
3435 if (msg.what == MSG_REQUEST_KEYBOARD_SHORTCUTS && msg.obj == null) {
3436 // Debugging for b/27963013
3437 throw new NullPointerException(
3438 "Attempted to call MSG_REQUEST_KEYBOARD_SHORTCUTS with null receiver:");
3439 }
3440 return super.sendMessageAtTime(msg, uptimeMillis);
3441 }
3442
3443 @Override
Jeff Browna175a5b2012-02-15 19:18:31 -08003444 public void handleMessage(Message msg) {
3445 switch (msg.what) {
3446 case MSG_INVALIDATE:
3447 ((View) msg.obj).invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003448 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003449 case MSG_INVALIDATE_RECT:
3450 final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
3451 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08003452 info.recycle();
Jeff Browna175a5b2012-02-15 19:18:31 -08003453 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003454 case MSG_PROCESS_INPUT_EVENTS:
3455 mProcessInputEventsScheduled = false;
3456 doProcessInputEvents();
3457 break;
3458 case MSG_DISPATCH_APP_VISIBILITY:
3459 handleAppVisibility(msg.arg1 != 0);
3460 break;
3461 case MSG_DISPATCH_GET_NEW_SURFACE:
3462 handleGetNewSurface();
3463 break;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003464 case MSG_RESIZED: {
3465 // Recycled in the fall through...
3466 SomeArgs args = (SomeArgs) msg.obj;
Romain Guydfab3632012-10-03 14:53:25 -07003467 if (mWinFrame.equals(args.arg1)
Dianne Hackbornc4aad012013-02-22 15:05:25 -08003468 && mPendingOverscanInsets.equals(args.arg5)
Romain Guydfab3632012-10-03 14:53:25 -07003469 && mPendingContentInsets.equals(args.arg2)
Adrian Roosfa104232014-06-20 16:10:14 -07003470 && mPendingStableInsets.equals(args.arg6)
Romain Guydfab3632012-10-03 14:53:25 -07003471 && mPendingVisibleInsets.equals(args.arg3)
Filip Gruszczynski2217f612015-05-26 11:32:08 -07003472 && mPendingOutsets.equals(args.arg7)
Jorim Jaggi0fe356e2016-01-05 14:43:25 +01003473 && mPendingBackDropFrame.equals(args.arg8)
Jorim Jaggia4a58ef2016-01-27 02:10:08 -08003474 && args.arg4 == null
3475 && args.argi1 == 0) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003476 break;
Romain Guycdb86672010-03-18 18:54:50 -07003477 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003478 } // fall through...
Jeff Browna175a5b2012-02-15 19:18:31 -08003479 case MSG_RESIZED_REPORT:
3480 if (mAdded) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003481 SomeArgs args = (SomeArgs) msg.obj;
3482
3483 Configuration config = (Configuration) args.arg4;
Jeff Browna175a5b2012-02-15 19:18:31 -08003484 if (config != null) {
3485 updateConfiguration(config, false);
3486 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003487
Jorim Jaggi26952d72016-04-01 17:43:14 -07003488 final boolean framesChanged = !mWinFrame.equals(args.arg1)
3489 || !mPendingOverscanInsets.equals(args.arg5)
3490 || !mPendingContentInsets.equals(args.arg2)
3491 || !mPendingStableInsets.equals(args.arg6)
3492 || !mPendingVisibleInsets.equals(args.arg3)
3493 || !mPendingOutsets.equals(args.arg7);
3494
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003495 mWinFrame.set((Rect) args.arg1);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08003496 mPendingOverscanInsets.set((Rect) args.arg5);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003497 mPendingContentInsets.set((Rect) args.arg2);
Adrian Roosfa104232014-06-20 16:10:14 -07003498 mPendingStableInsets.set((Rect) args.arg6);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003499 mPendingVisibleInsets.set((Rect) args.arg3);
Filip Gruszczynski2217f612015-05-26 11:32:08 -07003500 mPendingOutsets.set((Rect) args.arg7);
Jorim Jaggia7262a82015-11-03 15:15:40 +01003501 mPendingBackDropFrame.set((Rect) args.arg8);
Jorim Jaggia4a58ef2016-01-27 02:10:08 -08003502 mForceNextWindowRelayout = args.argi1 != 0;
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08003503 mPendingAlwaysConsumeNavBar = args.argi2 != 0;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003504
3505 args.recycle();
3506
Jeff Browna175a5b2012-02-15 19:18:31 -08003507 if (msg.what == MSG_RESIZED_REPORT) {
3508 mReportNextDraw = true;
3509 }
Romain Guy59a12ca2011-06-09 17:48:21 -07003510
Jorim Jaggi26952d72016-04-01 17:43:14 -07003511 if (mView != null && framesChanged) {
Yohei Yukawad2e56472015-07-28 17:00:33 -07003512 forceLayout(mView);
3513 }
3514
Jeff Browna175a5b2012-02-15 19:18:31 -08003515 requestLayout();
3516 }
3517 break;
Craig Mautner5702d4d2012-06-30 14:10:16 -07003518 case MSG_WINDOW_MOVED:
3519 if (mAdded) {
3520 final int w = mWinFrame.width();
3521 final int h = mWinFrame.height();
3522 final int l = msg.arg1;
3523 final int t = msg.arg2;
3524 mWinFrame.left = l;
3525 mWinFrame.right = l + w;
3526 mWinFrame.top = t;
3527 mWinFrame.bottom = t + h;
3528
Jorim Jaggia7262a82015-11-03 15:15:40 +01003529 mPendingBackDropFrame.set(mWinFrame);
3530
Jorim Jaggi844e1712016-01-13 17:39:25 -08003531 // Suppress layouts during resizing - a correct layout will happen when resizing
3532 // is done, and this just increases system load.
Jorim Jaggi2e95a482016-01-14 17:36:55 -08003533 boolean isDockedDivider = mWindowAttributes.type == TYPE_DOCK_DIVIDER;
3534 boolean suppress = (mDragResizing && mResizeMode == RESIZE_MODE_DOCKED_DIVIDER)
3535 || isDockedDivider;
Jorim Jaggi844e1712016-01-13 17:39:25 -08003536 if (!suppress) {
3537 if (mView != null) {
3538 forceLayout(mView);
3539 }
3540 requestLayout();
Jorim Jaggi2e95a482016-01-14 17:36:55 -08003541 } else {
3542 maybeHandleWindowMove(mWinFrame);
Yohei Yukawad2e56472015-07-28 17:00:33 -07003543 }
Craig Mautner5702d4d2012-06-30 14:10:16 -07003544 }
3545 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003546 case MSG_WINDOW_FOCUS_CHANGED: {
3547 if (mAdded) {
3548 boolean hasWindowFocus = msg.arg1 != 0;
3549 mAttachInfo.mHasWindowFocus = hasWindowFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003550
Jeff Browna175a5b2012-02-15 19:18:31 -08003551 profileRendering(hasWindowFocus);
3552
3553 if (hasWindowFocus) {
3554 boolean inTouchMode = msg.arg2 != 0;
3555 ensureTouchModeLocally(inTouchMode);
3556
Romain Guye55945e2013-04-04 15:26:04 -07003557 if (mAttachInfo.mHardwareRenderer != null && mSurface.isValid()){
Jeff Browna175a5b2012-02-15 19:18:31 -08003558 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08003559 try {
Alan Viveretteccb11e12014-07-08 16:04:02 -07003560 final WindowManager.LayoutParams lp = mWindowAttributes;
Alan Viverette49a22e82014-07-12 20:01:27 -07003561 final Rect surfaceInsets = lp != null ? lp.surfaceInsets : null;
Romain Guy3696779b2013-01-28 14:04:07 -08003562 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
Alan Viverette50210d92015-05-14 18:05:36 -07003563 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
Igor Murashkina86ab6402013-08-30 12:58:36 -07003564 } catch (OutOfResourcesException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003565 Log.e(mTag, "OutOfResourcesException locking surface", e);
Jeff Browna175a5b2012-02-15 19:18:31 -08003566 try {
Jeff Brown98365d72012-08-19 20:30:52 -07003567 if (!mWindowSession.outOfMemory(mWindow)) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003568 Slog.w(mTag, "No processes killed for memory; killing self");
Jeff Browna175a5b2012-02-15 19:18:31 -08003569 Process.killProcess(Process.myPid());
3570 }
3571 } catch (RemoteException ex) {
Dianne Hackborn64825172011-03-02 21:32:58 -08003572 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003573 // Retry in a bit.
3574 sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
3575 return;
Dianne Hackborn64825172011-03-02 21:32:58 -08003576 }
Dianne Hackborn64825172011-03-02 21:32:58 -08003577 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003578 }
Romain Guy8506ab42009-06-11 17:35:47 -07003579
Jeff Browna175a5b2012-02-15 19:18:31 -08003580 mLastWasImTarget = WindowManager.LayoutParams
3581 .mayUseInputMethod(mWindowAttributes.flags);
Romain Guy8506ab42009-06-11 17:35:47 -07003582
Jeff Browna175a5b2012-02-15 19:18:31 -08003583 InputMethodManager imm = InputMethodManager.peekInstance();
Yohei Yukawa5f059652015-05-14 22:16:41 -07003584 if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
3585 imm.onPreWindowFocus(mView, hasWindowFocus);
3586 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003587 if (mView != null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003588 mAttachInfo.mKeyDispatchState.reset();
3589 mView.dispatchWindowFocusChanged(hasWindowFocus);
Dianne Hackborn961cae92013-03-20 14:59:43 -07003590 mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003591 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003592
Jeff Browna175a5b2012-02-15 19:18:31 -08003593 // Note: must be done after the focus change callbacks,
3594 // so all of the view state is set up correctly.
3595 if (hasWindowFocus) {
keunyoung30f420f2013-08-02 14:23:10 -07003596 if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
Yohei Yukawa5f059652015-05-14 22:16:41 -07003597 imm.onPostWindowFocus(mView, mView.findFocus(),
Jeff Browna175a5b2012-02-15 19:18:31 -08003598 mWindowAttributes.softInputMode,
3599 !mHasHadWindowFocus, mWindowAttributes.flags);
3600 }
3601 // Clear the forward bit. We can just do this directly, since
3602 // the window manager doesn't care about it.
3603 mWindowAttributes.softInputMode &=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003604 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
Jeff Browna175a5b2012-02-15 19:18:31 -08003605 ((WindowManager.LayoutParams)mView.getLayoutParams())
3606 .softInputMode &=
3607 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
3608 mHasHadWindowFocus = true;
3609 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003610 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003611 } break;
3612 case MSG_DIE:
3613 doDie();
3614 break;
keunyoung30f420f2013-08-02 14:23:10 -07003615 case MSG_DISPATCH_INPUT_EVENT: {
Jae Seo6a6059a2014-04-17 21:35:29 -07003616 SomeArgs args = (SomeArgs)msg.obj;
3617 InputEvent event = (InputEvent)args.arg1;
3618 InputEventReceiver receiver = (InputEventReceiver)args.arg2;
3619 enqueueInputEvent(event, receiver, 0, true);
3620 args.recycle();
Jeff Browna175a5b2012-02-15 19:18:31 -08003621 } break;
Michael Wright899d7052014-04-23 17:23:39 -07003622 case MSG_SYNTHESIZE_INPUT_EVENT: {
3623 InputEvent event = (InputEvent)msg.obj;
3624 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_UNHANDLED, true);
3625 } break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003626 case MSG_DISPATCH_KEY_FROM_IME: {
3627 if (LOCAL_LOGV) Log.v(
3628 TAG, "Dispatching key "
3629 + msg.obj + " from IME to " + mView);
3630 KeyEvent event = (KeyEvent)msg.obj;
3631 if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
3632 // The IME is trying to say this event is from the
3633 // system! Bad bad bad!
3634 //noinspection UnusedAssignment
Michael Wright899d7052014-04-23 17:23:39 -07003635 event = KeyEvent.changeFlags(event, event.getFlags() &
3636 ~KeyEvent.FLAG_FROM_SYSTEM);
Jeff Browna175a5b2012-02-15 19:18:31 -08003637 }
3638 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
3639 } break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003640 case MSG_CHECK_FOCUS: {
3641 InputMethodManager imm = InputMethodManager.peekInstance();
3642 if (imm != null) {
3643 imm.checkFocus();
3644 }
3645 } break;
3646 case MSG_CLOSE_SYSTEM_DIALOGS: {
3647 if (mView != null) {
3648 mView.onCloseSystemDialogs((String)msg.obj);
3649 }
3650 } break;
3651 case MSG_DISPATCH_DRAG_EVENT:
3652 case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
3653 DragEvent event = (DragEvent)msg.obj;
3654 event.mLocalState = mLocalDragState; // only present when this app called startDrag()
3655 handleDragEvent(event);
3656 } break;
3657 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
Romain Guyfbb93fa2012-12-03 18:50:35 -08003658 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj);
Jeff Browna175a5b2012-02-15 19:18:31 -08003659 } break;
3660 case MSG_UPDATE_CONFIGURATION: {
3661 Configuration config = (Configuration)msg.obj;
3662 if (config.isOtherSeqNewer(mLastConfiguration)) {
3663 config = mLastConfiguration;
3664 }
3665 updateConfiguration(config, false);
3666 } break;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003667 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003668 setAccessibilityFocus(null, null);
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003669 } break;
Dianne Hackborna53de062012-05-08 18:53:51 -07003670 case MSG_INVALIDATE_WORLD: {
Romain Guyf84208f2012-09-13 22:50:18 -07003671 if (mView != null) {
3672 invalidateWorld(mView);
3673 }
Dianne Hackborna53de062012-05-08 18:53:51 -07003674 } break;
Craig Mautner9c795042014-10-28 19:59:59 -07003675 case MSG_DISPATCH_WINDOW_SHOWN: {
3676 handleDispatchWindowShown();
Clara Bayarri75e09792015-07-29 16:20:40 +01003677 } break;
3678 case MSG_REQUEST_KEYBOARD_SHORTCUTS: {
Clara Bayarrifcd7e802016-03-10 12:58:18 +00003679 final IResultReceiver receiver = (IResultReceiver) msg.obj;
3680 final int deviceId = msg.arg1;
3681 handleRequestKeyboardShortcuts(receiver, deviceId);
Clara Bayarri75e09792015-07-29 16:20:40 +01003682 } break;
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08003683 case MSG_UPDATE_POINTER_ICON: {
3684 MotionEvent event = (MotionEvent) msg.obj;
3685 resetPointerIcon(event);
3686 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003687 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003688 }
3689 }
Romain Guy51e4d4d2012-03-15 18:30:47 -07003690
Jeff Browna175a5b2012-02-15 19:18:31 -08003691 final ViewRootHandler mHandler = new ViewRootHandler();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003692
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003693 /**
3694 * Something in the current window tells us we need to change the touch mode. For
3695 * example, we are not in touch mode, and the user touches the screen.
3696 *
3697 * If the touch mode has changed, tell the window manager, and handle it locally.
3698 *
3699 * @param inTouchMode Whether we want to be in touch mode.
3700 * @return True if the touch mode changed and focus changed was changed as a result
3701 */
3702 boolean ensureTouchMode(boolean inTouchMode) {
3703 if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
3704 + "touch mode is " + mAttachInfo.mInTouchMode);
3705 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3706
3707 // tell the window manager
3708 try {
Matt Wud6bc96d2016-01-14 12:59:24 -08003709 mWindowSession.setInTouchMode(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003710 } catch (RemoteException e) {
3711 throw new RuntimeException(e);
3712 }
3713
3714 // handle the change
Romain Guy2d4cff62010-04-09 15:39:00 -07003715 return ensureTouchModeLocally(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003716 }
3717
3718 /**
3719 * Ensure that the touch mode for this window is set, and if it is changing,
3720 * take the appropriate action.
3721 * @param inTouchMode Whether we want to be in touch mode.
3722 * @return True if the touch mode changed and focus changed was changed as a result
3723 */
Romain Guy2d4cff62010-04-09 15:39:00 -07003724 private boolean ensureTouchModeLocally(boolean inTouchMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003725 if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
3726 + "touch mode is " + mAttachInfo.mInTouchMode);
3727
3728 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3729
3730 mAttachInfo.mInTouchMode = inTouchMode;
3731 mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
3732
Romain Guy2d4cff62010-04-09 15:39:00 -07003733 return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003734 }
3735
3736 private boolean enterTouchMode() {
Alan Viveretteed7821a2013-07-24 15:49:23 -07003737 if (mView != null && mView.hasFocus()) {
3738 // note: not relying on mFocusedView here because this could
3739 // be when the window is first being added, and mFocused isn't
3740 // set yet.
3741 final View focused = mView.findFocus();
3742 if (focused != null && !focused.isFocusableInTouchMode()) {
3743 final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
3744 if (ancestorToTakeFocus != null) {
3745 // there is an ancestor that wants focus after its
3746 // descendants that is focusable in touch mode.. give it
3747 // focus
3748 return ancestorToTakeFocus.requestFocus();
3749 } else {
Alan Viverette973f3b42013-08-13 16:57:28 -07003750 // There's nothing to focus. Clear and propagate through the
3751 // hierarchy, but don't attempt to place new focus.
Alan Viverette223622a2013-12-17 13:29:02 -08003752 focused.clearFocusInternal(null, true, false);
Alan Viveretteed7821a2013-07-24 15:49:23 -07003753 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003754 }
3755 }
3756 }
3757 return false;
3758 }
3759
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003760 /**
3761 * Find an ancestor of focused that wants focus after its descendants and is
3762 * focusable in touch mode.
3763 * @param focused The currently focused view.
3764 * @return An appropriate view, or null if no such view exists.
3765 */
Romain Guya998dff2012-03-23 18:58:36 -07003766 private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003767 ViewParent parent = focused.getParent();
3768 while (parent instanceof ViewGroup) {
3769 final ViewGroup vgParent = (ViewGroup) parent;
3770 if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
3771 && vgParent.isFocusableInTouchMode()) {
3772 return vgParent;
3773 }
3774 if (vgParent.isRootNamespace()) {
3775 return null;
3776 } else {
3777 parent = vgParent.getParent();
3778 }
3779 }
3780 return null;
3781 }
3782
3783 private boolean leaveTouchMode() {
3784 if (mView != null) {
3785 if (mView.hasFocus()) {
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003786 View focusedView = mView.findFocus();
3787 if (!(focusedView instanceof ViewGroup)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003788 // some view has focus, let it keep it
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003789 return false;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003790 } else if (((ViewGroup) focusedView).getDescendantFocusability() !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003791 ViewGroup.FOCUS_AFTER_DESCENDANTS) {
3792 // some view group has focus, and doesn't prefer its children
3793 // over itself for focus, so let them keep it.
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003794 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003795 }
3796 }
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003797
3798 // find the best view to give focus to in this brave new non-touch-mode
3799 // world
3800 final View focused = focusSearch(null, View.FOCUS_DOWN);
3801 if (focused != null) {
3802 return focused.requestFocus(View.FOCUS_DOWN);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003803 }
3804 }
3805 return false;
3806 }
3807
Jeff Brownf9e989d2013-04-04 23:04:03 -07003808 /**
3809 * Base class for implementing a stage in the chain of responsibility
3810 * for processing input events.
3811 * <p>
3812 * Events are delivered to the stage by the {@link #deliver} method. The stage
3813 * then has the choice of finishing the event or forwarding it to the next stage.
3814 * </p>
3815 */
3816 abstract class InputStage {
3817 private final InputStage mNext;
3818
3819 protected static final int FORWARD = 0;
3820 protected static final int FINISH_HANDLED = 1;
3821 protected static final int FINISH_NOT_HANDLED = 2;
3822
3823 /**
3824 * Creates an input stage.
3825 * @param next The next stage to which events should be forwarded.
3826 */
3827 public InputStage(InputStage next) {
3828 mNext = next;
3829 }
3830
3831 /**
3832 * Delivers an event to be processed.
3833 */
3834 public final void deliver(QueuedInputEvent q) {
3835 if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
3836 forward(q);
Michael Wright17d28ca2013-10-31 17:47:45 -07003837 } else if (shouldDropInputEvent(q)) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003838 finish(q, false);
3839 } else {
3840 apply(q, onProcess(q));
3841 }
3842 }
3843
3844 /**
3845 * Marks the the input event as finished then forwards it to the next stage.
3846 */
3847 protected void finish(QueuedInputEvent q, boolean handled) {
3848 q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
3849 if (handled) {
3850 q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
3851 }
3852 forward(q);
3853 }
3854
3855 /**
3856 * Forwards the event to the next stage.
3857 */
3858 protected void forward(QueuedInputEvent q) {
3859 onDeliverToNext(q);
3860 }
3861
3862 /**
3863 * Applies a result code from {@link #onProcess} to the specified event.
3864 */
3865 protected void apply(QueuedInputEvent q, int result) {
3866 if (result == FORWARD) {
3867 forward(q);
3868 } else if (result == FINISH_HANDLED) {
3869 finish(q, true);
3870 } else if (result == FINISH_NOT_HANDLED) {
3871 finish(q, false);
3872 } else {
3873 throw new IllegalArgumentException("Invalid result: " + result);
3874 }
3875 }
3876
3877 /**
3878 * Called when an event is ready to be processed.
3879 * @return A result code indicating how the event was handled.
3880 */
3881 protected int onProcess(QueuedInputEvent q) {
3882 return FORWARD;
3883 }
3884
3885 /**
3886 * Called when an event is being delivered to the next stage.
3887 */
3888 protected void onDeliverToNext(QueuedInputEvent q) {
Michael Wright06a79252014-05-05 17:45:29 -07003889 if (DEBUG_INPUT_STAGES) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003890 Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);
Michael Wright06a79252014-05-05 17:45:29 -07003891 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003892 if (mNext != null) {
3893 mNext.deliver(q);
3894 } else {
3895 finishInputEvent(q);
3896 }
3897 }
Jeff Brown5182c782013-10-15 20:31:52 -07003898
Michael Wright17d28ca2013-10-31 17:47:45 -07003899 protected boolean shouldDropInputEvent(QueuedInputEvent q) {
3900 if (mView == null || !mAdded) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003901 Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent);
Michael Wright17d28ca2013-10-31 17:47:45 -07003902 return true;
George Mount41725de2015-04-09 08:23:05 -07003903 } else if ((!mAttachInfo.mHasWindowFocus
3904 && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) || mStopped
Joe LaPenna90776de2016-01-22 07:11:49 -08003905 || (mIsAmbientMode && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON))
3906 || (mPausedForTransition && !isBack(q.mEvent))) {
Wale Ogunwalec3672cd2014-11-05 15:17:35 -08003907 // This is a focus event and the window doesn't currently have input focus or
3908 // has stopped. This could be an event that came back from the previous stage
3909 // but the window has lost focus or stopped in the meantime.
3910 if (isTerminalInputEvent(q.mEvent)) {
3911 // Don't drop terminal input events, however mark them as canceled.
3912 q.mEvent.cancel();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003913 Slog.w(mTag, "Cancelling event due to no window focus: " + q.mEvent);
Wale Ogunwalec3672cd2014-11-05 15:17:35 -08003914 return false;
3915 }
3916
3917 // Drop non-terminal input events.
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08003918 Slog.w(mTag, "Dropping event due to no window focus: " + q.mEvent);
Michael Wright17d28ca2013-10-31 17:47:45 -07003919 return true;
3920 }
3921 return false;
3922 }
3923
Jeff Brown5182c782013-10-15 20:31:52 -07003924 void dump(String prefix, PrintWriter writer) {
3925 if (mNext != null) {
3926 mNext.dump(prefix, writer);
3927 }
3928 }
George Mount41725de2015-04-09 08:23:05 -07003929
3930 private boolean isBack(InputEvent event) {
3931 if (event instanceof KeyEvent) {
3932 return ((KeyEvent) event).getKeyCode() == KeyEvent.KEYCODE_BACK;
3933 } else {
3934 return false;
3935 }
3936 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003937 }
3938
3939 /**
3940 * Base class for implementing an input pipeline stage that supports
3941 * asynchronous and out-of-order processing of input events.
3942 * <p>
3943 * In addition to what a normal input stage can do, an asynchronous
3944 * input stage may also defer an input event that has been delivered to it
3945 * and finish or forward it later.
3946 * </p>
3947 */
3948 abstract class AsyncInputStage extends InputStage {
3949 private final String mTraceCounter;
3950
3951 private QueuedInputEvent mQueueHead;
3952 private QueuedInputEvent mQueueTail;
3953 private int mQueueLength;
3954
3955 protected static final int DEFER = 3;
3956
3957 /**
3958 * Creates an asynchronous input stage.
3959 * @param next The next stage to which events should be forwarded.
3960 * @param traceCounter The name of a counter to record the size of
3961 * the queue of pending events.
3962 */
3963 public AsyncInputStage(InputStage next, String traceCounter) {
3964 super(next);
3965 mTraceCounter = traceCounter;
3966 }
3967
3968 /**
3969 * Marks the event as deferred, which is to say that it will be handled
3970 * asynchronously. The caller is responsible for calling {@link #forward}
3971 * or {@link #finish} later when it is done handling the event.
3972 */
3973 protected void defer(QueuedInputEvent q) {
3974 q.mFlags |= QueuedInputEvent.FLAG_DEFERRED;
3975 enqueue(q);
3976 }
3977
3978 @Override
3979 protected void forward(QueuedInputEvent q) {
3980 // Clear the deferred flag.
3981 q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED;
3982
3983 // Fast path if the queue is empty.
3984 QueuedInputEvent curr = mQueueHead;
3985 if (curr == null) {
3986 super.forward(q);
3987 return;
3988 }
3989
3990 // Determine whether the event must be serialized behind any others
3991 // before it can be delivered to the next stage. This is done because
3992 // deferred events might be handled out of order by the stage.
3993 final int deviceId = q.mEvent.getDeviceId();
3994 QueuedInputEvent prev = null;
3995 boolean blocked = false;
3996 while (curr != null && curr != q) {
3997 if (!blocked && deviceId == curr.mEvent.getDeviceId()) {
3998 blocked = true;
3999 }
4000 prev = curr;
4001 curr = curr.mNext;
4002 }
4003
4004 // If the event is blocked, then leave it in the queue to be delivered later.
4005 // Note that the event might not yet be in the queue if it was not previously
4006 // deferred so we will enqueue it if needed.
4007 if (blocked) {
4008 if (curr == null) {
4009 enqueue(q);
4010 }
4011 return;
4012 }
4013
4014 // The event is not blocked. Deliver it immediately.
4015 if (curr != null) {
4016 curr = curr.mNext;
4017 dequeue(q, prev);
4018 }
4019 super.forward(q);
4020
4021 // Dequeuing this event may have unblocked successors. Deliver them.
4022 while (curr != null) {
4023 if (deviceId == curr.mEvent.getDeviceId()) {
4024 if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) {
4025 break;
4026 }
4027 QueuedInputEvent next = curr.mNext;
4028 dequeue(curr, prev);
4029 super.forward(curr);
4030 curr = next;
4031 } else {
4032 prev = curr;
4033 curr = curr.mNext;
4034 }
4035 }
4036 }
4037
4038 @Override
4039 protected void apply(QueuedInputEvent q, int result) {
4040 if (result == DEFER) {
4041 defer(q);
4042 } else {
4043 super.apply(q, result);
4044 }
4045 }
4046
4047 private void enqueue(QueuedInputEvent q) {
4048 if (mQueueTail == null) {
4049 mQueueHead = q;
4050 mQueueTail = q;
4051 } else {
4052 mQueueTail.mNext = q;
4053 mQueueTail = q;
4054 }
4055
4056 mQueueLength += 1;
4057 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
4058 }
4059
4060 private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) {
4061 if (prev == null) {
4062 mQueueHead = q.mNext;
4063 } else {
4064 prev.mNext = q.mNext;
4065 }
4066 if (mQueueTail == q) {
4067 mQueueTail = prev;
4068 }
4069 q.mNext = null;
4070
4071 mQueueLength -= 1;
4072 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
4073 }
Jeff Brown5182c782013-10-15 20:31:52 -07004074
4075 @Override
4076 void dump(String prefix, PrintWriter writer) {
4077 writer.print(prefix);
4078 writer.print(getClass().getName());
4079 writer.print(": mQueueLength=");
4080 writer.println(mQueueLength);
4081
4082 super.dump(prefix, writer);
4083 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004084 }
4085
4086 /**
4087 * Delivers pre-ime input events to a native activity.
4088 * Does not support pointer events.
4089 */
Michael Wrighta44dd262013-04-10 21:12:00 -07004090 final class NativePreImeInputStage extends AsyncInputStage
4091 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004092 public NativePreImeInputStage(InputStage next, String traceCounter) {
4093 super(next, traceCounter);
4094 }
4095
4096 @Override
4097 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07004098 if (mInputQueue != null && q.mEvent instanceof KeyEvent) {
4099 mInputQueue.sendInputEvent(q.mEvent, q, true, this);
4100 return DEFER;
4101 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004102 return FORWARD;
4103 }
Michael Wrighta44dd262013-04-10 21:12:00 -07004104
4105 @Override
4106 public void onFinishedInputEvent(Object token, boolean handled) {
4107 QueuedInputEvent q = (QueuedInputEvent)token;
4108 if (handled) {
4109 finish(q, true);
4110 return;
4111 }
4112 forward(q);
4113 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004114 }
4115
4116 /**
4117 * Delivers pre-ime input events to the view hierarchy.
4118 * Does not support pointer events.
4119 */
4120 final class ViewPreImeInputStage extends InputStage {
4121 public ViewPreImeInputStage(InputStage next) {
4122 super(next);
4123 }
4124
4125 @Override
4126 protected int onProcess(QueuedInputEvent q) {
Jeff Brown481c1572012-03-09 14:41:15 -08004127 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004128 return processKeyEvent(q);
4129 }
4130 return FORWARD;
4131 }
4132
4133 private int processKeyEvent(QueuedInputEvent q) {
4134 final KeyEvent event = (KeyEvent)q.mEvent;
4135 if (mView.dispatchKeyEventPreIme(event)) {
4136 return FINISH_HANDLED;
4137 }
4138 return FORWARD;
4139 }
4140 }
4141
4142 /**
4143 * Delivers input events to the ime.
4144 * Does not support pointer events.
4145 */
4146 final class ImeInputStage extends AsyncInputStage
4147 implements InputMethodManager.FinishedInputEventCallback {
4148 public ImeInputStage(InputStage next, String traceCounter) {
4149 super(next, traceCounter);
4150 }
4151
4152 @Override
4153 protected int onProcess(QueuedInputEvent q) {
keunyoung30f420f2013-08-02 14:23:10 -07004154 if (mLastWasImTarget && !isInLocalFocusMode()) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004155 InputMethodManager imm = InputMethodManager.peekInstance();
4156 if (imm != null) {
4157 final InputEvent event = q.mEvent;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004158 if (DEBUG_IMF) Log.v(mTag, "Sending input event to IME: " + event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004159 int result = imm.dispatchInputEvent(event, q, this, mHandler);
4160 if (result == InputMethodManager.DISPATCH_HANDLED) {
4161 return FINISH_HANDLED;
4162 } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
Adam Lesinskic0f6eed2013-10-28 16:03:19 -07004163 // The IME could not handle it, so skip along to the next InputStage
4164 return FORWARD;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004165 } else {
4166 return DEFER; // callback will be invoked later
4167 }
4168 }
4169 }
4170 return FORWARD;
4171 }
4172
4173 @Override
4174 public void onFinishedInputEvent(Object token, boolean handled) {
4175 QueuedInputEvent q = (QueuedInputEvent)token;
4176 if (handled) {
4177 finish(q, true);
4178 return;
4179 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004180 forward(q);
4181 }
4182 }
4183
4184 /**
4185 * Performs early processing of post-ime input events.
4186 */
4187 final class EarlyPostImeInputStage extends InputStage {
4188 public EarlyPostImeInputStage(InputStage next) {
4189 super(next);
4190 }
4191
4192 @Override
4193 protected int onProcess(QueuedInputEvent q) {
4194 if (q.mEvent instanceof KeyEvent) {
4195 return processKeyEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08004196 } else {
Jeff Brown481c1572012-03-09 14:41:15 -08004197 final int source = q.mEvent.getSource();
4198 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004199 return processPointerEvent(q);
Jeff Brown481c1572012-03-09 14:41:15 -08004200 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08004201 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004202 return FORWARD;
4203 }
4204
4205 private int processKeyEvent(QueuedInputEvent q) {
4206 final KeyEvent event = (KeyEvent)q.mEvent;
4207
4208 // If the key's purpose is to exit touch mode then we consume it
4209 // and consider it handled.
4210 if (checkForLeavingTouchModeAndConsume(event)) {
4211 return FINISH_HANDLED;
4212 }
4213
4214 // Make sure the fallback event policy sees all keys that will be
4215 // delivered to the view hierarchy.
4216 mFallbackEventHandler.preDispatchKeyEvent(event);
4217 return FORWARD;
4218 }
4219
4220 private int processPointerEvent(QueuedInputEvent q) {
4221 final MotionEvent event = (MotionEvent)q.mEvent;
4222
4223 // Translate the pointer event for compatibility, if needed.
4224 if (mTranslator != null) {
4225 mTranslator.translateEventInScreenToAppWindow(event);
4226 }
4227
4228 // Enter touch mode on down or scroll.
4229 final int action = event.getAction();
4230 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
4231 ensureTouchMode(true);
4232 }
4233
4234 // Offset the scroll position.
4235 if (mCurScrollY != 0) {
4236 event.offsetLocation(0, mCurScrollY);
4237 }
4238
4239 // Remember the touch position for possible drag-initiation.
4240 if (event.isTouchEvent()) {
4241 mLastTouchPoint.x = event.getRawX();
4242 mLastTouchPoint.y = event.getRawY();
Vladislav Kaznacheevba761122016-01-22 12:09:45 -08004243 mLastTouchSource = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004244 }
4245 return FORWARD;
Jeff Brown4952dfd2011-11-30 19:23:22 -08004246 }
4247 }
4248
Jeff Brownf9e989d2013-04-04 23:04:03 -07004249 /**
4250 * Delivers post-ime input events to a native activity.
4251 */
Michael Wrighta44dd262013-04-10 21:12:00 -07004252 final class NativePostImeInputStage extends AsyncInputStage
4253 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004254 public NativePostImeInputStage(InputStage next, String traceCounter) {
4255 super(next, traceCounter);
4256 }
4257
4258 @Override
4259 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07004260 if (mInputQueue != null) {
4261 mInputQueue.sendInputEvent(q.mEvent, q, false, this);
4262 return DEFER;
4263 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004264 return FORWARD;
4265 }
Michael Wrighta44dd262013-04-10 21:12:00 -07004266
4267 @Override
4268 public void onFinishedInputEvent(Object token, boolean handled) {
4269 QueuedInputEvent q = (QueuedInputEvent)token;
4270 if (handled) {
4271 finish(q, true);
4272 return;
4273 }
4274 forward(q);
4275 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004276 }
4277
4278 /**
4279 * Delivers post-ime input events to the view hierarchy.
4280 */
4281 final class ViewPostImeInputStage extends InputStage {
4282 public ViewPostImeInputStage(InputStage next) {
4283 super(next);
4284 }
4285
4286 @Override
4287 protected int onProcess(QueuedInputEvent q) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08004288 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004289 return processKeyEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08004290 } else {
4291 final int source = q.mEvent.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004292 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
4293 return processPointerEvent(q);
4294 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
4295 return processTrackballEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08004296 } else {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004297 return processGenericMotionEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08004298 }
4299 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08004300 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08004301
Michael Wright9d744c72014-02-18 21:27:42 -08004302 @Override
4303 protected void onDeliverToNext(QueuedInputEvent q) {
4304 if (mUnbufferedInputDispatch
4305 && q.mEvent instanceof MotionEvent
4306 && ((MotionEvent)q.mEvent).isTouchEvent()
4307 && isTerminalInputEvent(q.mEvent)) {
4308 mUnbufferedInputDispatch = false;
4309 scheduleConsumeBatchedInput();
4310 }
4311 super.onDeliverToNext(q);
4312 }
4313
Jeff Brownf9e989d2013-04-04 23:04:03 -07004314 private int processKeyEvent(QueuedInputEvent q) {
4315 final KeyEvent event = (KeyEvent)q.mEvent;
4316
4317 // Deliver the key to the view hierarchy.
4318 if (mView.dispatchKeyEvent(event)) {
4319 return FINISH_HANDLED;
Jeff Brown21bc5c92011-02-28 18:27:14 -08004320 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004321
Michael Wright17d28ca2013-10-31 17:47:45 -07004322 if (shouldDropInputEvent(q)) {
4323 return FINISH_NOT_HANDLED;
4324 }
4325
Jeff Brownf9e989d2013-04-04 23:04:03 -07004326 // If the Control modifier is held, try to interpret the key as a shortcut.
4327 if (event.getAction() == KeyEvent.ACTION_DOWN
4328 && event.isCtrlPressed()
4329 && event.getRepeatCount() == 0
4330 && !KeyEvent.isModifierKey(event.getKeyCode())) {
4331 if (mView.dispatchKeyShortcutEvent(event)) {
4332 return FINISH_HANDLED;
4333 }
Michael Wright17d28ca2013-10-31 17:47:45 -07004334 if (shouldDropInputEvent(q)) {
4335 return FINISH_NOT_HANDLED;
4336 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004337 }
4338
4339 // Apply the fallback event policy.
4340 if (mFallbackEventHandler.dispatchKeyEvent(event)) {
4341 return FINISH_HANDLED;
4342 }
Michael Wright17d28ca2013-10-31 17:47:45 -07004343 if (shouldDropInputEvent(q)) {
4344 return FINISH_NOT_HANDLED;
4345 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004346
4347 // Handle automatic focus changes.
4348 if (event.getAction() == KeyEvent.ACTION_DOWN) {
4349 int direction = 0;
4350 switch (event.getKeyCode()) {
4351 case KeyEvent.KEYCODE_DPAD_LEFT:
4352 if (event.hasNoModifiers()) {
4353 direction = View.FOCUS_LEFT;
4354 }
4355 break;
4356 case KeyEvent.KEYCODE_DPAD_RIGHT:
4357 if (event.hasNoModifiers()) {
4358 direction = View.FOCUS_RIGHT;
4359 }
4360 break;
4361 case KeyEvent.KEYCODE_DPAD_UP:
4362 if (event.hasNoModifiers()) {
4363 direction = View.FOCUS_UP;
4364 }
4365 break;
4366 case KeyEvent.KEYCODE_DPAD_DOWN:
4367 if (event.hasNoModifiers()) {
4368 direction = View.FOCUS_DOWN;
4369 }
4370 break;
4371 case KeyEvent.KEYCODE_TAB:
4372 if (event.hasNoModifiers()) {
4373 direction = View.FOCUS_FORWARD;
4374 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
4375 direction = View.FOCUS_BACKWARD;
4376 }
4377 break;
4378 }
4379 if (direction != 0) {
4380 View focused = mView.findFocus();
4381 if (focused != null) {
4382 View v = focused.focusSearch(direction);
4383 if (v != null && v != focused) {
4384 // do the math the get the interesting rect
4385 // of previous focused into the coord system of
4386 // newly focused view
4387 focused.getFocusedRect(mTempRect);
4388 if (mView instanceof ViewGroup) {
4389 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
4390 focused, mTempRect);
4391 ((ViewGroup) mView).offsetRectIntoDescendantCoords(
4392 v, mTempRect);
4393 }
4394 if (v.requestFocus(direction, mTempRect)) {
4395 playSoundEffect(SoundEffectConstants
4396 .getContantForFocusDirection(direction));
4397 return FINISH_HANDLED;
4398 }
4399 }
4400
4401 // Give the focused view a last chance to handle the dpad key.
4402 if (mView.dispatchUnhandledMove(focused, direction)) {
4403 return FINISH_HANDLED;
4404 }
4405 } else {
4406 // find the best view to give focus to in this non-touch-mode with no-focus
4407 View v = focusSearch(null, direction);
4408 if (v != null && v.requestFocus(direction)) {
4409 return FINISH_HANDLED;
4410 }
4411 }
4412 }
4413 }
4414 return FORWARD;
Jeff Brown21bc5c92011-02-28 18:27:14 -08004415 }
4416
Jeff Brownf9e989d2013-04-04 23:04:03 -07004417 private int processPointerEvent(QueuedInputEvent q) {
4418 final MotionEvent event = (MotionEvent)q.mEvent;
4419
Vladislav Kaznacheev527905e2016-02-16 16:20:56 -08004420 mAttachInfo.mUnbufferedDispatchRequested = false;
4421 final View eventTarget =
4422 (event.isFromSource(InputDevice.SOURCE_MOUSE) && mCapturingView != null) ?
4423 mCapturingView : mView;
4424 mAttachInfo.mHandlingPointerEvent = true;
4425 boolean handled = eventTarget.dispatchPointerEvent(event);
4426 maybeUpdatePointerIcon(event);
4427 mAttachInfo.mHandlingPointerEvent = false;
4428 if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
4429 mUnbufferedInputDispatch = true;
4430 if (mConsumeBatchedInputScheduled) {
4431 scheduleConsumeBatchedInputImmediately();
4432 }
4433 }
4434 return handled ? FINISH_HANDLED : FORWARD;
4435 }
4436
4437 private void maybeUpdatePointerIcon(MotionEvent event) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01004438 if (event.getPointerCount() == 1 && event.isFromSource(InputDevice.SOURCE_MOUSE)) {
Jun Mukai1db53972015-09-11 18:08:31 -07004439 if (event.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER
4440 || event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01004441 // Other apps or the window manager may change the icon type outside of
4442 // this app, therefore the icon type has to be reset on enter/exit event.
4443 mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
Jun Mukai1db53972015-09-11 18:08:31 -07004444 }
4445
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08004446 if (event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT) {
4447 if (!updatePointerIcon(event) &&
4448 event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01004449 mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
Jun Mukai1db53972015-09-11 18:08:31 -07004450 }
4451 }
4452 }
Jeff Brown3915bb82010-11-05 15:02:16 -07004453 }
4454
Jeff Brownf9e989d2013-04-04 23:04:03 -07004455 private int processTrackballEvent(QueuedInputEvent q) {
4456 final MotionEvent event = (MotionEvent)q.mEvent;
4457
4458 if (mView.dispatchTrackballEvent(event)) {
4459 return FINISH_HANDLED;
4460 }
4461 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004462 }
4463
Jeff Brownf9e989d2013-04-04 23:04:03 -07004464 private int processGenericMotionEvent(QueuedInputEvent q) {
4465 final MotionEvent event = (MotionEvent)q.mEvent;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07004466
Jeff Brownf9e989d2013-04-04 23:04:03 -07004467 // Deliver the event to the view.
4468 if (mView.dispatchGenericMotionEvent(event)) {
4469 return FINISH_HANDLED;
4470 }
4471 return FORWARD;
Jeff Brown3915bb82010-11-05 15:02:16 -07004472 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07004473 }
4474
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08004475 private void resetPointerIcon(MotionEvent event) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01004476 mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED;
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08004477 updatePointerIcon(event);
4478 }
4479
4480 private boolean updatePointerIcon(MotionEvent event) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +01004481 final int pointerIndex = 0;
4482 final float x = event.getX(pointerIndex);
4483 final float y = event.getY(pointerIndex);
Andrii Kulian33c1bc52016-02-29 10:38:59 -08004484 if (mView == null) {
4485 // E.g. click outside a popup to dismiss it
4486 Slog.d(mTag, "updatePointerIcon called after view was removed");
4487 return false;
4488 }
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08004489 if (x < 0 || x >= mView.getWidth() || y < 0 || y >= mView.getHeight()) {
Andrii Kulian33c1bc52016-02-29 10:38:59 -08004490 // E.g. when moving window divider with mouse
4491 Slog.d(mTag, "updatePointerIcon called with position out of bounds");
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08004492 return false;
4493 }
Michael Wrightf9d9ce772016-05-13 17:44:16 +01004494 final PointerIcon pointerIcon = mView.onResolvePointerIcon(event, pointerIndex);
4495 final int pointerType = (pointerIcon != null) ?
4496 pointerIcon.getType() : PointerIcon.TYPE_DEFAULT;
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08004497
Michael Wrightf9d9ce772016-05-13 17:44:16 +01004498 if (mPointerIconType != pointerType) {
4499 mPointerIconType = pointerType;
4500 if (mPointerIconType != PointerIcon.TYPE_CUSTOM) {
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08004501 mCustomPointerIcon = null;
Michael Wrightf9d9ce772016-05-13 17:44:16 +01004502 InputManager.getInstance().setPointerIconType(pointerType);
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08004503 return true;
4504 }
4505 }
Michael Wrightf9d9ce772016-05-13 17:44:16 +01004506 if (mPointerIconType == PointerIcon.TYPE_CUSTOM &&
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08004507 !pointerIcon.equals(mCustomPointerIcon)) {
4508 mCustomPointerIcon = pointerIcon;
4509 InputManager.getInstance().setCustomPointerIcon(mCustomPointerIcon);
4510 }
4511 return true;
4512 }
4513
Jeff Brownf9e989d2013-04-04 23:04:03 -07004514 /**
Jeff Brown678a1252013-04-09 17:46:25 -07004515 * Performs synthesis of new input events from unhandled input events.
Jeff Brownf9e989d2013-04-04 23:04:03 -07004516 */
4517 final class SyntheticInputStage extends InputStage {
Jeff Brown678a1252013-04-09 17:46:25 -07004518 private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler();
4519 private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
4520 private final SyntheticTouchNavigationHandler mTouchNavigation =
4521 new SyntheticTouchNavigationHandler();
Michael Wright899d7052014-04-23 17:23:39 -07004522 private final SyntheticKeyboardHandler mKeyboard = new SyntheticKeyboardHandler();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004523
4524 public SyntheticInputStage() {
4525 super(null);
Jeff Brown21bc5c92011-02-28 18:27:14 -08004526 }
4527
Jeff Brownf9e989d2013-04-04 23:04:03 -07004528 @Override
4529 protected int onProcess(QueuedInputEvent q) {
4530 q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED;
4531 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07004532 final MotionEvent event = (MotionEvent)q.mEvent;
4533 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004534 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004535 mTrackball.process(event);
4536 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004537 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004538 mJoystick.process(event);
4539 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004540 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
4541 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07004542 mTouchNavigation.process(event);
4543 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004544 }
Michael Wright899d7052014-04-23 17:23:39 -07004545 } else if ((q.mFlags & QueuedInputEvent.FLAG_UNHANDLED) != 0) {
4546 mKeyboard.process((KeyEvent)q.mEvent);
4547 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004548 }
Michael Wright899d7052014-04-23 17:23:39 -07004549
Jeff Brownf9e989d2013-04-04 23:04:03 -07004550 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004551 }
4552
Jeff Brownf9e989d2013-04-04 23:04:03 -07004553 @Override
4554 protected void onDeliverToNext(QueuedInputEvent q) {
4555 if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) {
4556 // Cancel related synthetic events if any prior stage has handled the event.
4557 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07004558 final MotionEvent event = (MotionEvent)q.mEvent;
4559 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004560 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004561 mTrackball.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004562 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004563 mJoystick.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004564 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
4565 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07004566 mTouchNavigation.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004567 }
4568 }
4569 }
4570 super.onDeliverToNext(q);
4571 }
Jeff Brown678a1252013-04-09 17:46:25 -07004572 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004573
Jeff Brown678a1252013-04-09 17:46:25 -07004574 /**
4575 * Creates dpad events from unhandled trackball movements.
4576 */
4577 final class SyntheticTrackballHandler {
4578 private final TrackballAxis mX = new TrackballAxis();
4579 private final TrackballAxis mY = new TrackballAxis();
4580 private long mLastTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004581
Jeff Brown678a1252013-04-09 17:46:25 -07004582 public void process(MotionEvent event) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004583 // Translate the trackball event into DPAD keys and try to deliver those.
Jeff Brownf9e989d2013-04-04 23:04:03 -07004584 long curTime = SystemClock.uptimeMillis();
Jeff Brown678a1252013-04-09 17:46:25 -07004585 if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004586 // It has been too long since the last movement,
4587 // so restart at the beginning.
Jeff Brown678a1252013-04-09 17:46:25 -07004588 mX.reset(0);
4589 mY.reset(0);
4590 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004591 }
4592
4593 final int action = event.getAction();
4594 final int metaState = event.getMetaState();
4595 switch (action) {
4596 case MotionEvent.ACTION_DOWN:
Jeff Brown678a1252013-04-09 17:46:25 -07004597 mX.reset(2);
4598 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004599 enqueueInputEvent(new KeyEvent(curTime, curTime,
4600 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
4601 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4602 InputDevice.SOURCE_KEYBOARD));
4603 break;
4604 case MotionEvent.ACTION_UP:
Jeff Brown678a1252013-04-09 17:46:25 -07004605 mX.reset(2);
4606 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004607 enqueueInputEvent(new KeyEvent(curTime, curTime,
4608 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
4609 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4610 InputDevice.SOURCE_KEYBOARD));
4611 break;
4612 }
4613
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004614 if (DEBUG_TRACKBALL) Log.v(mTag, "TB X=" + mX.position + " step="
Jeff Brown678a1252013-04-09 17:46:25 -07004615 + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07004616 + " move=" + event.getX()
Jeff Brown678a1252013-04-09 17:46:25 -07004617 + " / Y=" + mY.position + " step="
4618 + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07004619 + " move=" + event.getY());
Jeff Brown678a1252013-04-09 17:46:25 -07004620 final float xOff = mX.collect(event.getX(), event.getEventTime(), "X");
4621 final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y");
Jeff Brownf9e989d2013-04-04 23:04:03 -07004622
4623 // Generate DPAD events based on the trackball movement.
4624 // We pick the axis that has moved the most as the direction of
4625 // the DPAD. When we generate DPAD events for one axis, then the
4626 // other axis is reset -- we don't want to perform DPAD jumps due
4627 // to slight movements in the trackball when making major movements
4628 // along the other axis.
4629 int keycode = 0;
4630 int movement = 0;
4631 float accel = 1;
4632 if (xOff > yOff) {
Jeff Brown678a1252013-04-09 17:46:25 -07004633 movement = mX.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004634 if (movement != 0) {
4635 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
4636 : KeyEvent.KEYCODE_DPAD_LEFT;
Jeff Brown678a1252013-04-09 17:46:25 -07004637 accel = mX.acceleration;
4638 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004639 }
4640 } else if (yOff > 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004641 movement = mY.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004642 if (movement != 0) {
4643 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
4644 : KeyEvent.KEYCODE_DPAD_UP;
Jeff Brown678a1252013-04-09 17:46:25 -07004645 accel = mY.acceleration;
4646 mX.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004647 }
4648 }
4649
4650 if (keycode != 0) {
4651 if (movement < 0) movement = -movement;
4652 int accelMovement = (int)(movement * accel);
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004653 if (DEBUG_TRACKBALL) Log.v(mTag, "Move: movement=" + movement
Jeff Brownf9e989d2013-04-04 23:04:03 -07004654 + " accelMovement=" + accelMovement
4655 + " accel=" + accel);
4656 if (accelMovement > movement) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004657 if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
Jeff Brownf9e989d2013-04-04 23:04:03 -07004658 + keycode);
4659 movement--;
4660 int repeatCount = accelMovement - movement;
4661 enqueueInputEvent(new KeyEvent(curTime, curTime,
4662 KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
4663 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4664 InputDevice.SOURCE_KEYBOARD));
4665 }
4666 while (movement > 0) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004667 if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
Jeff Brownf9e989d2013-04-04 23:04:03 -07004668 + keycode);
4669 movement--;
4670 curTime = SystemClock.uptimeMillis();
4671 enqueueInputEvent(new KeyEvent(curTime, curTime,
4672 KeyEvent.ACTION_DOWN, keycode, 0, metaState,
4673 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4674 InputDevice.SOURCE_KEYBOARD));
4675 enqueueInputEvent(new KeyEvent(curTime, curTime,
4676 KeyEvent.ACTION_UP, keycode, 0, metaState,
4677 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4678 InputDevice.SOURCE_KEYBOARD));
4679 }
Jeff Brown678a1252013-04-09 17:46:25 -07004680 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004681 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004682 }
4683
Jeff Brown678a1252013-04-09 17:46:25 -07004684 public void cancel(MotionEvent event) {
4685 mLastTime = Integer.MIN_VALUE;
Jeff Brown3915bb82010-11-05 15:02:16 -07004686
Jeff Brownf9e989d2013-04-04 23:04:03 -07004687 // If we reach this, we consumed a trackball event.
4688 // Because we will not translate the trackball event into a key event,
4689 // touch mode will not exit, so we exit touch mode here.
4690 if (mView != null && mAdded) {
4691 ensureTouchMode(false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07004692 }
4693 }
Jeff Brown678a1252013-04-09 17:46:25 -07004694 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004695
Jeff Brown678a1252013-04-09 17:46:25 -07004696 /**
4697 * Maintains state information for a single trackball axis, generating
4698 * discrete (DPAD) movements based on raw trackball motion.
4699 */
4700 static final class TrackballAxis {
4701 /**
4702 * The maximum amount of acceleration we will apply.
4703 */
4704 static final float MAX_ACCELERATION = 20;
4705
4706 /**
4707 * The maximum amount of time (in milliseconds) between events in order
4708 * for us to consider the user to be doing fast trackball movements,
4709 * and thus apply an acceleration.
4710 */
4711 static final long FAST_MOVE_TIME = 150;
4712
4713 /**
4714 * Scaling factor to the time (in milliseconds) between events to how
4715 * much to multiple/divide the current acceleration. When movement
4716 * is < FAST_MOVE_TIME this multiplies the acceleration; when >
4717 * FAST_MOVE_TIME it divides it.
4718 */
4719 static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
4720
4721 static final float FIRST_MOVEMENT_THRESHOLD = 0.5f;
4722 static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f;
4723 static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f;
4724
4725 float position;
4726 float acceleration = 1;
4727 long lastMoveTime = 0;
4728 int step;
4729 int dir;
4730 int nonAccelMovement;
4731
4732 void reset(int _step) {
4733 position = 0;
4734 acceleration = 1;
4735 lastMoveTime = 0;
4736 step = _step;
4737 dir = 0;
Jeff Brown6f2fba42011-02-19 01:08:02 -08004738 }
4739
Jeff Brown678a1252013-04-09 17:46:25 -07004740 /**
4741 * Add trackball movement into the state. If the direction of movement
4742 * has been reversed, the state is reset before adding the
4743 * movement (so that you don't have to compensate for any previously
4744 * collected movement before see the result of the movement in the
4745 * new direction).
4746 *
4747 * @return Returns the absolute value of the amount of movement
4748 * collected so far.
4749 */
4750 float collect(float off, long time, String axis) {
4751 long normTime;
4752 if (off > 0) {
4753 normTime = (long)(off * FAST_MOVE_TIME);
4754 if (dir < 0) {
4755 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
4756 position = 0;
4757 step = 0;
4758 acceleration = 1;
4759 lastMoveTime = 0;
4760 }
4761 dir = 1;
4762 } else if (off < 0) {
4763 normTime = (long)((-off) * FAST_MOVE_TIME);
4764 if (dir > 0) {
4765 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
4766 position = 0;
4767 step = 0;
4768 acceleration = 1;
4769 lastMoveTime = 0;
4770 }
4771 dir = -1;
4772 } else {
4773 normTime = 0;
4774 }
4775
4776 // The number of milliseconds between each movement that is
4777 // considered "normal" and will not result in any acceleration
4778 // or deceleration, scaled by the offset we have here.
4779 if (normTime > 0) {
4780 long delta = time - lastMoveTime;
4781 lastMoveTime = time;
4782 float acc = acceleration;
4783 if (delta < normTime) {
4784 // The user is scrolling rapidly, so increase acceleration.
4785 float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
4786 if (scale > 1) acc *= scale;
4787 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
4788 + off + " normTime=" + normTime + " delta=" + delta
4789 + " scale=" + scale + " acc=" + acc);
4790 acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
4791 } else {
4792 // The user is scrolling slowly, so decrease acceleration.
4793 float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
4794 if (scale > 1) acc /= scale;
4795 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
4796 + off + " normTime=" + normTime + " delta=" + delta
4797 + " scale=" + scale + " acc=" + acc);
4798 acceleration = acc > 1 ? acc : 1;
4799 }
4800 }
4801 position += off;
4802 return Math.abs(position);
Jeff Brown6f2fba42011-02-19 01:08:02 -08004803 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004804
Jeff Brown678a1252013-04-09 17:46:25 -07004805 /**
4806 * Generate the number of discrete movement events appropriate for
4807 * the currently collected trackball movement.
4808 *
4809 * @return Returns the number of discrete movements, either positive
4810 * or negative, or 0 if there is not enough trackball movement yet
4811 * for a discrete movement.
4812 */
4813 int generate() {
4814 int movement = 0;
4815 nonAccelMovement = 0;
4816 do {
4817 final int dir = position >= 0 ? 1 : -1;
4818 switch (step) {
4819 // If we are going to execute the first step, then we want
4820 // to do this as soon as possible instead of waiting for
4821 // a full movement, in order to make things look responsive.
4822 case 0:
4823 if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) {
4824 return movement;
4825 }
4826 movement += dir;
4827 nonAccelMovement += dir;
4828 step = 1;
4829 break;
4830 // If we have generated the first movement, then we need
4831 // to wait for the second complete trackball motion before
4832 // generating the second discrete movement.
4833 case 1:
4834 if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) {
4835 return movement;
4836 }
4837 movement += dir;
4838 nonAccelMovement += dir;
4839 position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir;
4840 step = 2;
4841 break;
4842 // After the first two, we generate discrete movements
4843 // consistently with the trackball, applying an acceleration
4844 // if the trackball is moving quickly. This is a simple
4845 // acceleration on top of what we already compute based
4846 // on how quickly the wheel is being turned, to apply
4847 // a longer increasing acceleration to continuous movement
4848 // in one direction.
4849 default:
4850 if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) {
4851 return movement;
4852 }
4853 movement += dir;
4854 position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD;
4855 float acc = acceleration;
4856 acc *= 1.1f;
4857 acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
4858 break;
4859 }
4860 } while (true);
4861 }
4862 }
4863
4864 /**
4865 * Creates dpad events from unhandled joystick movements.
4866 */
4867 final class SyntheticJoystickHandler extends Handler {
Michael Wright9adca062014-03-19 11:51:26 -07004868 private final static String TAG = "SyntheticJoystickHandler";
Jeff Brown678a1252013-04-09 17:46:25 -07004869 private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
4870 private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
4871
4872 private int mLastXDirection;
4873 private int mLastYDirection;
4874 private int mLastXKeyCode;
4875 private int mLastYKeyCode;
4876
4877 public SyntheticJoystickHandler() {
4878 super(true);
4879 }
4880
4881 @Override
4882 public void handleMessage(Message msg) {
4883 switch (msg.what) {
4884 case MSG_ENQUEUE_X_AXIS_KEY_REPEAT:
4885 case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: {
4886 KeyEvent oldEvent = (KeyEvent)msg.obj;
4887 KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent,
4888 SystemClock.uptimeMillis(),
4889 oldEvent.getRepeatCount() + 1);
4890 if (mAttachInfo.mHasWindowFocus) {
4891 enqueueInputEvent(e);
4892 Message m = obtainMessage(msg.what, e);
4893 m.setAsynchronous(true);
4894 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay());
4895 }
4896 } break;
4897 }
4898 }
4899
4900 public void process(MotionEvent event) {
Michael Wright9adca062014-03-19 11:51:26 -07004901 switch(event.getActionMasked()) {
4902 case MotionEvent.ACTION_CANCEL:
4903 cancel(event);
4904 break;
4905 case MotionEvent.ACTION_MOVE:
4906 update(event, true);
4907 break;
4908 default:
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08004909 Log.w(mTag, "Unexpected action: " + event.getActionMasked());
Michael Wright9adca062014-03-19 11:51:26 -07004910 }
Jeff Brown678a1252013-04-09 17:46:25 -07004911 }
4912
Michael Wright9adca062014-03-19 11:51:26 -07004913 private void cancel(MotionEvent event) {
4914 removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
4915 removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
Jeff Brown678a1252013-04-09 17:46:25 -07004916 update(event, false);
4917 }
4918
4919 private void update(MotionEvent event, boolean synthesizeNewKeys) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004920 final long time = event.getEventTime();
4921 final int metaState = event.getMetaState();
4922 final int deviceId = event.getDeviceId();
4923 final int source = event.getSource();
4924
4925 int xDirection = joystickAxisValueToDirection(
4926 event.getAxisValue(MotionEvent.AXIS_HAT_X));
4927 if (xDirection == 0) {
4928 xDirection = joystickAxisValueToDirection(event.getX());
Jeff Browncb1404e2011-01-15 18:14:15 -08004929 }
4930
Jeff Brownf9e989d2013-04-04 23:04:03 -07004931 int yDirection = joystickAxisValueToDirection(
4932 event.getAxisValue(MotionEvent.AXIS_HAT_Y));
4933 if (yDirection == 0) {
4934 yDirection = joystickAxisValueToDirection(event.getY());
4935 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004936
Jeff Brown678a1252013-04-09 17:46:25 -07004937 if (xDirection != mLastXDirection) {
4938 if (mLastXKeyCode != 0) {
4939 removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004940 enqueueInputEvent(new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004941 KeyEvent.ACTION_UP, mLastXKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004942 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Brown678a1252013-04-09 17:46:25 -07004943 mLastXKeyCode = 0;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004944 }
4945
Jeff Brown678a1252013-04-09 17:46:25 -07004946 mLastXDirection = xDirection;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004947
4948 if (xDirection != 0 && synthesizeNewKeys) {
Jeff Brown678a1252013-04-09 17:46:25 -07004949 mLastXKeyCode = xDirection > 0
Jeff Brownf9e989d2013-04-04 23:04:03 -07004950 ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
4951 final KeyEvent e = new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004952 KeyEvent.ACTION_DOWN, mLastXKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004953 deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
4954 enqueueInputEvent(e);
Jeff Brown678a1252013-04-09 17:46:25 -07004955 Message m = obtainMessage(MSG_ENQUEUE_X_AXIS_KEY_REPEAT, e);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004956 m.setAsynchronous(true);
Michael Wrightb9618522013-04-10 15:20:56 -07004957 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
Jeff Brownf9e989d2013-04-04 23:04:03 -07004958 }
4959 }
4960
Jeff Brown678a1252013-04-09 17:46:25 -07004961 if (yDirection != mLastYDirection) {
4962 if (mLastYKeyCode != 0) {
4963 removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004964 enqueueInputEvent(new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004965 KeyEvent.ACTION_UP, mLastYKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004966 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Brown678a1252013-04-09 17:46:25 -07004967 mLastYKeyCode = 0;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004968 }
4969
Jeff Brown678a1252013-04-09 17:46:25 -07004970 mLastYDirection = yDirection;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004971
4972 if (yDirection != 0 && synthesizeNewKeys) {
Jeff Brown678a1252013-04-09 17:46:25 -07004973 mLastYKeyCode = yDirection > 0
Jeff Brownf9e989d2013-04-04 23:04:03 -07004974 ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
4975 final KeyEvent e = new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004976 KeyEvent.ACTION_DOWN, mLastYKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004977 deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
4978 enqueueInputEvent(e);
Jeff Brown678a1252013-04-09 17:46:25 -07004979 Message m = obtainMessage(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT, e);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004980 m.setAsynchronous(true);
Jeff Brown678a1252013-04-09 17:46:25 -07004981 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
Jeff Brownf9e989d2013-04-04 23:04:03 -07004982 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004983 }
4984 }
4985
Jeff Brownf9e989d2013-04-04 23:04:03 -07004986 private int joystickAxisValueToDirection(float value) {
4987 if (value >= 0.5f) {
4988 return 1;
4989 } else if (value <= -0.5f) {
4990 return -1;
4991 } else {
4992 return 0;
Jeff Browncb1404e2011-01-15 18:14:15 -08004993 }
4994 }
Jeff Brown678a1252013-04-09 17:46:25 -07004995 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004996
Jeff Brown678a1252013-04-09 17:46:25 -07004997 /**
4998 * Creates dpad events from unhandled touch navigation movements.
4999 */
5000 final class SyntheticTouchNavigationHandler extends Handler {
Jeff Brown4dac9012013-04-10 01:03:19 -07005001 private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler";
5002 private static final boolean LOCAL_DEBUG = false;
Jeff Brown678a1252013-04-09 17:46:25 -07005003
Jeff Brown4dac9012013-04-10 01:03:19 -07005004 // Assumed nominal width and height in millimeters of a touch navigation pad,
5005 // if no resolution information is available from the input system.
5006 private static final float DEFAULT_WIDTH_MILLIMETERS = 48;
5007 private static final float DEFAULT_HEIGHT_MILLIMETERS = 48;
Jeff Brown678a1252013-04-09 17:46:25 -07005008
Jeff Brown4dac9012013-04-10 01:03:19 -07005009 /* TODO: These constants should eventually be moved to ViewConfiguration. */
Jeff Brown678a1252013-04-09 17:46:25 -07005010
Jeff Brown4dac9012013-04-10 01:03:19 -07005011 // The nominal distance traveled to move by one unit.
5012 private static final int TICK_DISTANCE_MILLIMETERS = 12;
5013
5014 // Minimum and maximum fling velocity in ticks per second.
5015 // The minimum velocity should be set such that we perform enough ticks per
5016 // second that the fling appears to be fluid. For example, if we set the minimum
5017 // to 2 ticks per second, then there may be up to half a second delay between the next
5018 // to last and last ticks which is noticeably discrete and jerky. This value should
5019 // probably not be set to anything less than about 4.
5020 // If fling accuracy is a problem then consider tuning the tick distance instead.
5021 private static final float MIN_FLING_VELOCITY_TICKS_PER_SECOND = 6f;
5022 private static final float MAX_FLING_VELOCITY_TICKS_PER_SECOND = 20f;
5023
5024 // Fling velocity decay factor applied after each new key is emitted.
5025 // This parameter controls the deceleration and overall duration of the fling.
5026 // The fling stops automatically when its velocity drops below the minimum
5027 // fling velocity defined above.
5028 private static final float FLING_TICK_DECAY = 0.8f;
5029
5030 /* The input device that we are tracking. */
5031
5032 private int mCurrentDeviceId = -1;
5033 private int mCurrentSource;
5034 private boolean mCurrentDeviceSupported;
5035
5036 /* Configuration for the current input device. */
5037
Jeff Brown4dac9012013-04-10 01:03:19 -07005038 // The scaled tick distance. A movement of this amount should generally translate
5039 // into a single dpad event in a given direction.
5040 private float mConfigTickDistance;
5041
5042 // The minimum and maximum scaled fling velocity.
5043 private float mConfigMinFlingVelocity;
5044 private float mConfigMaxFlingVelocity;
5045
5046 /* Tracking state. */
5047
5048 // The velocity tracker for detecting flings.
5049 private VelocityTracker mVelocityTracker;
5050
5051 // The active pointer id, or -1 if none.
5052 private int mActivePointerId = -1;
5053
John Reck79d81e62013-11-05 13:26:57 -08005054 // Location where tracking started.
Jeff Brown4dac9012013-04-10 01:03:19 -07005055 private float mStartX;
5056 private float mStartY;
5057
5058 // Most recently observed position.
5059 private float mLastX;
5060 private float mLastY;
5061
5062 // Accumulated movement delta since the last direction key was sent.
Jeff Brown678a1252013-04-09 17:46:25 -07005063 private float mAccumulatedX;
5064 private float mAccumulatedY;
5065
Jeff Brown4dac9012013-04-10 01:03:19 -07005066 // Set to true if any movement was delivered to the app.
5067 // Implies that tap slop was exceeded.
5068 private boolean mConsumedMovement;
Jeff Brown678a1252013-04-09 17:46:25 -07005069
Jeff Brown4dac9012013-04-10 01:03:19 -07005070 // The most recently sent key down event.
5071 // The keycode remains set until the direction changes or a fling ends
5072 // so that repeated key events may be generated as required.
5073 private long mPendingKeyDownTime;
5074 private int mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
5075 private int mPendingKeyRepeatCount;
5076 private int mPendingKeyMetaState;
Jeff Brown678a1252013-04-09 17:46:25 -07005077
Jeff Brown4dac9012013-04-10 01:03:19 -07005078 // The current fling velocity while a fling is in progress.
5079 private boolean mFlinging;
5080 private float mFlingVelocity;
Jeff Brown678a1252013-04-09 17:46:25 -07005081
5082 public SyntheticTouchNavigationHandler() {
5083 super(true);
Jeff Brown678a1252013-04-09 17:46:25 -07005084 }
5085
5086 public void process(MotionEvent event) {
Jeff Brown4dac9012013-04-10 01:03:19 -07005087 // Update the current device information.
5088 final long time = event.getEventTime();
5089 final int deviceId = event.getDeviceId();
5090 final int source = event.getSource();
5091 if (mCurrentDeviceId != deviceId || mCurrentSource != source) {
5092 finishKeys(time);
5093 finishTracking(time);
5094 mCurrentDeviceId = deviceId;
5095 mCurrentSource = source;
5096 mCurrentDeviceSupported = false;
5097 InputDevice device = event.getDevice();
5098 if (device != null) {
5099 // In order to support an input device, we must know certain
5100 // characteristics about it, such as its size and resolution.
5101 InputDevice.MotionRange xRange = device.getMotionRange(MotionEvent.AXIS_X);
5102 InputDevice.MotionRange yRange = device.getMotionRange(MotionEvent.AXIS_Y);
5103 if (xRange != null && yRange != null) {
5104 mCurrentDeviceSupported = true;
Jeff Brown678a1252013-04-09 17:46:25 -07005105
Jeff Brown4dac9012013-04-10 01:03:19 -07005106 // Infer the resolution if it not actually known.
5107 float xRes = xRange.getResolution();
5108 if (xRes <= 0) {
5109 xRes = xRange.getRange() / DEFAULT_WIDTH_MILLIMETERS;
5110 }
5111 float yRes = yRange.getResolution();
5112 if (yRes <= 0) {
5113 yRes = yRange.getRange() / DEFAULT_HEIGHT_MILLIMETERS;
5114 }
5115 float nominalRes = (xRes + yRes) * 0.5f;
Jeff Brown678a1252013-04-09 17:46:25 -07005116
Jeff Brown4dac9012013-04-10 01:03:19 -07005117 // Precompute all of the configuration thresholds we will need.
Jeff Brown4dac9012013-04-10 01:03:19 -07005118 mConfigTickDistance = TICK_DISTANCE_MILLIMETERS * nominalRes;
5119 mConfigMinFlingVelocity =
5120 MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
5121 mConfigMaxFlingVelocity =
5122 MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
5123
5124 if (LOCAL_DEBUG) {
5125 Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId
5126 + " (" + Integer.toHexString(mCurrentSource) + "): "
Jeff Brown4dac9012013-04-10 01:03:19 -07005127 + ", mConfigTickDistance=" + mConfigTickDistance
5128 + ", mConfigMinFlingVelocity=" + mConfigMinFlingVelocity
5129 + ", mConfigMaxFlingVelocity=" + mConfigMaxFlingVelocity);
5130 }
5131 }
5132 }
Jeff Brown678a1252013-04-09 17:46:25 -07005133 }
Jeff Brown4dac9012013-04-10 01:03:19 -07005134 if (!mCurrentDeviceSupported) {
Jeff Brown678a1252013-04-09 17:46:25 -07005135 return;
5136 }
5137
Jeff Brown4dac9012013-04-10 01:03:19 -07005138 // Handle the event.
5139 final int action = event.getActionMasked();
5140 switch (action) {
Jeff Brown678a1252013-04-09 17:46:25 -07005141 case MotionEvent.ACTION_DOWN: {
Jeff Brown4dac9012013-04-10 01:03:19 -07005142 boolean caughtFling = mFlinging;
5143 finishKeys(time);
5144 finishTracking(time);
5145 mActivePointerId = event.getPointerId(0);
5146 mVelocityTracker = VelocityTracker.obtain();
5147 mVelocityTracker.addMovement(event);
Jeff Brown4dac9012013-04-10 01:03:19 -07005148 mStartX = event.getX();
5149 mStartY = event.getY();
5150 mLastX = mStartX;
5151 mLastY = mStartY;
Jeff Brown678a1252013-04-09 17:46:25 -07005152 mAccumulatedX = 0;
5153 mAccumulatedY = 0;
Jeff Brown4dac9012013-04-10 01:03:19 -07005154
5155 // If we caught a fling, then pretend that the tap slop has already
5156 // been exceeded to suppress taps whose only purpose is to stop the fling.
5157 mConsumedMovement = caughtFling;
Jeff Brown678a1252013-04-09 17:46:25 -07005158 break;
5159 }
5160
Jeff Brown4dac9012013-04-10 01:03:19 -07005161 case MotionEvent.ACTION_MOVE:
Jeff Brown678a1252013-04-09 17:46:25 -07005162 case MotionEvent.ACTION_UP: {
Jeff Brown4dac9012013-04-10 01:03:19 -07005163 if (mActivePointerId < 0) {
5164 break;
5165 }
5166 final int index = event.findPointerIndex(mActivePointerId);
5167 if (index < 0) {
5168 finishKeys(time);
5169 finishTracking(time);
5170 break;
5171 }
Jeff Brown678a1252013-04-09 17:46:25 -07005172
Jeff Brown4dac9012013-04-10 01:03:19 -07005173 mVelocityTracker.addMovement(event);
5174 final float x = event.getX(index);
5175 final float y = event.getY(index);
5176 mAccumulatedX += x - mLastX;
5177 mAccumulatedY += y - mLastY;
5178 mLastX = x;
5179 mLastY = y;
5180
5181 // Consume any accumulated movement so far.
5182 final int metaState = event.getMetaState();
5183 consumeAccumulatedMovement(time, metaState);
5184
5185 // Detect taps and flings.
5186 if (action == MotionEvent.ACTION_UP) {
Michael Wright88d7f792013-08-27 15:45:42 -07005187 if (mConsumedMovement && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
Jeff Brown4dac9012013-04-10 01:03:19 -07005188 // It might be a fling.
5189 mVelocityTracker.computeCurrentVelocity(1000, mConfigMaxFlingVelocity);
5190 final float vx = mVelocityTracker.getXVelocity(mActivePointerId);
5191 final float vy = mVelocityTracker.getYVelocity(mActivePointerId);
5192 if (!startFling(time, vx, vy)) {
5193 finishKeys(time);
Jeff Brown678a1252013-04-09 17:46:25 -07005194 }
5195 }
Jeff Brown4dac9012013-04-10 01:03:19 -07005196 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07005197 }
Jeff Brown4dac9012013-04-10 01:03:19 -07005198 break;
5199 }
5200
5201 case MotionEvent.ACTION_CANCEL: {
5202 finishKeys(time);
5203 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07005204 break;
5205 }
5206 }
Jeff Browncb1404e2011-01-15 18:14:15 -08005207 }
Jeff Brown4dac9012013-04-10 01:03:19 -07005208
5209 public void cancel(MotionEvent event) {
5210 if (mCurrentDeviceId == event.getDeviceId()
5211 && mCurrentSource == event.getSource()) {
5212 final long time = event.getEventTime();
5213 finishKeys(time);
5214 finishTracking(time);
5215 }
5216 }
5217
5218 private void finishKeys(long time) {
5219 cancelFling();
5220 sendKeyUp(time);
5221 }
5222
5223 private void finishTracking(long time) {
5224 if (mActivePointerId >= 0) {
5225 mActivePointerId = -1;
5226 mVelocityTracker.recycle();
5227 mVelocityTracker = null;
5228 }
5229 }
5230
5231 private void consumeAccumulatedMovement(long time, int metaState) {
5232 final float absX = Math.abs(mAccumulatedX);
5233 final float absY = Math.abs(mAccumulatedY);
5234 if (absX >= absY) {
5235 if (absX >= mConfigTickDistance) {
5236 mAccumulatedX = consumeAccumulatedMovement(time, metaState, mAccumulatedX,
5237 KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT);
5238 mAccumulatedY = 0;
5239 mConsumedMovement = true;
5240 }
5241 } else {
5242 if (absY >= mConfigTickDistance) {
5243 mAccumulatedY = consumeAccumulatedMovement(time, metaState, mAccumulatedY,
5244 KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN);
5245 mAccumulatedX = 0;
5246 mConsumedMovement = true;
5247 }
5248 }
5249 }
5250
5251 private float consumeAccumulatedMovement(long time, int metaState,
5252 float accumulator, int negativeKeyCode, int positiveKeyCode) {
5253 while (accumulator <= -mConfigTickDistance) {
5254 sendKeyDownOrRepeat(time, negativeKeyCode, metaState);
5255 accumulator += mConfigTickDistance;
5256 }
5257 while (accumulator >= mConfigTickDistance) {
5258 sendKeyDownOrRepeat(time, positiveKeyCode, metaState);
5259 accumulator -= mConfigTickDistance;
5260 }
5261 return accumulator;
5262 }
5263
5264 private void sendKeyDownOrRepeat(long time, int keyCode, int metaState) {
5265 if (mPendingKeyCode != keyCode) {
5266 sendKeyUp(time);
5267 mPendingKeyDownTime = time;
5268 mPendingKeyCode = keyCode;
5269 mPendingKeyRepeatCount = 0;
5270 } else {
5271 mPendingKeyRepeatCount += 1;
5272 }
5273 mPendingKeyMetaState = metaState;
5274
5275 // Note: Normally we would pass FLAG_LONG_PRESS when the repeat count is 1
5276 // but it doesn't quite make sense when simulating the events in this way.
5277 if (LOCAL_DEBUG) {
5278 Log.d(LOCAL_TAG, "Sending key down: keyCode=" + mPendingKeyCode
5279 + ", repeatCount=" + mPendingKeyRepeatCount
5280 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
5281 }
5282 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
5283 KeyEvent.ACTION_DOWN, mPendingKeyCode, mPendingKeyRepeatCount,
5284 mPendingKeyMetaState, mCurrentDeviceId,
5285 KeyEvent.FLAG_FALLBACK, mCurrentSource));
5286 }
5287
5288 private void sendKeyUp(long time) {
5289 if (mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
5290 if (LOCAL_DEBUG) {
5291 Log.d(LOCAL_TAG, "Sending key up: keyCode=" + mPendingKeyCode
5292 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
5293 }
5294 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
5295 KeyEvent.ACTION_UP, mPendingKeyCode, 0, mPendingKeyMetaState,
5296 mCurrentDeviceId, 0, KeyEvent.FLAG_FALLBACK,
5297 mCurrentSource));
5298 mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
5299 }
5300 }
5301
5302 private boolean startFling(long time, float vx, float vy) {
5303 if (LOCAL_DEBUG) {
5304 Log.d(LOCAL_TAG, "Considering fling: vx=" + vx + ", vy=" + vy
5305 + ", min=" + mConfigMinFlingVelocity);
5306 }
5307
5308 // Flings must be oriented in the same direction as the preceding movements.
5309 switch (mPendingKeyCode) {
5310 case KeyEvent.KEYCODE_DPAD_LEFT:
5311 if (-vx >= mConfigMinFlingVelocity
5312 && Math.abs(vy) < mConfigMinFlingVelocity) {
5313 mFlingVelocity = -vx;
5314 break;
5315 }
5316 return false;
5317
5318 case KeyEvent.KEYCODE_DPAD_RIGHT:
5319 if (vx >= mConfigMinFlingVelocity
5320 && Math.abs(vy) < mConfigMinFlingVelocity) {
5321 mFlingVelocity = vx;
5322 break;
5323 }
5324 return false;
5325
5326 case KeyEvent.KEYCODE_DPAD_UP:
5327 if (-vy >= mConfigMinFlingVelocity
5328 && Math.abs(vx) < mConfigMinFlingVelocity) {
5329 mFlingVelocity = -vy;
5330 break;
5331 }
5332 return false;
5333
5334 case KeyEvent.KEYCODE_DPAD_DOWN:
5335 if (vy >= mConfigMinFlingVelocity
5336 && Math.abs(vx) < mConfigMinFlingVelocity) {
5337 mFlingVelocity = vy;
5338 break;
5339 }
5340 return false;
5341 }
5342
5343 // Post the first fling event.
5344 mFlinging = postFling(time);
5345 return mFlinging;
5346 }
5347
5348 private boolean postFling(long time) {
5349 // The idea here is to estimate the time when the pointer would have
5350 // traveled one tick distance unit given the current fling velocity.
5351 // This effect creates continuity of motion.
5352 if (mFlingVelocity >= mConfigMinFlingVelocity) {
5353 long delay = (long)(mConfigTickDistance / mFlingVelocity * 1000);
5354 postAtTime(mFlingRunnable, time + delay);
5355 if (LOCAL_DEBUG) {
5356 Log.d(LOCAL_TAG, "Posted fling: velocity="
5357 + mFlingVelocity + ", delay=" + delay
5358 + ", keyCode=" + mPendingKeyCode);
5359 }
5360 return true;
5361 }
5362 return false;
5363 }
5364
5365 private void cancelFling() {
5366 if (mFlinging) {
5367 removeCallbacks(mFlingRunnable);
5368 mFlinging = false;
5369 }
5370 }
5371
5372 private final Runnable mFlingRunnable = new Runnable() {
5373 @Override
5374 public void run() {
5375 final long time = SystemClock.uptimeMillis();
5376 sendKeyDownOrRepeat(time, mPendingKeyCode, mPendingKeyMetaState);
5377 mFlingVelocity *= FLING_TICK_DECAY;
5378 if (!postFling(time)) {
5379 mFlinging = false;
5380 finishKeys(time);
5381 }
5382 }
5383 };
Jeff Browncb1404e2011-01-15 18:14:15 -08005384 }
5385
Michael Wright899d7052014-04-23 17:23:39 -07005386 final class SyntheticKeyboardHandler {
5387 public void process(KeyEvent event) {
5388 if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
5389 return;
5390 }
5391
5392 final KeyCharacterMap kcm = event.getKeyCharacterMap();
5393 final int keyCode = event.getKeyCode();
5394 final int metaState = event.getMetaState();
5395
5396 // Check for fallback actions specified by the key character map.
5397 KeyCharacterMap.FallbackAction fallbackAction =
5398 kcm.getFallbackAction(keyCode, metaState);
5399 if (fallbackAction != null) {
5400 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
5401 KeyEvent fallbackEvent = KeyEvent.obtain(
5402 event.getDownTime(), event.getEventTime(),
5403 event.getAction(), fallbackAction.keyCode,
5404 event.getRepeatCount(), fallbackAction.metaState,
5405 event.getDeviceId(), event.getScanCode(),
5406 flags, event.getSource(), null);
5407 fallbackAction.recycle();
5408 enqueueInputEvent(fallbackEvent);
5409 }
5410 }
5411 }
5412
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005413 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08005414 * Returns true if the key is used for keyboard navigation.
5415 * @param keyEvent The key event.
5416 * @return True if the key is used for keyboard navigation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005417 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08005418 private static boolean isNavigationKey(KeyEvent keyEvent) {
5419 switch (keyEvent.getKeyCode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005420 case KeyEvent.KEYCODE_DPAD_LEFT:
5421 case KeyEvent.KEYCODE_DPAD_RIGHT:
5422 case KeyEvent.KEYCODE_DPAD_UP:
5423 case KeyEvent.KEYCODE_DPAD_DOWN:
Jeff Brown4e6319b2010-12-13 10:36:51 -08005424 case KeyEvent.KEYCODE_DPAD_CENTER:
5425 case KeyEvent.KEYCODE_PAGE_UP:
5426 case KeyEvent.KEYCODE_PAGE_DOWN:
5427 case KeyEvent.KEYCODE_MOVE_HOME:
5428 case KeyEvent.KEYCODE_MOVE_END:
5429 case KeyEvent.KEYCODE_TAB:
5430 case KeyEvent.KEYCODE_SPACE:
5431 case KeyEvent.KEYCODE_ENTER:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005432 return true;
5433 }
5434 return false;
5435 }
5436
5437 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08005438 * Returns true if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005439 * @param keyEvent The key event.
Jeff Brown4e6319b2010-12-13 10:36:51 -08005440 * @return True if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005441 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08005442 private static boolean isTypingKey(KeyEvent keyEvent) {
5443 return keyEvent.getUnicodeChar() > 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005444 }
5445
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005446 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08005447 * 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 -08005448 * @param event The key event.
5449 * @return Whether this key event should be consumed (meaning the act of
5450 * leaving touch mode alone is considered the event).
5451 */
5452 private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08005453 // Only relevant in touch mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005454 if (!mAttachInfo.mInTouchMode) {
5455 return false;
5456 }
5457
Jeff Brown4e6319b2010-12-13 10:36:51 -08005458 // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
5459 final int action = event.getAction();
5460 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005461 return false;
5462 }
5463
Jeff Brown4e6319b2010-12-13 10:36:51 -08005464 // Don't leave touch mode if the IME told us not to.
5465 if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
5466 return false;
5467 }
5468
5469 // If the key can be used for keyboard navigation then leave touch mode
5470 // and select a focused view if needed (in ensureTouchMode).
5471 // When a new focused view is selected, we consume the navigation key because
5472 // navigation doesn't make much sense unless a view already has focus so
5473 // the key's purpose is to set focus.
5474 if (isNavigationKey(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005475 return ensureTouchMode(false);
5476 }
Jeff Brown4e6319b2010-12-13 10:36:51 -08005477
5478 // If the key can be used for typing then leave touch mode
5479 // and select a focused view if needed (in ensureTouchMode).
5480 // Always allow the view to process the typing key.
5481 if (isTypingKey(event)) {
5482 ensureTouchMode(false);
5483 return false;
5484 }
5485
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005486 return false;
5487 }
5488
Christopher Tatea53146c2010-09-07 11:57:52 -07005489 /* drag/drop */
Christopher Tate407b4e92010-11-30 17:14:08 -08005490 void setLocalDragState(Object obj) {
5491 mLocalDragState = obj;
5492 }
5493
Christopher Tatea53146c2010-09-07 11:57:52 -07005494 private void handleDragEvent(DragEvent event) {
5495 // From the root, only drag start/end/location are dispatched. entered/exited
5496 // are determined and dispatched by the viewgroup hierarchy, who then report
5497 // that back here for ultimate reporting back to the framework.
5498 if (mView != null && mAdded) {
5499 final int what = event.mAction;
5500
5501 if (what == DragEvent.ACTION_DRAG_EXITED) {
5502 // A direct EXITED event means that the window manager knows we've just crossed
5503 // a window boundary, so the current drag target within this one must have
5504 // just been exited. Send it the usual notifications and then we're done
5505 // for now.
Chris Tate9d1ab882010-11-02 15:55:39 -07005506 mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07005507 } else {
5508 // Cache the drag description when the operation starts, then fill it in
5509 // on subsequent calls as a convenience
5510 if (what == DragEvent.ACTION_DRAG_STARTED) {
Chris Tate9d1ab882010-11-02 15:55:39 -07005511 mCurrentDragView = null; // Start the current-recipient tracking
Christopher Tatea53146c2010-09-07 11:57:52 -07005512 mDragDescription = event.mClipDescription;
5513 } else {
5514 event.mClipDescription = mDragDescription;
5515 }
5516
5517 // For events with a [screen] location, translate into window coordinates
5518 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
5519 mDragPoint.set(event.mX, event.mY);
5520 if (mTranslator != null) {
5521 mTranslator.translatePointInScreenToAppWindow(mDragPoint);
5522 }
5523
5524 if (mCurScrollY != 0) {
5525 mDragPoint.offset(0, mCurScrollY);
5526 }
5527
5528 event.mX = mDragPoint.x;
5529 event.mY = mDragPoint.y;
5530 }
5531
5532 // Remember who the current drag target is pre-dispatch
5533 final View prevDragView = mCurrentDragView;
5534
5535 // Now dispatch the drag/drop event
Chris Tated4533f12010-10-19 15:15:08 -07005536 boolean result = mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07005537
5538 // If we changed apparent drag target, tell the OS about it
5539 if (prevDragView != mCurrentDragView) {
5540 try {
5541 if (prevDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07005542 mWindowSession.dragRecipientExited(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07005543 }
5544 if (mCurrentDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07005545 mWindowSession.dragRecipientEntered(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07005546 }
5547 } catch (RemoteException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005548 Slog.e(mTag, "Unable to note drag target change");
Christopher Tatea53146c2010-09-07 11:57:52 -07005549 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005550 }
Chris Tated4533f12010-10-19 15:15:08 -07005551
Christopher Tate407b4e92010-11-30 17:14:08 -08005552 // Report the drop result when we're done
Chris Tated4533f12010-10-19 15:15:08 -07005553 if (what == DragEvent.ACTION_DROP) {
Christopher Tate1fc014f2011-01-19 12:56:26 -08005554 mDragDescription = null;
Chris Tated4533f12010-10-19 15:15:08 -07005555 try {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005556 Log.i(mTag, "Reporting drop result: " + result);
Jeff Brown98365d72012-08-19 20:30:52 -07005557 mWindowSession.reportDropResult(mWindow, result);
Chris Tated4533f12010-10-19 15:15:08 -07005558 } catch (RemoteException e) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005559 Log.e(mTag, "Unable to report drop result");
Chris Tated4533f12010-10-19 15:15:08 -07005560 }
5561 }
Christopher Tate407b4e92010-11-30 17:14:08 -08005562
Vladislav Kaznacheev82063912015-11-20 14:20:13 -08005563 // When the drag operation ends, reset drag-related state
Christopher Tate407b4e92010-11-30 17:14:08 -08005564 if (what == DragEvent.ACTION_DRAG_ENDED) {
5565 setLocalDragState(null);
Vladislav Kaznacheev82063912015-11-20 14:20:13 -08005566 mAttachInfo.mDragToken = null;
Vladislav Kaznacheev4f639742015-11-18 13:21:35 -08005567 if (mAttachInfo.mDragSurface != null) {
5568 mAttachInfo.mDragSurface.release();
5569 mAttachInfo.mDragSurface = null;
5570 }
Christopher Tate407b4e92010-11-30 17:14:08 -08005571 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005572 }
5573 }
5574 event.recycle();
5575 }
5576
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005577 public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
5578 if (mSeq != args.seq) {
5579 // The sequence has changed, so we need to update our value and make
5580 // sure to do a traversal afterward so the window manager is given our
5581 // most recent data.
5582 mSeq = args.seq;
5583 mAttachInfo.mForceReportNewAttributes = true;
Igor Murashkina86ab6402013-08-30 12:58:36 -07005584 scheduleTraversals();
Joe Onorato14782f72011-01-25 19:53:17 -08005585 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005586 if (mView == null) return;
5587 if (args.localChanges != 0) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005588 mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005589 }
Chris Craikd36a81f2014-07-17 10:16:51 -07005590
5591 int visibility = args.globalVisibility&View.SYSTEM_UI_CLEARABLE_FLAGS;
5592 if (visibility != mAttachInfo.mGlobalSystemUiVisibility) {
5593 mAttachInfo.mGlobalSystemUiVisibility = visibility;
5594 mView.dispatchSystemUiVisibilityChanged(visibility);
Dianne Hackborncf675782012-05-10 15:07:24 -07005595 }
Joe Onorato664644d2011-01-23 17:53:23 -08005596 }
5597
Craig Mautner9c795042014-10-28 19:59:59 -07005598 public void handleDispatchWindowShown() {
5599 mAttachInfo.mTreeObserver.dispatchOnWindowShown();
5600 }
5601
Clara Bayarrifcd7e802016-03-10 12:58:18 +00005602 public void handleRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
Clara Bayarri75e09792015-07-29 16:20:40 +01005603 Bundle data = new Bundle();
5604 ArrayList<KeyboardShortcutGroup> list = new ArrayList<>();
5605 if (mView != null) {
Clara Bayarrifcd7e802016-03-10 12:58:18 +00005606 mView.requestKeyboardShortcuts(list, deviceId);
Clara Bayarri75e09792015-07-29 16:20:40 +01005607 }
5608 data.putParcelableArrayList(WindowManager.PARCEL_KEY_SHORTCUTS_ARRAY, list);
5609 try {
5610 receiver.send(0, data);
5611 } catch (RemoteException e) {
5612 }
5613 }
5614
Christopher Tate2c095f32010-10-04 14:13:40 -07005615 public void getLastTouchPoint(Point outLocation) {
5616 outLocation.x = (int) mLastTouchPoint.x;
5617 outLocation.y = (int) mLastTouchPoint.y;
5618 }
5619
Vladislav Kaznacheevba761122016-01-22 12:09:45 -08005620 public int getLastTouchSource() {
5621 return mLastTouchSource;
5622 }
5623
Chris Tate9d1ab882010-11-02 15:55:39 -07005624 public void setDragFocus(View newDragTarget) {
Christopher Tatea53146c2010-09-07 11:57:52 -07005625 if (mCurrentDragView != newDragTarget) {
Chris Tate048691c2010-10-12 17:39:18 -07005626 mCurrentDragView = newDragTarget;
Christopher Tatea53146c2010-09-07 11:57:52 -07005627 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005628 }
5629
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005630 private AudioManager getAudioManager() {
5631 if (mView == null) {
5632 throw new IllegalStateException("getAudioManager called when there is no mView");
5633 }
5634 if (mAudioManager == null) {
5635 mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
5636 }
5637 return mAudioManager;
5638 }
5639
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005640 public AccessibilityInteractionController getAccessibilityInteractionController() {
5641 if (mView == null) {
5642 throw new IllegalStateException("getAccessibilityInteractionController"
5643 + " called when there is no mView");
5644 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07005645 if (mAccessibilityInteractionController == null) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005646 mAccessibilityInteractionController = new AccessibilityInteractionController(this);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005647 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07005648 return mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005649 }
5650
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07005651 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
5652 boolean insetsPending) throws RemoteException {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005653
5654 float appScale = mAttachInfo.mApplicationScale;
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005655 boolean restore = false;
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005656 if (params != null && mTranslator != null) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005657 restore = true;
5658 params.backup();
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005659 mTranslator.translateWindowLayout(params);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005660 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005661 if (params != null) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005662 if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005663 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07005664 mPendingConfiguration.seq = 0;
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005665 //Log.d(mTag, ">>>>>> CALLING relayout");
Dianne Hackborn180c4842011-09-13 12:39:25 -07005666 if (params != null && mOrigWindowType != params.type) {
5667 // For compatibility with old apps, don't crash here.
Michael Wright5bd69e62015-05-14 14:48:08 +01005668 if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005669 Slog.w(mTag, "Window type can not be changed after "
Dianne Hackborn180c4842011-09-13 12:39:25 -07005670 + "the window is added; ignoring change of " + mView);
5671 params.type = mOrigWindowType;
5672 }
5673 }
Jeff Brown98365d72012-08-19 20:30:52 -07005674 int relayoutResult = mWindowSession.relayout(
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005675 mWindow, mSeq, params,
Dianne Hackborn189ee182010-12-02 21:48:53 -08005676 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
5677 (int) (mView.getMeasuredHeight() * appScale + 0.5f),
Jeff Brown98365d72012-08-19 20:30:52 -07005678 viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005679 mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
Jorim Jaggi2e95a482016-01-14 17:36:55 -08005680 mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration,
5681 mSurface);
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08005682
5683 mPendingAlwaysConsumeNavBar =
5684 (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR) != 0;
5685
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005686 //Log.d(mTag, "<<<<<< BACK FROM relayout");
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005687 if (restore) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005688 params.restore();
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005689 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07005690
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005691 if (mTranslator != null) {
5692 mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005693 mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005694 mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
5695 mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
Adrian Roosfa104232014-06-20 16:10:14 -07005696 mTranslator.translateRectInScreenToAppWindow(mPendingStableInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005697 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07005698 return relayoutResult;
5699 }
Romain Guy8506ab42009-06-11 17:35:47 -07005700
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005701 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005702 * {@inheritDoc}
5703 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005704 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005705 public void playSoundEffect(int effectId) {
5706 checkThread();
5707
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005708 try {
5709 final AudioManager audioManager = getAudioManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005710
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005711 switch (effectId) {
5712 case SoundEffectConstants.CLICK:
5713 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
5714 return;
5715 case SoundEffectConstants.NAVIGATION_DOWN:
5716 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
5717 return;
5718 case SoundEffectConstants.NAVIGATION_LEFT:
5719 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
5720 return;
5721 case SoundEffectConstants.NAVIGATION_RIGHT:
5722 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
5723 return;
5724 case SoundEffectConstants.NAVIGATION_UP:
5725 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
5726 return;
5727 default:
5728 throw new IllegalArgumentException("unknown effect id " + effectId +
5729 " not defined in " + SoundEffectConstants.class.getCanonicalName());
5730 }
5731 } catch (IllegalStateException e) {
5732 // Exception thrown by getAudioManager() when mView is null
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005733 Log.e(mTag, "FATAL EXCEPTION when attempting to play sound effect: " + e);
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005734 e.printStackTrace();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005735 }
5736 }
5737
5738 /**
5739 * {@inheritDoc}
5740 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005741 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005742 public boolean performHapticFeedback(int effectId, boolean always) {
5743 try {
Jeff Brown98365d72012-08-19 20:30:52 -07005744 return mWindowSession.performHapticFeedback(mWindow, effectId, always);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005745 } catch (RemoteException e) {
5746 return false;
5747 }
5748 }
5749
5750 /**
5751 * {@inheritDoc}
5752 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005753 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005754 public View focusSearch(View focused, int direction) {
5755 checkThread();
5756 if (!(mView instanceof ViewGroup)) {
5757 return null;
5758 }
5759 return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
5760 }
5761
5762 public void debug() {
5763 mView.debug();
5764 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07005765
Jeff Brown5182c782013-10-15 20:31:52 -07005766 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
5767 String innerPrefix = prefix + " ";
5768 writer.print(prefix); writer.println("ViewRoot:");
5769 writer.print(innerPrefix); writer.print("mAdded="); writer.print(mAdded);
5770 writer.print(" mRemoved="); writer.println(mRemoved);
5771 writer.print(innerPrefix); writer.print("mConsumeBatchedInputScheduled=");
5772 writer.println(mConsumeBatchedInputScheduled);
Michael Wright9d744c72014-02-18 21:27:42 -08005773 writer.print(innerPrefix); writer.print("mConsumeBatchedInputImmediatelyScheduled=");
5774 writer.println(mConsumeBatchedInputImmediatelyScheduled);
Jeff Brown5182c782013-10-15 20:31:52 -07005775 writer.print(innerPrefix); writer.print("mPendingInputEventCount=");
5776 writer.println(mPendingInputEventCount);
5777 writer.print(innerPrefix); writer.print("mProcessInputEventsScheduled=");
5778 writer.println(mProcessInputEventsScheduled);
5779 writer.print(innerPrefix); writer.print("mTraversalScheduled=");
5780 writer.print(mTraversalScheduled);
Daniel Koulomzin087ae472015-12-16 17:52:25 -05005781 writer.print(innerPrefix); writer.print("mIsAmbientMode=");
5782 writer.print(mIsAmbientMode);
Jeff Brown5182c782013-10-15 20:31:52 -07005783 if (mTraversalScheduled) {
5784 writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
5785 } else {
5786 writer.println();
5787 }
5788 mFirstInputStage.dump(innerPrefix, writer);
5789
5790 mChoreographer.dump(prefix, writer);
5791
5792 writer.print(prefix); writer.println("View Hierarchy:");
5793 dumpViewHierarchy(innerPrefix, writer, mView);
5794 }
5795
5796 private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) {
5797 writer.print(prefix);
5798 if (view == null) {
5799 writer.println("null");
5800 return;
5801 }
5802 writer.println(view.toString());
5803 if (!(view instanceof ViewGroup)) {
5804 return;
5805 }
5806 ViewGroup grp = (ViewGroup)view;
5807 final int N = grp.getChildCount();
5808 if (N <= 0) {
5809 return;
5810 }
5811 prefix = prefix + " ";
5812 for (int i=0; i<N; i++) {
5813 dumpViewHierarchy(prefix, writer, grp.getChildAt(i));
5814 }
5815 }
5816
Romain Guy211370f2012-02-01 16:10:55 -08005817 public void dumpGfxInfo(int[] info) {
Romain Guy54ab3472012-06-14 12:52:53 -07005818 info[0] = info[1] = 0;
Romain Guy65b345f2011-07-27 18:51:50 -07005819 if (mView != null) {
5820 getGfxInfo(mView, info);
Romain Guy65b345f2011-07-27 18:51:50 -07005821 }
5822 }
5823
Romain Guya998dff2012-03-23 18:58:36 -07005824 private static void getGfxInfo(View view, int[] info) {
Chris Craik64a12e12014-03-28 18:12:12 -07005825 RenderNode renderNode = view.mRenderNode;
Romain Guy65b345f2011-07-27 18:51:50 -07005826 info[0]++;
Chris Craik64a12e12014-03-28 18:12:12 -07005827 if (renderNode != null) {
John Reckfe5e7b72014-05-23 17:42:28 -07005828 info[1] += renderNode.getDebugSize();
Romain Guy65b345f2011-07-27 18:51:50 -07005829 }
5830
5831 if (view instanceof ViewGroup) {
5832 ViewGroup group = (ViewGroup) view;
5833
5834 int count = group.getChildCount();
5835 for (int i = 0; i < count; i++) {
5836 getGfxInfo(group.getChildAt(i), info);
5837 }
5838 }
5839 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005840
Craig Mautner8f303ad2013-06-14 11:32:22 -07005841 /**
5842 * @param immediate True, do now if not in traversal. False, put on queue and do later.
5843 * @return True, request has been queued. False, request has been completed.
5844 */
5845 boolean die(boolean immediate) {
Craig Mautnerdf2390a2012-08-29 20:59:22 -07005846 // Make sure we do execute immediately if we are in the middle of a traversal or the damage
5847 // done by dispatchDetachedFromWindow will cause havoc on return.
5848 if (immediate && !mIsInTraversal) {
Dianne Hackborn94d69142009-09-28 22:14:42 -07005849 doDie();
Craig Mautner8f303ad2013-06-14 11:32:22 -07005850 return false;
Dianne Hackborn94d69142009-09-28 22:14:42 -07005851 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07005852
5853 if (!mIsDrawing) {
5854 destroyHardwareRenderer();
5855 } else {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005856 Log.e(mTag, "Attempting to destroy the window while drawing!\n" +
Craig Mautner8f303ad2013-06-14 11:32:22 -07005857 " window=" + this + ", title=" + mWindowAttributes.getTitle());
5858 }
5859 mHandler.sendEmptyMessage(MSG_DIE);
5860 return true;
Dianne Hackborn94d69142009-09-28 22:14:42 -07005861 }
5862
5863 void doDie() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005864 checkThread();
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005865 if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005866 synchronized (this) {
Craig Mautner8f303ad2013-06-14 11:32:22 -07005867 if (mRemoved) {
5868 return;
5869 }
5870 mRemoved = true;
Romain Guy16260e72011-09-01 14:26:11 -07005871 if (mAdded) {
Romain Guy16260e72011-09-01 14:26:11 -07005872 dispatchDetachedFromWindow();
5873 }
5874
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005875 if (mAdded && !mFirst) {
Romain Guy29d89972010-09-22 16:10:57 -07005876 destroyHardwareRenderer();
5877
Romain Guyedbca122012-04-04 18:25:53 -07005878 if (mView != null) {
5879 int viewVisibility = mView.getVisibility();
5880 boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
5881 if (mWindowAttributesChanged || viewVisibilityChanged) {
5882 // If layout params have been changed, first give them
5883 // to the window manager to make sure it has the correct
5884 // animation info.
5885 try {
5886 if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
Jeff Brown98365d72012-08-19 20:30:52 -07005887 & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
5888 mWindowSession.finishDrawing(mWindow);
Romain Guyedbca122012-04-04 18:25:53 -07005889 }
5890 } catch (RemoteException e) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005891 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005892 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07005893
Romain Guyedbca122012-04-04 18:25:53 -07005894 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005895 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005896 }
Romain Guyedbca122012-04-04 18:25:53 -07005897
5898 mAdded = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005899 }
Craig Mautner05eb7302013-06-03 17:24:21 -07005900 WindowManagerGlobal.getInstance().doRemoveView(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005901 }
5902
Dianne Hackborn5fd21692011-06-07 14:09:47 -07005903 public void requestUpdateConfiguration(Configuration config) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005904 Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
5905 mHandler.sendMessage(msg);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07005906 }
5907
Dianne Hackborna53de062012-05-08 18:53:51 -07005908 public void loadSystemProperties() {
Romain Guy5bb3c732012-11-29 17:52:58 -08005909 mHandler.post(new Runnable() {
5910 @Override
5911 public void run() {
5912 // Profiling
5913 mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false);
5914 profileRendering(mAttachInfo.mHasWindowFocus);
5915
5916 // Hardware rendering
5917 if (mAttachInfo.mHardwareRenderer != null) {
John Reckcec24ae2013-11-05 13:27:50 -08005918 if (mAttachInfo.mHardwareRenderer.loadSystemProperties()) {
Romain Guy5bb3c732012-11-29 17:52:58 -08005919 invalidate();
5920 }
5921 }
5922
5923 // Layout debugging
5924 boolean layout = SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false);
5925 if (layout != mAttachInfo.mDebugLayout) {
5926 mAttachInfo.mDebugLayout = layout;
5927 if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
5928 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
5929 }
5930 }
Dianne Hackborna53de062012-05-08 18:53:51 -07005931 }
Romain Guy5bb3c732012-11-29 17:52:58 -08005932 });
Dianne Hackborna53de062012-05-08 18:53:51 -07005933 }
5934
Romain Guy29d89972010-09-22 16:10:57 -07005935 private void destroyHardwareRenderer() {
John Reck51aaf902015-12-02 15:08:07 -08005936 ThreadedRenderer hardwareRenderer = mAttachInfo.mHardwareRenderer;
Romain Guya998dff2012-03-23 18:58:36 -07005937
5938 if (hardwareRenderer != null) {
5939 if (mView != null) {
5940 hardwareRenderer.destroyHardwareResources(mView);
5941 }
John Reckf47a5942014-06-30 16:20:04 -07005942 hardwareRenderer.destroy();
Romain Guya998dff2012-03-23 18:58:36 -07005943 hardwareRenderer.setRequested(false);
5944
Chris Craikd36a81f2014-07-17 10:16:51 -07005945 mAttachInfo.mHardwareRenderer = null;
5946 mAttachInfo.mHardwareAccelerated = false;
Romain Guy29d89972010-09-22 16:10:57 -07005947 }
5948 }
5949
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005950 public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Filip Gruszczynski2217f612015-05-26 11:32:08 -07005951 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08005952 Configuration newConfig, Rect backDropFrame, boolean forceLayout,
5953 boolean alwaysConsumeNavBar) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005954 if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005955 + " contentInsets=" + contentInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005956 + " visibleInsets=" + visibleInsets.toShortString()
Chong Zhangd153c4f2015-11-06 20:26:40 -08005957 + " reportDraw=" + reportDraw
5958 + " backDropFrame=" + backDropFrame);
Chong Zhangdcee1de2015-10-06 10:26:00 -07005959
5960 // Tell all listeners that we are resizing the window so that the chrome can get
5961 // updated as fast as possible on a separate thread,
5962 if (mDragResizing) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08005963 boolean fullscreen = frame.equals(backDropFrame);
Chong Zhangdcee1de2015-10-06 10:26:00 -07005964 synchronized (mWindowCallbacks) {
5965 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08005966 mWindowCallbacks.get(i).onWindowSizeIsChanging(backDropFrame, fullscreen,
5967 visibleInsets, stableInsets);
Chong Zhangdcee1de2015-10-06 10:26:00 -07005968 }
5969 }
5970 }
5971
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005972 Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005973 if (mTranslator != null) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005974 mTranslator.translateRectInScreenToAppWindow(frame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005975 mTranslator.translateRectInScreenToAppWindow(overscanInsets);
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07005976 mTranslator.translateRectInScreenToAppWindow(contentInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005977 mTranslator.translateRectInScreenToAppWindow(visibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005978 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005979 SomeArgs args = SomeArgs.obtain();
5980 final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
5981 args.arg1 = sameProcessCall ? new Rect(frame) : frame;
5982 args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets;
5983 args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
5984 args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005985 args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
Adrian Roosfa104232014-06-20 16:10:14 -07005986 args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
Filip Gruszczynski2217f612015-05-26 11:32:08 -07005987 args.arg7 = sameProcessCall ? new Rect(outsets) : outsets;
Jorim Jaggia7262a82015-11-03 15:15:40 +01005988 args.arg8 = sameProcessCall ? new Rect(backDropFrame) : backDropFrame;
Jorim Jaggia4a58ef2016-01-27 02:10:08 -08005989 args.argi1 = forceLayout ? 1 : 0;
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08005990 args.argi2 = alwaysConsumeNavBar ? 1 : 0;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005991 msg.obj = args;
Jeff Browna175a5b2012-02-15 19:18:31 -08005992 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005993 }
Chet Haase1f4786b2011-11-02 10:51:52 -07005994
Craig Mautner5702d4d2012-06-30 14:10:16 -07005995 public void dispatchMoved(int newX, int newY) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08005996 if (DEBUG_LAYOUT) Log.v(mTag, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
Craig Mautner5702d4d2012-06-30 14:10:16 -07005997 if (mTranslator != null) {
5998 PointF point = new PointF(newX, newY);
5999 mTranslator.translatePointInScreenToAppWindow(point);
6000 newX = (int) (point.x + 0.5);
6001 newY = (int) (point.y + 0.5);
6002 }
6003 Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY);
6004 mHandler.sendMessage(msg);
6005 }
6006
Jeff Brown4952dfd2011-11-30 19:23:22 -08006007 /**
6008 * Represents a pending input event that is waiting in a queue.
6009 *
6010 * Input events are processed in serial order by the timestamp specified by
Romain Guy211370f2012-02-01 16:10:55 -08006011 * {@link InputEvent#getEventTimeNano()}. In general, the input dispatcher delivers
Jeff Brown4952dfd2011-11-30 19:23:22 -08006012 * one input event to the application at a time and waits for the application
6013 * to finish handling it before delivering the next one.
6014 *
6015 * However, because the application or IME can synthesize and inject multiple
6016 * key events at a time without going through the input dispatcher, we end up
6017 * needing a queue on the application's side.
6018 */
6019 private static final class QueuedInputEvent {
Jeff Brownf9e989d2013-04-04 23:04:03 -07006020 public static final int FLAG_DELIVER_POST_IME = 1 << 0;
6021 public static final int FLAG_DEFERRED = 1 << 1;
6022 public static final int FLAG_FINISHED = 1 << 2;
6023 public static final int FLAG_FINISHED_HANDLED = 1 << 3;
6024 public static final int FLAG_RESYNTHESIZED = 1 << 4;
Michael Wright899d7052014-04-23 17:23:39 -07006025 public static final int FLAG_UNHANDLED = 1 << 5;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006026
6027 public QueuedInputEvent mNext;
6028
6029 public InputEvent mEvent;
Jeff Brown32cbc38552011-12-01 14:01:49 -08006030 public InputEventReceiver mReceiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006031 public int mFlags;
Jeff Brownf9e989d2013-04-04 23:04:03 -07006032
6033 public boolean shouldSkipIme() {
6034 if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
6035 return true;
6036 }
6037 return mEvent instanceof MotionEvent
6038 && mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER);
6039 }
Michael Wright899d7052014-04-23 17:23:39 -07006040
6041 public boolean shouldSendToSynthesizer() {
6042 if ((mFlags & FLAG_UNHANDLED) != 0) {
6043 return true;
6044 }
6045
6046 return false;
6047 }
Michael Wright06a79252014-05-05 17:45:29 -07006048
6049 @Override
6050 public String toString() {
6051 StringBuilder sb = new StringBuilder("QueuedInputEvent{flags=");
6052 boolean hasPrevious = false;
6053 hasPrevious = flagToString("DELIVER_POST_IME", FLAG_DELIVER_POST_IME, hasPrevious, sb);
6054 hasPrevious = flagToString("DEFERRED", FLAG_DEFERRED, hasPrevious, sb);
6055 hasPrevious = flagToString("FINISHED", FLAG_FINISHED, hasPrevious, sb);
6056 hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb);
6057 hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb);
6058 hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb);
6059 if (!hasPrevious) {
6060 sb.append("0");
6061 }
6062 sb.append(", hasNextQueuedEvent=" + (mEvent != null ? "true" : "false"));
6063 sb.append(", hasInputEventReceiver=" + (mReceiver != null ? "true" : "false"));
6064 sb.append(", mEvent=" + mEvent + "}");
6065 return sb.toString();
6066 }
6067
6068 private boolean flagToString(String name, int flag,
6069 boolean hasPrevious, StringBuilder sb) {
6070 if ((mFlags & flag) != 0) {
6071 if (hasPrevious) {
6072 sb.append("|");
6073 }
6074 sb.append(name);
6075 return true;
6076 }
6077 return hasPrevious;
6078 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08006079 }
6080
6081 private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
Jeff Brown32cbc38552011-12-01 14:01:49 -08006082 InputEventReceiver receiver, int flags) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08006083 QueuedInputEvent q = mQueuedInputEventPool;
6084 if (q != null) {
6085 mQueuedInputEventPoolSize -= 1;
6086 mQueuedInputEventPool = q.mNext;
6087 q.mNext = null;
6088 } else {
6089 q = new QueuedInputEvent();
Jeff Brown46b9ac02010-04-22 18:58:52 -07006090 }
6091
Jeff Brown4952dfd2011-11-30 19:23:22 -08006092 q.mEvent = event;
Jeff Brown32cbc38552011-12-01 14:01:49 -08006093 q.mReceiver = receiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006094 q.mFlags = flags;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006095 return q;
6096 }
6097
6098 private void recycleQueuedInputEvent(QueuedInputEvent q) {
6099 q.mEvent = null;
Jeff Brown32cbc38552011-12-01 14:01:49 -08006100 q.mReceiver = null;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006101
6102 if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
6103 mQueuedInputEventPoolSize += 1;
6104 q.mNext = mQueuedInputEventPool;
6105 mQueuedInputEventPool = q;
6106 }
6107 }
6108
Jeff Brownf9261d22012-02-03 13:49:15 -08006109 void enqueueInputEvent(InputEvent event) {
6110 enqueueInputEvent(event, null, 0, false);
6111 }
6112
Jeff Brown4952dfd2011-11-30 19:23:22 -08006113 void enqueueInputEvent(InputEvent event,
Jeff Brownf9261d22012-02-03 13:49:15 -08006114 InputEventReceiver receiver, int flags, boolean processImmediately) {
Michael Wright5bd69e62015-05-14 14:48:08 +01006115 adjustInputEventForCompatibility(event);
Jeff Brown32cbc38552011-12-01 14:01:49 -08006116 QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
Jeff Brown4952dfd2011-11-30 19:23:22 -08006117
Jeff Brown4952dfd2011-11-30 19:23:22 -08006118 // Always enqueue the input event in order, regardless of its time stamp.
6119 // We do this because the application or the IME may inject key events
6120 // in response to touch events and we want to ensure that the injected keys
6121 // are processed in the order they were received and we cannot trust that
6122 // the time stamp of injected events are monotonic.
Michael Wrightc8a7e542013-03-20 17:58:33 -07006123 QueuedInputEvent last = mPendingInputEventTail;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006124 if (last == null) {
Michael Wrightc8a7e542013-03-20 17:58:33 -07006125 mPendingInputEventHead = q;
6126 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006127 } else {
Jeff Brown4952dfd2011-11-30 19:23:22 -08006128 last.mNext = q;
Michael Wrightc8a7e542013-03-20 17:58:33 -07006129 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006130 }
Michael Wright95ae9422013-03-14 10:58:50 -07006131 mPendingInputEventCount += 1;
6132 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
6133 mPendingInputEventCount);
Jeff Brown4952dfd2011-11-30 19:23:22 -08006134
Jeff Brownf9261d22012-02-03 13:49:15 -08006135 if (processImmediately) {
6136 doProcessInputEvents();
6137 } else {
6138 scheduleProcessInputEvents();
6139 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08006140 }
6141
6142 private void scheduleProcessInputEvents() {
Jeff Brown96e942d2011-11-30 19:55:01 -08006143 if (!mProcessInputEventsScheduled) {
6144 mProcessInputEventsScheduled = true;
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006145 Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
6146 msg.setAsynchronous(true);
6147 mHandler.sendMessage(msg);
Jeff Brown4952dfd2011-11-30 19:23:22 -08006148 }
6149 }
6150
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006151 void doProcessInputEvents() {
Jeff Brownf9e989d2013-04-04 23:04:03 -07006152 // Deliver all pending input events in the queue.
Michael Wrightc8a7e542013-03-20 17:58:33 -07006153 while (mPendingInputEventHead != null) {
6154 QueuedInputEvent q = mPendingInputEventHead;
6155 mPendingInputEventHead = q.mNext;
6156 if (mPendingInputEventHead == null) {
6157 mPendingInputEventTail = null;
6158 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08006159 q.mNext = null;
Jeff Brown29c0ed22013-01-14 13:50:37 -08006160
Michael Wright95ae9422013-03-14 10:58:50 -07006161 mPendingInputEventCount -= 1;
6162 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
6163 mPendingInputEventCount);
6164
John Reckba6adf62015-02-19 14:36:50 -08006165 long eventTime = q.mEvent.getEventTimeNano();
6166 long oldestEventTime = eventTime;
6167 if (q.mEvent instanceof MotionEvent) {
6168 MotionEvent me = (MotionEvent)q.mEvent;
6169 if (me.getHistorySize() > 0) {
6170 oldestEventTime = me.getHistoricalEventTimeNano(0);
6171 }
6172 }
6173 mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
6174
Jeff Brownf9e989d2013-04-04 23:04:03 -07006175 deliverInputEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08006176 }
6177
6178 // We are done processing all input events that we can process right now
6179 // so we can clear the pending flag immediately.
Jeff Brown96e942d2011-11-30 19:55:01 -08006180 if (mProcessInputEventsScheduled) {
6181 mProcessInputEventsScheduled = false;
Jeff Browna175a5b2012-02-15 19:18:31 -08006182 mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
Jeff Brown4952dfd2011-11-30 19:23:22 -08006183 }
6184 }
6185
Jeff Brownf9e989d2013-04-04 23:04:03 -07006186 private void deliverInputEvent(QueuedInputEvent q) {
Michael Wrightd2c3adc2014-02-18 22:50:50 -08006187 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
6188 q.mEvent.getSequenceNumber());
6189 if (mInputEventConsistencyVerifier != null) {
6190 mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
6191 }
Michael Wrightc8a7e542013-03-20 17:58:33 -07006192
Michael Wright899d7052014-04-23 17:23:39 -07006193 InputStage stage;
6194 if (q.shouldSendToSynthesizer()) {
6195 stage = mSyntheticInputStage;
6196 } else {
6197 stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
6198 }
6199
Michael Wrightd2c3adc2014-02-18 22:50:50 -08006200 if (stage != null) {
6201 stage.deliver(q);
6202 } else {
6203 finishInputEvent(q);
Michael Wrightbf020962013-03-28 17:27:50 -07006204 }
Michael Wrightbf020962013-03-28 17:27:50 -07006205 }
6206
Jeff Brownf9e989d2013-04-04 23:04:03 -07006207 private void finishInputEvent(QueuedInputEvent q) {
Michael Wrightd2c3adc2014-02-18 22:50:50 -08006208 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
6209 q.mEvent.getSequenceNumber());
Michael Wright9d744c72014-02-18 21:27:42 -08006210
Jeff Brown32cbc38552011-12-01 14:01:49 -08006211 if (q.mReceiver != null) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07006212 boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
Jeff Brown32cbc38552011-12-01 14:01:49 -08006213 q.mReceiver.finishInputEvent(q.mEvent, handled);
Jeff Brown92cc2d82011-12-02 01:19:47 -08006214 } else {
6215 q.mEvent.recycleIfNeededAfterDispatch();
Jeff Brown4952dfd2011-11-30 19:23:22 -08006216 }
6217
6218 recycleQueuedInputEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08006219 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08006220
Michael Wright5bd69e62015-05-14 14:48:08 +01006221 private void adjustInputEventForCompatibility(InputEvent e) {
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07006222 if (mTargetSdkVersion < Build.VERSION_CODES.M && e instanceof MotionEvent) {
Michael Wright5bd69e62015-05-14 14:48:08 +01006223 MotionEvent motion = (MotionEvent) e;
6224 final int mask =
6225 MotionEvent.BUTTON_STYLUS_PRIMARY | MotionEvent.BUTTON_STYLUS_SECONDARY;
6226 final int buttonState = motion.getButtonState();
6227 final int compatButtonState = (buttonState & mask) >> 4;
6228 if (compatButtonState != 0) {
6229 motion.setButtonState(buttonState | compatButtonState);
6230 }
6231 }
6232 }
6233
Jeff Brownf9e989d2013-04-04 23:04:03 -07006234 static boolean isTerminalInputEvent(InputEvent event) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08006235 if (event instanceof KeyEvent) {
6236 final KeyEvent keyEvent = (KeyEvent)event;
6237 return keyEvent.getAction() == KeyEvent.ACTION_UP;
6238 } else {
6239 final MotionEvent motionEvent = (MotionEvent)event;
6240 final int action = motionEvent.getAction();
6241 return action == MotionEvent.ACTION_UP
6242 || action == MotionEvent.ACTION_CANCEL
6243 || action == MotionEvent.ACTION_HOVER_EXIT;
Jeff Brown4952dfd2011-11-30 19:23:22 -08006244 }
6245 }
6246
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006247 void scheduleConsumeBatchedInput() {
6248 if (!mConsumeBatchedInputScheduled) {
6249 mConsumeBatchedInputScheduled = true;
6250 mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
6251 mConsumedBatchedInputRunnable, null);
Jeff Brown4a06c802012-02-15 15:06:01 -08006252 }
6253 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006254
6255 void unscheduleConsumeBatchedInput() {
6256 if (mConsumeBatchedInputScheduled) {
6257 mConsumeBatchedInputScheduled = false;
6258 mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT,
6259 mConsumedBatchedInputRunnable, null);
6260 }
6261 }
6262
Michael Wright9d744c72014-02-18 21:27:42 -08006263 void scheduleConsumeBatchedInputImmediately() {
6264 if (!mConsumeBatchedInputImmediatelyScheduled) {
6265 unscheduleConsumeBatchedInput();
6266 mConsumeBatchedInputImmediatelyScheduled = true;
6267 mHandler.post(mConsumeBatchedInputImmediatelyRunnable);
6268 }
6269 }
6270
Jeff Brown771526c2012-04-27 15:13:25 -07006271 void doConsumeBatchedInput(long frameTimeNanos) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006272 if (mConsumeBatchedInputScheduled) {
6273 mConsumeBatchedInputScheduled = false;
Jeff Brown330314c2012-04-27 02:20:22 -07006274 if (mInputEventReceiver != null) {
Michael Wright9d744c72014-02-18 21:27:42 -08006275 if (mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos)
6276 && frameTimeNanos != -1) {
Michael Wright62ce65d2013-10-25 14:50:36 -07006277 // If we consumed a batch here, we want to go ahead and schedule the
6278 // consumption of batched input events on the next frame. Otherwise, we would
6279 // wait until we have more input events pending and might get starved by other
Michael Wright9d744c72014-02-18 21:27:42 -08006280 // things occurring in the process. If the frame time is -1, however, then
6281 // we're in a non-batching mode, so there's no need to schedule this.
Michael Wright62ce65d2013-10-25 14:50:36 -07006282 scheduleConsumeBatchedInput();
6283 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006284 }
Jeff Brown330314c2012-04-27 02:20:22 -07006285 doProcessInputEvents();
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006286 }
6287 }
6288
6289 final class TraversalRunnable implements Runnable {
6290 @Override
6291 public void run() {
6292 doTraversal();
6293 }
6294 }
6295 final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
Jeff Brown4a06c802012-02-15 15:06:01 -08006296
Jeff Brown32cbc38552011-12-01 14:01:49 -08006297 final class WindowInputEventReceiver extends InputEventReceiver {
6298 public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
6299 super(inputChannel, looper);
Jeff Brown46b9ac02010-04-22 18:58:52 -07006300 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08006301
6302 @Override
6303 public void onInputEvent(InputEvent event) {
Jeff Brownf9261d22012-02-03 13:49:15 -08006304 enqueueInputEvent(event, this, 0, true);
Jeff Brown32cbc38552011-12-01 14:01:49 -08006305 }
Jeff Brown072ec962012-02-07 14:46:57 -08006306
6307 @Override
6308 public void onBatchedInputEventPending() {
Michael Wright9d744c72014-02-18 21:27:42 -08006309 if (mUnbufferedInputDispatch) {
6310 super.onBatchedInputEventPending();
6311 } else {
6312 scheduleConsumeBatchedInput();
6313 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006314 }
6315
6316 @Override
6317 public void dispose() {
6318 unscheduleConsumeBatchedInput();
6319 super.dispose();
Jeff Brown072ec962012-02-07 14:46:57 -08006320 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08006321 }
6322 WindowInputEventReceiver mInputEventReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006323
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006324 final class ConsumeBatchedInputRunnable implements Runnable {
6325 @Override
6326 public void run() {
Jeff Brown771526c2012-04-27 15:13:25 -07006327 doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006328 }
6329 }
6330 final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =
6331 new ConsumeBatchedInputRunnable();
6332 boolean mConsumeBatchedInputScheduled;
6333
Michael Wright9d744c72014-02-18 21:27:42 -08006334 final class ConsumeBatchedInputImmediatelyRunnable implements Runnable {
6335 @Override
6336 public void run() {
6337 doConsumeBatchedInput(-1);
6338 }
6339 }
6340 final ConsumeBatchedInputImmediatelyRunnable mConsumeBatchedInputImmediatelyRunnable =
6341 new ConsumeBatchedInputImmediatelyRunnable();
6342 boolean mConsumeBatchedInputImmediatelyScheduled;
6343
Jeff Brown6cb7b462012-03-05 13:21:17 -08006344 final class InvalidateOnAnimationRunnable implements Runnable {
6345 private boolean mPosted;
Igor Murashkina86ab6402013-08-30 12:58:36 -07006346 private final ArrayList<View> mViews = new ArrayList<View>();
6347 private final ArrayList<AttachInfo.InvalidateInfo> mViewRects =
Jeff Brown6cb7b462012-03-05 13:21:17 -08006348 new ArrayList<AttachInfo.InvalidateInfo>();
6349 private View[] mTempViews;
6350 private AttachInfo.InvalidateInfo[] mTempViewRects;
6351
6352 public void addView(View view) {
6353 synchronized (this) {
6354 mViews.add(view);
6355 postIfNeededLocked();
6356 }
6357 }
6358
6359 public void addViewRect(AttachInfo.InvalidateInfo info) {
6360 synchronized (this) {
6361 mViewRects.add(info);
6362 postIfNeededLocked();
6363 }
6364 }
6365
6366 public void removeView(View view) {
6367 synchronized (this) {
6368 mViews.remove(view);
6369
6370 for (int i = mViewRects.size(); i-- > 0; ) {
6371 AttachInfo.InvalidateInfo info = mViewRects.get(i);
6372 if (info.target == view) {
6373 mViewRects.remove(i);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08006374 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08006375 }
6376 }
6377
6378 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006379 mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08006380 mPosted = false;
6381 }
6382 }
6383 }
6384
6385 @Override
6386 public void run() {
6387 final int viewCount;
6388 final int viewRectCount;
6389 synchronized (this) {
6390 mPosted = false;
6391
6392 viewCount = mViews.size();
6393 if (viewCount != 0) {
6394 mTempViews = mViews.toArray(mTempViews != null
6395 ? mTempViews : new View[viewCount]);
6396 mViews.clear();
6397 }
6398
6399 viewRectCount = mViewRects.size();
6400 if (viewRectCount != 0) {
6401 mTempViewRects = mViewRects.toArray(mTempViewRects != null
6402 ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]);
6403 mViewRects.clear();
6404 }
6405 }
6406
6407 for (int i = 0; i < viewCount; i++) {
6408 mTempViews[i].invalidate();
Adam Powell3e3c4ee2012-05-16 17:34:21 -07006409 mTempViews[i] = null;
Jeff Brown6cb7b462012-03-05 13:21:17 -08006410 }
6411
6412 for (int i = 0; i < viewRectCount; i++) {
6413 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
6414 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08006415 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08006416 }
6417 }
6418
6419 private void postIfNeededLocked() {
6420 if (!mPosted) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006421 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08006422 mPosted = true;
6423 }
6424 }
6425 }
6426 final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
6427 new InvalidateOnAnimationRunnable();
6428
Jeff Browna175a5b2012-02-15 19:18:31 -08006429 public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
6430 Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
6431 mHandler.sendMessageDelayed(msg, delayMilliseconds);
6432 }
6433
Jeff Browna175a5b2012-02-15 19:18:31 -08006434 public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
6435 long delayMilliseconds) {
6436 final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
6437 mHandler.sendMessageDelayed(msg, delayMilliseconds);
6438 }
6439
Jeff Brown6cb7b462012-03-05 13:21:17 -08006440 public void dispatchInvalidateOnAnimation(View view) {
6441 mInvalidateOnAnimationRunnable.addView(view);
6442 }
6443
6444 public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) {
6445 mInvalidateOnAnimationRunnable.addViewRect(info);
6446 }
6447
6448 public void cancelInvalidate(View view) {
6449 mHandler.removeMessages(MSG_INVALIDATE, view);
6450 // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning
6451 // them to the pool
6452 mHandler.removeMessages(MSG_INVALIDATE_RECT, view);
6453 mInvalidateOnAnimationRunnable.removeView(view);
6454 }
6455
keunyoung30f420f2013-08-02 14:23:10 -07006456 public void dispatchInputEvent(InputEvent event) {
Jae Seo6a6059a2014-04-17 21:35:29 -07006457 dispatchInputEvent(event, null);
6458 }
6459
6460 public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
6461 SomeArgs args = SomeArgs.obtain();
6462 args.arg1 = event;
6463 args.arg2 = receiver;
6464 Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
Jeff Browne0dbd002012-02-15 19:34:58 -08006465 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08006466 mHandler.sendMessage(msg);
6467 }
6468
Michael Wright899d7052014-04-23 17:23:39 -07006469 public void synthesizeInputEvent(InputEvent event) {
6470 Message msg = mHandler.obtainMessage(MSG_SYNTHESIZE_INPUT_EVENT, event);
6471 msg.setAsynchronous(true);
6472 mHandler.sendMessage(msg);
6473 }
6474
Jeff Browna175a5b2012-02-15 19:18:31 -08006475 public void dispatchKeyFromIme(KeyEvent event) {
6476 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
Jeff Browne0dbd002012-02-15 19:34:58 -08006477 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08006478 mHandler.sendMessage(msg);
Jeff Browncb1404e2011-01-15 18:14:15 -08006479 }
6480
Michael Wright899d7052014-04-23 17:23:39 -07006481 /**
6482 * Reinject unhandled {@link InputEvent}s in order to synthesize fallbacks events.
6483 *
6484 * Note that it is the responsibility of the caller of this API to recycle the InputEvent it
6485 * passes in.
6486 */
Michael Wright3da28342014-04-22 17:00:11 -07006487 public void dispatchUnhandledInputEvent(InputEvent event) {
Michael Wright899d7052014-04-23 17:23:39 -07006488 if (event instanceof MotionEvent) {
6489 event = MotionEvent.obtain((MotionEvent) event);
Michael Wright3da28342014-04-22 17:00:11 -07006490 }
Michael Wright899d7052014-04-23 17:23:39 -07006491 synthesizeInputEvent(event);
Michael Wright3da28342014-04-22 17:00:11 -07006492 }
6493
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006494 public void dispatchAppVisibility(boolean visible) {
Jeff Browna175a5b2012-02-15 19:18:31 -08006495 Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006496 msg.arg1 = visible ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08006497 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006498 }
6499
6500 public void dispatchGetNewSurface() {
Jeff Browna175a5b2012-02-15 19:18:31 -08006501 Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
6502 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006503 }
6504
6505 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
6506 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08006507 msg.what = MSG_WINDOW_FOCUS_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006508 msg.arg1 = hasFocus ? 1 : 0;
6509 msg.arg2 = inTouchMode ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08006510 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006511 }
6512
Craig Mautner9c795042014-10-28 19:59:59 -07006513 public void dispatchWindowShown() {
6514 mHandler.sendEmptyMessage(MSG_DISPATCH_WINDOW_SHOWN);
6515 }
6516
Dianne Hackbornffa42482009-09-23 22:20:11 -07006517 public void dispatchCloseSystemDialogs(String reason) {
6518 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08006519 msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
Dianne Hackbornffa42482009-09-23 22:20:11 -07006520 msg.obj = reason;
Jeff Browna175a5b2012-02-15 19:18:31 -08006521 mHandler.sendMessage(msg);
Dianne Hackbornffa42482009-09-23 22:20:11 -07006522 }
Christopher Tatea53146c2010-09-07 11:57:52 -07006523
6524 public void dispatchDragEvent(DragEvent event) {
Chris Tate91e9bb32010-10-12 12:58:43 -07006525 final int what;
6526 if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
Jeff Browna175a5b2012-02-15 19:18:31 -08006527 what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
6528 mHandler.removeMessages(what);
Chris Tate91e9bb32010-10-12 12:58:43 -07006529 } else {
Jeff Browna175a5b2012-02-15 19:18:31 -08006530 what = MSG_DISPATCH_DRAG_EVENT;
Chris Tate91e9bb32010-10-12 12:58:43 -07006531 }
Jeff Browna175a5b2012-02-15 19:18:31 -08006532 Message msg = mHandler.obtainMessage(what, event);
6533 mHandler.sendMessage(msg);
Christopher Tatea53146c2010-09-07 11:57:52 -07006534 }
6535
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08006536 public void updatePointerIcon(float x, float y) {
6537 final int what = MSG_UPDATE_POINTER_ICON;
6538 mHandler.removeMessages(what);
6539 final long now = SystemClock.uptimeMillis();
6540 final MotionEvent event = MotionEvent.obtain(
6541 0, now, MotionEvent.ACTION_HOVER_MOVE, x, y, 0);
6542 Message msg = mHandler.obtainMessage(what, event);
6543 mHandler.sendMessage(msg);
6544 }
6545
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006546 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
6547 int localValue, int localChanges) {
6548 SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
6549 args.seq = seq;
6550 args.globalVisibility = globalVisibility;
6551 args.localValue = localValue;
6552 args.localChanges = localChanges;
Jeff Browna175a5b2012-02-15 19:18:31 -08006553 mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
6554 }
6555
6556 public void dispatchCheckFocus() {
6557 if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
6558 // This will result in a call to checkFocus() below.
6559 mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
6560 }
Joe Onorato664644d2011-01-23 17:53:23 -08006561 }
6562
Clara Bayarrifcd7e802016-03-10 12:58:18 +00006563 public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
6564 mHandler.obtainMessage(
6565 MSG_REQUEST_KEYBOARD_SHORTCUTS, deviceId, 0, receiver).sendToTarget();
Clara Bayarri75e09792015-07-29 16:20:40 +01006566 }
6567
svetoslavganov75986cf2009-05-14 22:28:01 -07006568 /**
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006569 * Post a callback to send a
6570 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
Svetoslav Ganova0156172011-06-26 17:55:44 -07006571 * This event is send at most once every
6572 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006573 */
Alan Viverette77e9a282013-09-12 17:16:09 -07006574 private void postSendWindowContentChangedCallback(View source, int changeType) {
Svetoslav Ganova0156172011-06-26 17:55:44 -07006575 if (mSendWindowContentChangedAccessibilityEvent == null) {
6576 mSendWindowContentChangedAccessibilityEvent =
6577 new SendWindowContentChangedAccessibilityEvent();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006578 }
Alan Viverette77e9a282013-09-12 17:16:09 -07006579 mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006580 }
6581
6582 /**
6583 * Remove a posted callback to send a
6584 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
6585 */
6586 private void removeSendWindowContentChangedCallback() {
Svetoslav Ganova0156172011-06-26 17:55:44 -07006587 if (mSendWindowContentChangedAccessibilityEvent != null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08006588 mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006589 }
6590 }
6591
Igor Murashkina86ab6402013-08-30 12:58:36 -07006592 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006593 public boolean showContextMenuForChild(View originalView) {
6594 return false;
6595 }
6596
Igor Murashkina86ab6402013-08-30 12:58:36 -07006597 @Override
Oren Blasberged391262015-09-01 12:12:51 -07006598 public boolean showContextMenuForChild(View originalView, float x, float y) {
6599 return false;
6600 }
6601
6602 @Override
Adam Powell6e346362010-07-23 10:18:23 -07006603 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
6604 return null;
6605 }
6606
Igor Murashkina86ab6402013-08-30 12:58:36 -07006607 @Override
Clara Bayarri4423d912015-03-02 19:42:48 +00006608 public ActionMode startActionModeForChild(
6609 View originalView, ActionMode.Callback callback, int type) {
6610 return null;
6611 }
6612
6613 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006614 public void createContextMenu(ContextMenu menu) {
6615 }
6616
Igor Murashkina86ab6402013-08-30 12:58:36 -07006617 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006618 public void childDrawableStateChanged(View child) {
6619 }
6620
Igor Murashkina86ab6402013-08-30 12:58:36 -07006621 @Override
Svetoslav Ganov736c2752011-04-22 18:30:36 -07006622 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
George Mount41725de2015-04-09 08:23:05 -07006623 if (mView == null || mStopped || mPausedForTransition) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -07006624 return false;
6625 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006626 // Intercept accessibility focus events fired by virtual nodes to keep
6627 // track of accessibility focus position in such nodes.
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006628 final int eventType = event.getEventType();
6629 switch (eventType) {
6630 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006631 final long sourceNodeId = event.getSourceNodeId();
6632 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
6633 sourceNodeId);
6634 View source = mView.findViewByAccessibilityId(accessibilityViewId);
6635 if (source != null) {
6636 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
6637 if (provider != null) {
Svetoslavb3ba1d42014-09-26 15:20:40 -07006638 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
6639 sourceNodeId);
6640 final AccessibilityNodeInfo node;
6641 if (virtualNodeId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
6642 node = provider.createAccessibilityNodeInfo(
6643 AccessibilityNodeProvider.HOST_VIEW_ID);
6644 } else {
6645 node = provider.createAccessibilityNodeInfo(virtualNodeId);
6646 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006647 setAccessibilityFocus(source, node);
6648 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006649 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006650 } break;
6651 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006652 final long sourceNodeId = event.getSourceNodeId();
6653 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
6654 sourceNodeId);
6655 View source = mView.findViewByAccessibilityId(accessibilityViewId);
6656 if (source != null) {
6657 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
6658 if (provider != null) {
6659 setAccessibilityFocus(null, null);
6660 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006661 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006662 } break;
Svetoslavf0c758b2014-09-03 17:47:37 -07006663
6664
6665 case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: {
Alan Viverette34457f52015-03-25 13:09:20 -07006666 handleWindowContentChangedEvent(event);
Svetoslavf0c758b2014-09-03 17:47:37 -07006667 } break;
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006668 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006669 mAccessibilityManager.sendAccessibilityEvent(event);
Svetoslav Ganov736c2752011-04-22 18:30:36 -07006670 return true;
6671 }
6672
Alan Viverette34457f52015-03-25 13:09:20 -07006673 /**
6674 * Updates the focused virtual view, when necessary, in response to a
6675 * content changed event.
6676 * <p>
6677 * This is necessary to get updated bounds after a position change.
6678 *
6679 * @param event an accessibility event of type
6680 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}
6681 */
6682 private void handleWindowContentChangedEvent(AccessibilityEvent event) {
Alan Viverette25acc7e2015-05-19 11:32:08 -07006683 final View focusedHost = mAccessibilityFocusedHost;
6684 if (focusedHost == null || mAccessibilityFocusedVirtualView == null) {
6685 // No virtual view focused, nothing to do here.
Alan Viverette34457f52015-03-25 13:09:20 -07006686 return;
6687 }
6688
Alan Viverette25acc7e2015-05-19 11:32:08 -07006689 final AccessibilityNodeProvider provider = focusedHost.getAccessibilityNodeProvider();
Alan Viverette34457f52015-03-25 13:09:20 -07006690 if (provider == null) {
Alan Viverette25acc7e2015-05-19 11:32:08 -07006691 // Error state: virtual view with no provider. Clear focus.
6692 mAccessibilityFocusedHost = null;
6693 mAccessibilityFocusedVirtualView = null;
Phil Weavere37cfab2016-04-07 21:01:57 -07006694 focusedHost.clearAccessibilityFocusNoCallbacks(0);
Alan Viverette34457f52015-03-25 13:09:20 -07006695 return;
6696 }
6697
6698 // We only care about change types that may affect the bounds of the
6699 // focused virtual view.
6700 final int changes = event.getContentChangeTypes();
6701 if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) == 0
6702 && changes != AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) {
6703 return;
6704 }
6705
6706 final long eventSourceNodeId = event.getSourceNodeId();
6707 final int changedViewId = AccessibilityNodeInfo.getAccessibilityViewId(eventSourceNodeId);
6708
6709 // Search up the tree for subtree containment.
6710 boolean hostInSubtree = false;
6711 View root = mAccessibilityFocusedHost;
6712 while (root != null && !hostInSubtree) {
6713 if (changedViewId == root.getAccessibilityViewId()) {
6714 hostInSubtree = true;
6715 } else {
6716 final ViewParent parent = root.getParent();
6717 if (parent instanceof View) {
6718 root = (View) parent;
6719 } else {
6720 root = null;
6721 }
6722 }
6723 }
6724
6725 // We care only about changes in subtrees containing the host view.
6726 if (!hostInSubtree) {
6727 return;
6728 }
6729
6730 final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId();
6731 int focusedChildId = AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId);
6732 if (focusedChildId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
6733 // TODO: Should we clear the focused virtual view?
6734 focusedChildId = AccessibilityNodeProvider.HOST_VIEW_ID;
6735 }
6736
6737 // Refresh the node for the focused virtual view.
Alan Viverettea7ea65e2015-05-15 11:30:21 -07006738 final Rect oldBounds = mTempRect;
6739 mAccessibilityFocusedVirtualView.getBoundsInScreen(oldBounds);
Alan Viverette34457f52015-03-25 13:09:20 -07006740 mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo(focusedChildId);
Alan Viverette25acc7e2015-05-19 11:32:08 -07006741 if (mAccessibilityFocusedVirtualView == null) {
6742 // Error state: The node no longer exists. Clear focus.
6743 mAccessibilityFocusedHost = null;
Phil Weavere37cfab2016-04-07 21:01:57 -07006744 focusedHost.clearAccessibilityFocusNoCallbacks(0);
Alan Viverette25acc7e2015-05-19 11:32:08 -07006745
6746 // This will probably fail, but try to keep the provider's internal
6747 // state consistent by clearing focus.
6748 provider.performAction(focusedChildId,
6749 AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(), null);
Alan Viverettea7ea65e2015-05-15 11:30:21 -07006750 invalidateRectOnScreen(oldBounds);
Alan Viverette25acc7e2015-05-19 11:32:08 -07006751 } else {
6752 // The node was refreshed, invalidate bounds if necessary.
6753 final Rect newBounds = mAccessibilityFocusedVirtualView.getBoundsInScreen();
6754 if (!oldBounds.equals(newBounds)) {
6755 oldBounds.union(newBounds);
6756 invalidateRectOnScreen(oldBounds);
6757 }
Alan Viverettea7ea65e2015-05-15 11:30:21 -07006758 }
Alan Viverette34457f52015-03-25 13:09:20 -07006759 }
6760
Svetoslav Ganov42138042012-03-20 11:51:39 -07006761 @Override
Alan Viverette77e9a282013-09-12 17:16:09 -07006762 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
6763 postSendWindowContentChangedCallback(source, changeType);
Svetoslav Ganov42138042012-03-20 11:51:39 -07006764 }
6765
Fabrice Di Meglio9dd4c5c2013-02-08 18:15:07 -08006766 @Override
6767 public boolean canResolveLayoutDirection() {
6768 return true;
6769 }
6770
6771 @Override
6772 public boolean isLayoutDirectionResolved() {
6773 return true;
6774 }
6775
6776 @Override
6777 public int getLayoutDirection() {
6778 return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT;
6779 }
6780
6781 @Override
6782 public boolean canResolveTextDirection() {
6783 return true;
6784 }
6785
6786 @Override
6787 public boolean isTextDirectionResolved() {
6788 return true;
6789 }
6790
6791 @Override
6792 public int getTextDirection() {
6793 return View.TEXT_DIRECTION_RESOLVED_DEFAULT;
6794 }
6795
6796 @Override
6797 public boolean canResolveTextAlignment() {
6798 return true;
6799 }
6800
6801 @Override
6802 public boolean isTextAlignmentResolved() {
6803 return true;
6804 }
6805
6806 @Override
6807 public int getTextAlignment() {
6808 return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT;
6809 }
6810
Svetoslav Ganov42138042012-03-20 11:51:39 -07006811 private View getCommonPredecessor(View first, View second) {
Chris Craikd36a81f2014-07-17 10:16:51 -07006812 if (mTempHashSet == null) {
6813 mTempHashSet = new HashSet<View>();
Svetoslav Ganov42138042012-03-20 11:51:39 -07006814 }
Chris Craikd36a81f2014-07-17 10:16:51 -07006815 HashSet<View> seen = mTempHashSet;
6816 seen.clear();
6817 View firstCurrent = first;
6818 while (firstCurrent != null) {
6819 seen.add(firstCurrent);
6820 ViewParent firstCurrentParent = firstCurrent.mParent;
6821 if (firstCurrentParent instanceof View) {
6822 firstCurrent = (View) firstCurrentParent;
6823 } else {
6824 firstCurrent = null;
6825 }
6826 }
6827 View secondCurrent = second;
6828 while (secondCurrent != null) {
6829 if (seen.contains(secondCurrent)) {
6830 seen.clear();
6831 return secondCurrent;
6832 }
6833 ViewParent secondCurrentParent = secondCurrent.mParent;
6834 if (secondCurrentParent instanceof View) {
6835 secondCurrent = (View) secondCurrentParent;
6836 } else {
6837 secondCurrent = null;
6838 }
6839 }
6840 seen.clear();
Svetoslav Ganov42138042012-03-20 11:51:39 -07006841 return null;
6842 }
6843
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006844 void checkThread() {
6845 if (mThread != Thread.currentThread()) {
6846 throw new CalledFromWrongThreadException(
6847 "Only the original thread that created a view hierarchy can touch its views.");
6848 }
6849 }
6850
Igor Murashkina86ab6402013-08-30 12:58:36 -07006851 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006852 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Joe Onoratoc6cc0f82011-04-12 11:53:13 -07006853 // ViewAncestor never intercepts touch event, so this can be a no-op
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006854 }
6855
Igor Murashkina86ab6402013-08-30 12:58:36 -07006856 @Override
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07006857 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
Yigit Boyard62d5e92016-01-19 18:56:20 -08006858 if (rectangle == null) {
6859 return scrollToRectOrFocus(null, immediate);
6860 }
6861 rectangle.offset(child.getLeft() - child.getScrollX(),
6862 child.getTop() - child.getScrollY());
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07006863 final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
Yigit Boyard62d5e92016-01-19 18:56:20 -08006864 mTempRect.set(rectangle);
6865 mTempRect.offset(0, -mCurScrollY);
6866 mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
6867 try {
6868 mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect);
6869 } catch (RemoteException re) {
6870 /* ignore */
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07006871 }
6872 return scrolled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006873 }
Romain Guy8506ab42009-06-11 17:35:47 -07006874
Igor Murashkina86ab6402013-08-30 12:58:36 -07006875 @Override
Adam Powell539ee872012-02-03 19:00:49 -08006876 public void childHasTransientStateChanged(View child, boolean hasTransientState) {
6877 // Do nothing.
6878 }
6879
Adam Powell10ba2772014-04-15 09:46:51 -07006880 @Override
6881 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
6882 return false;
6883 }
6884
6885 @Override
6886 public void onStopNestedScroll(View target) {
6887 }
6888
6889 @Override
6890 public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
6891 }
6892
6893 @Override
6894 public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
6895 int dxUnconsumed, int dyUnconsumed) {
6896 }
6897
6898 @Override
6899 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
6900 }
6901
6902 @Override
Adam Powellb36e4f92014-05-01 10:23:33 -07006903 public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
Adam Powell10ba2772014-04-15 09:46:51 -07006904 return false;
6905 }
6906
Adam Powellb72be592014-07-16 21:41:31 -07006907 @Override
6908 public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
6909 return false;
6910 }
6911
Adam Powellb6ab0982015-01-07 17:00:12 -08006912 @Override
6913 public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
6914 return false;
6915 }
6916
Jorim Jaggib774e552015-08-24 14:52:45 -07006917 /**
6918 * Force the window to report its next draw.
6919 * <p>
6920 * This method is only supposed to be used to speed up the interaction from SystemUI and window
6921 * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE
6922 * unless you fully understand this interaction.
6923 * @hide
6924 */
6925 public void setReportNextDraw() {
6926 mReportNextDraw = true;
6927 invalidate();
6928 }
6929
Craig Mautnerbc57cd12013-08-19 15:47:42 -07006930 void changeCanvasOpacity(boolean opaque) {
Filip Gruszczynski34dab0b2015-12-22 08:29:07 -08006931 Log.d(mTag, "changeCanvasOpacity: opaque=" + opaque);
John Reck63a06672014-05-07 13:45:54 -07006932 if (mAttachInfo.mHardwareRenderer != null) {
6933 mAttachInfo.mHardwareRenderer.setOpaque(opaque);
6934 }
Craig Mautnerbc57cd12013-08-19 15:47:42 -07006935 }
6936
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006937 class TakenSurfaceHolder extends BaseSurfaceHolder {
6938 @Override
6939 public boolean onAllowLockCanvas() {
6940 return mDrawingAllowed;
6941 }
6942
6943 @Override
6944 public void onRelayoutContainer() {
6945 // Not currently interesting -- from changing between fixed and layout size.
6946 }
6947
Igor Murashkina86ab6402013-08-30 12:58:36 -07006948 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006949 public void setFormat(int format) {
6950 ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
6951 }
6952
Igor Murashkina86ab6402013-08-30 12:58:36 -07006953 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006954 public void setType(int type) {
6955 ((RootViewSurfaceTaker)mView).setSurfaceType(type);
6956 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006957
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006958 @Override
6959 public void onUpdateSurface() {
6960 // We take care of format and type changes on our own.
6961 throw new IllegalStateException("Shouldn't be here");
6962 }
6963
Igor Murashkina86ab6402013-08-30 12:58:36 -07006964 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006965 public boolean isCreating() {
6966 return mIsCreating;
6967 }
6968
6969 @Override
6970 public void setFixedSize(int width, int height) {
6971 throw new UnsupportedOperationException(
6972 "Currently only support sizing from layout");
6973 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006974
6975 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006976 public void setKeepScreenOn(boolean screenOn) {
6977 ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
6978 }
6979 }
Romain Guy8506ab42009-06-11 17:35:47 -07006980
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006981 static class W extends IWindow.Stub {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006982 private final WeakReference<ViewRootImpl> mViewAncestor;
Jeff Brown98365d72012-08-19 20:30:52 -07006983 private final IWindowSession mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006984
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006985 W(ViewRootImpl viewAncestor) {
6986 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
Jeff Brown98365d72012-08-19 20:30:52 -07006987 mWindowSession = viewAncestor.mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006988 }
6989
Igor Murashkina86ab6402013-08-30 12:58:36 -07006990 @Override
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006991 public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Filip Gruszczynski2217f612015-05-26 11:32:08 -07006992 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08006993 Configuration newConfig, Rect backDropFrame, boolean forceLayout,
6994 boolean alwaysConsumeNavBar) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006995 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006996 if (viewAncestor != null) {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006997 viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
Jorim Jaggia4a58ef2016-01-27 02:10:08 -08006998 visibleInsets, stableInsets, outsets, reportDraw, newConfig, backDropFrame,
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -08006999 forceLayout, alwaysConsumeNavBar);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007000 }
7001 }
7002
Craig Mautner5702d4d2012-06-30 14:10:16 -07007003 @Override
7004 public void moved(int newX, int newY) {
7005 final ViewRootImpl viewAncestor = mViewAncestor.get();
7006 if (viewAncestor != null) {
7007 viewAncestor.dispatchMoved(newX, newY);
7008 }
7009 }
7010
Igor Murashkina86ab6402013-08-30 12:58:36 -07007011 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007012 public void dispatchAppVisibility(boolean visible) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007013 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007014 if (viewAncestor != null) {
7015 viewAncestor.dispatchAppVisibility(visible);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007016 }
7017 }
7018
Igor Murashkina86ab6402013-08-30 12:58:36 -07007019 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007020 public void dispatchGetNewSurface() {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007021 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007022 if (viewAncestor != null) {
7023 viewAncestor.dispatchGetNewSurface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007024 }
7025 }
7026
Igor Murashkina86ab6402013-08-30 12:58:36 -07007027 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007028 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007029 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007030 if (viewAncestor != null) {
7031 viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007032 }
7033 }
7034
7035 private static int checkCallingPermission(String permission) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007036 try {
7037 return ActivityManagerNative.getDefault().checkPermission(
7038 permission, Binder.getCallingPid(), Binder.getCallingUid());
7039 } catch (RemoteException e) {
7040 return PackageManager.PERMISSION_DENIED;
7041 }
7042 }
7043
Igor Murashkina86ab6402013-08-30 12:58:36 -07007044 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007045 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007046 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007047 if (viewAncestor != null) {
7048 final View view = viewAncestor.mView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007049 if (view != null) {
7050 if (checkCallingPermission(Manifest.permission.DUMP) !=
7051 PackageManager.PERMISSION_GRANTED) {
7052 throw new SecurityException("Insufficient permissions to invoke"
7053 + " executeCommand() from pid=" + Binder.getCallingPid()
7054 + ", uid=" + Binder.getCallingUid());
7055 }
7056
7057 OutputStream clientStream = null;
7058 try {
7059 clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
7060 ViewDebug.dispatchCommand(view, command, parameters, clientStream);
7061 } catch (IOException e) {
7062 e.printStackTrace();
7063 } finally {
7064 if (clientStream != null) {
7065 try {
7066 clientStream.close();
7067 } catch (IOException e) {
7068 e.printStackTrace();
7069 }
7070 }
7071 }
7072 }
7073 }
7074 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07007075
7076 @Override
Dianne Hackbornffa42482009-09-23 22:20:11 -07007077 public void closeSystemDialogs(String reason) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007078 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007079 if (viewAncestor != null) {
7080 viewAncestor.dispatchCloseSystemDialogs(reason);
Dianne Hackbornffa42482009-09-23 22:20:11 -07007081 }
7082 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07007083
7084 @Override
Marco Nelissenbf6956b2009-11-09 15:21:13 -08007085 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
7086 boolean sync) {
Dianne Hackborn19382ac2009-09-11 21:13:37 -07007087 if (sync) {
7088 try {
Jeff Brown98365d72012-08-19 20:30:52 -07007089 mWindowSession.wallpaperOffsetsComplete(asBinder());
Dianne Hackborn19382ac2009-09-11 21:13:37 -07007090 } catch (RemoteException e) {
7091 }
7092 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07007093 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007094
Igor Murashkina86ab6402013-08-30 12:58:36 -07007095 @Override
Dianne Hackborn75804932009-10-20 20:15:20 -07007096 public void dispatchWallpaperCommand(String action, int x, int y,
7097 int z, Bundle extras, boolean sync) {
7098 if (sync) {
7099 try {
Jeff Brown98365d72012-08-19 20:30:52 -07007100 mWindowSession.wallpaperCommandComplete(asBinder(), null);
Dianne Hackborn75804932009-10-20 20:15:20 -07007101 } catch (RemoteException e) {
7102 }
7103 }
7104 }
Christopher Tatea53146c2010-09-07 11:57:52 -07007105
7106 /* Drag/drop */
Igor Murashkina86ab6402013-08-30 12:58:36 -07007107 @Override
Christopher Tatea53146c2010-09-07 11:57:52 -07007108 public void dispatchDragEvent(DragEvent event) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007109 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007110 if (viewAncestor != null) {
7111 viewAncestor.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07007112 }
7113 }
Joe Onorato664644d2011-01-23 17:53:23 -08007114
Igor Murashkina86ab6402013-08-30 12:58:36 -07007115 @Override
Vladislav Kaznacheevec6a4472016-01-22 12:21:52 -08007116 public void updatePointerIcon(float x, float y) {
7117 final ViewRootImpl viewAncestor = mViewAncestor.get();
7118 if (viewAncestor != null) {
7119 viewAncestor.updatePointerIcon(x, y);
7120 }
7121 }
7122
7123 @Override
Dianne Hackborn9a230e02011-10-06 11:51:27 -07007124 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
7125 int localValue, int localChanges) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07007126 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007127 if (viewAncestor != null) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07007128 viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility,
7129 localValue, localChanges);
Joe Onorato664644d2011-01-23 17:53:23 -08007130 }
7131 }
Dianne Hackborn12d3a942012-04-27 14:16:30 -07007132
Igor Murashkina86ab6402013-08-30 12:58:36 -07007133 @Override
Craig Mautner9c795042014-10-28 19:59:59 -07007134 public void dispatchWindowShown() {
7135 final ViewRootImpl viewAncestor = mViewAncestor.get();
7136 if (viewAncestor != null) {
7137 viewAncestor.dispatchWindowShown();
7138 }
7139 }
Clara Bayarri75e09792015-07-29 16:20:40 +01007140
7141 @Override
Clara Bayarrifcd7e802016-03-10 12:58:18 +00007142 public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
7143 ViewRootImpl viewAncestor = mViewAncestor.get();
7144 if (viewAncestor != null) {
7145 viewAncestor.dispatchRequestKeyboardShortcuts(receiver, deviceId);
7146 }
Clara Bayarri75e09792015-07-29 16:20:40 +01007147 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007148 }
7149
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007150 public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
7151 public CalledFromWrongThreadException(String msg) {
7152 super(msg);
7153 }
7154 }
7155
Alan Viverettebea0c7da2015-09-01 16:00:20 -04007156 static HandlerActionQueue getRunQueue() {
7157 HandlerActionQueue rq = sRunQueues.get();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007158 if (rq != null) {
7159 return rq;
7160 }
Alan Viverettebea0c7da2015-09-01 16:00:20 -04007161 rq = new HandlerActionQueue();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007162 sRunQueues.set(rq);
7163 return rq;
7164 }
Romain Guy8506ab42009-06-11 17:35:47 -07007165
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007166 /**
Skuhneb8160872015-09-22 09:51:39 -07007167 * Start a drag resizing which will inform all listeners that a window resize is taking place.
7168 */
Jorim Jaggi9511b0f2016-01-29 19:12:44 -08007169 private void startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets,
Jorim Jaggic39c7b02016-03-24 10:47:07 -07007170 Rect stableInsets, int resizeMode) {
Skuhneb8160872015-09-22 09:51:39 -07007171 if (!mDragResizing) {
7172 mDragResizing = true;
Jorim Jaggi16b63192016-03-25 18:32:19 -07007173 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
7174 mWindowCallbacks.get(i).onWindowDragResizeStart(initialBounds, fullscreen,
7175 systemInsets, stableInsets, resizeMode);
Skuhneb8160872015-09-22 09:51:39 -07007176 }
7177 mFullRedrawNeeded = true;
7178 }
7179 }
7180
7181 /**
7182 * End a drag resize which will inform all listeners that a window resize has ended.
7183 */
7184 private void endDragResizing() {
7185 if (mDragResizing) {
7186 mDragResizing = false;
Jorim Jaggi16b63192016-03-25 18:32:19 -07007187 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
7188 mWindowCallbacks.get(i).onWindowDragResizeEnd();
Skuhneb8160872015-09-22 09:51:39 -07007189 }
7190 mFullRedrawNeeded = true;
7191 }
7192 }
7193
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07007194 private boolean updateContentDrawBounds() {
7195 boolean updated = false;
Jorim Jaggi16b63192016-03-25 18:32:19 -07007196 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
7197 updated |= mWindowCallbacks.get(i).onContentDrawn(
7198 mWindowAttributes.surfaceInsets.left,
7199 mWindowAttributes.surfaceInsets.top,
7200 mWidth, mHeight);
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07007201 }
7202 return updated | (mDragResizing && mReportNextDraw);
7203 }
7204
7205 private void requestDrawWindow() {
7206 if (mReportNextDraw) {
7207 mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size());
7208 }
Jorim Jaggi16b63192016-03-25 18:32:19 -07007209 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
7210 mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw);
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07007211 }
7212 }
7213
Skuhneb8160872015-09-22 09:51:39 -07007214 /**
Jorim Jaggi4846ee32016-01-07 17:39:12 +01007215 * Tells this instance that its corresponding activity has just relaunched. In this case, we
7216 * need to force a relayout of the window to make sure we get the correct bounds from window
7217 * manager.
7218 */
7219 public void reportActivityRelaunched() {
7220 mActivityRelaunched = true;
7221 }
7222
7223 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007224 * Class for managing the accessibility interaction connection
7225 * based on the global accessibility state.
7226 */
7227 final class AccessibilityInteractionConnectionManager
7228 implements AccessibilityStateChangeListener {
Igor Murashkina86ab6402013-08-30 12:58:36 -07007229 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007230 public void onAccessibilityStateChanged(boolean enabled) {
7231 if (enabled) {
7232 ensureConnection();
Chris Craikcce47eb2014-07-16 15:12:15 -07007233 if (mAttachInfo.mHasWindowFocus) {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08007234 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
7235 View focusedView = mView.findFocus();
7236 if (focusedView != null && focusedView != mView) {
7237 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
7238 }
7239 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007240 } else {
7241 ensureNoConnection();
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07007242 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007243 }
7244 }
7245
7246 public void ensureConnection() {
Chris Craikcce47eb2014-07-16 15:12:15 -07007247 final boolean registered =
Svetoslav8e3feb12014-02-24 13:46:47 -08007248 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
Chris Craikcce47eb2014-07-16 15:12:15 -07007249 if (!registered) {
7250 mAttachInfo.mAccessibilityWindowId =
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08007251 mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
7252 new AccessibilityInteractionConnection(ViewRootImpl.this));
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007253 }
7254 }
7255
7256 public void ensureNoConnection() {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08007257 final boolean registered =
Svetoslav8e3feb12014-02-24 13:46:47 -08007258 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007259 if (registered) {
Svetoslav8e3feb12014-02-24 13:46:47 -08007260 mAttachInfo.mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007261 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
7262 }
7263 }
7264 }
7265
Chris Craikcce47eb2014-07-16 15:12:15 -07007266 final class HighContrastTextManager implements HighTextContrastChangeListener {
7267 HighContrastTextManager() {
7268 mAttachInfo.mHighContrastText = mAccessibilityManager.isHighTextContrastEnabled();
7269 }
7270 @Override
7271 public void onHighTextContrastStateChanged(boolean enabled) {
7272 mAttachInfo.mHighContrastText = enabled;
7273
7274 // Destroy Displaylists so they can be recreated with high contrast recordings
7275 destroyHardwareResources();
Chris Craikd36a81f2014-07-17 10:16:51 -07007276
7277 // Schedule redraw, which will rerecord + redraw all text
7278 invalidate();
Chris Craikcce47eb2014-07-16 15:12:15 -07007279 }
7280 }
7281
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007282 /**
7283 * This class is an interface this ViewAncestor provides to the
7284 * AccessibilityManagerService to the latter can interact with
7285 * the view hierarchy in this ViewAncestor.
7286 */
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07007287 static final class AccessibilityInteractionConnection
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007288 extends IAccessibilityInteractionConnection.Stub {
Svetoslav Ganov02107852011-10-03 17:06:56 -07007289 private final WeakReference<ViewRootImpl> mViewRootImpl;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007290
Svetoslav Ganovf79f4762011-10-28 15:40:32 -07007291 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) {
7292 mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007293 }
7294
Svetoslav Ganov42138042012-03-20 11:51:39 -07007295 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07007296 public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07007297 Region interactiveRegion, int interactionId,
7298 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07007299 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07007300 ViewRootImpl viewRootImpl = mViewRootImpl.get();
7301 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07007302 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov02107852011-10-03 17:06:56 -07007303 .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07007304 interactiveRegion, interactionId, callback, flags, interrogatingPid,
7305 interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007306 } else {
7307 // We cannot make the call and notify the caller so it does not wait.
7308 try {
7309 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
7310 } catch (RemoteException re) {
7311 /* best effort - ignore */
7312 }
Svetoslav Ganov601ad802011-06-09 14:47:38 -07007313 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007314 }
7315
Svetoslav Ganov42138042012-03-20 11:51:39 -07007316 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07007317 public void performAccessibilityAction(long accessibilityNodeId, int action,
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07007318 Bundle arguments, int interactionId,
7319 IAccessibilityInteractionConnectionCallback callback, int flags,
Svet Ganov7498efd2014-09-03 21:33:00 -07007320 int interrogatingPid, long interrogatingTid) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07007321 ViewRootImpl viewRootImpl = mViewRootImpl.get();
7322 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07007323 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07007324 .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
Svet Ganov7498efd2014-09-03 21:33:00 -07007325 interactionId, callback, flags, interrogatingPid, interrogatingTid);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007326 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007327 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007328 try {
7329 callback.setPerformAccessibilityActionResult(false, interactionId);
7330 } catch (RemoteException re) {
7331 /* best effort - ignore */
7332 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007333 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007334 }
7335
Svetoslav Ganov42138042012-03-20 11:51:39 -07007336 @Override
Svetoslav Ganov80943d82013-01-02 10:25:37 -08007337 public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07007338 String viewId, Region interactiveRegion, int interactionId,
Svetoslav Ganov80943d82013-01-02 10:25:37 -08007339 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07007340 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07007341 ViewRootImpl viewRootImpl = mViewRootImpl.get();
7342 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07007343 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov80943d82013-01-02 10:25:37 -08007344 .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07007345 viewId, interactiveRegion, interactionId, callback, flags,
7346 interrogatingPid, interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007347 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007348 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007349 try {
7350 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
7351 } catch (RemoteException re) {
7352 /* best effort - ignore */
7353 }
7354 }
7355 }
7356
Svetoslav Ganov42138042012-03-20 11:51:39 -07007357 @Override
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007358 public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
Svetoslav9ae9ed22014-09-02 16:36:35 -07007359 Region interactiveRegion, int interactionId,
7360 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07007361 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007362 ViewRootImpl viewRootImpl = mViewRootImpl.get();
7363 if (viewRootImpl != null && viewRootImpl.mView != null) {
7364 viewRootImpl.getAccessibilityInteractionController()
7365 .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
Svetoslav9ae9ed22014-09-02 16:36:35 -07007366 interactiveRegion, interactionId, callback, flags, interrogatingPid,
7367 interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007368 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007369 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007370 try {
7371 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
7372 } catch (RemoteException re) {
7373 /* best effort - ignore */
7374 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007375 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007376 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007377
Svetoslav Ganov42138042012-03-20 11:51:39 -07007378 @Override
Svetoslav9ae9ed22014-09-02 16:36:35 -07007379 public void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion,
7380 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07007381 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007382 ViewRootImpl viewRootImpl = mViewRootImpl.get();
7383 if (viewRootImpl != null && viewRootImpl.mView != null) {
7384 viewRootImpl.getAccessibilityInteractionController()
Svetoslav9ae9ed22014-09-02 16:36:35 -07007385 .findFocusClientThread(accessibilityNodeId, focusType, interactiveRegion,
7386 interactionId, callback, flags, interrogatingPid, interrogatingTid,
7387 spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07007388 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007389 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007390 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007391 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007392 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007393 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007394 }
7395 }
7396 }
7397
Svetoslav Ganov42138042012-03-20 11:51:39 -07007398 @Override
Svetoslav9ae9ed22014-09-02 16:36:35 -07007399 public void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion,
7400 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07007401 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007402 ViewRootImpl viewRootImpl = mViewRootImpl.get();
7403 if (viewRootImpl != null && viewRootImpl.mView != null) {
7404 viewRootImpl.getAccessibilityInteractionController()
Svetoslav9ae9ed22014-09-02 16:36:35 -07007405 .focusSearchClientThread(accessibilityNodeId, direction, interactiveRegion,
7406 interactionId, callback, flags, interrogatingPid, interrogatingTid,
7407 spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07007408 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007409 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007410 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007411 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007412 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007413 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007414 }
7415 }
7416 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007417 }
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07007418
Svetoslav Ganova0156172011-06-26 17:55:44 -07007419 private class SendWindowContentChangedAccessibilityEvent implements Runnable {
Alan Viverette77e9a282013-09-12 17:16:09 -07007420 private int mChangeTypes = 0;
7421
Svetoslav Ganov42138042012-03-20 11:51:39 -07007422 public View mSource;
Svetoslav6254f482013-06-04 17:22:14 -07007423 public long mLastEventTimeMillis;
Svetoslav Ganova0156172011-06-26 17:55:44 -07007424
Igor Murashkina86ab6402013-08-30 12:58:36 -07007425 @Override
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07007426 public void run() {
Svetoslav8d820ecf2013-07-15 17:12:41 -07007427 // The accessibility may be turned off while we were waiting so check again.
7428 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
7429 mLastEventTimeMillis = SystemClock.uptimeMillis();
7430 AccessibilityEvent event = AccessibilityEvent.obtain();
7431 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
Alan Viverette77e9a282013-09-12 17:16:09 -07007432 event.setContentChangeTypes(mChangeTypes);
Svetoslav8d820ecf2013-07-15 17:12:41 -07007433 mSource.sendAccessibilityEventUnchecked(event);
7434 } else {
7435 mLastEventTimeMillis = 0;
7436 }
7437 // In any case reset to initial state.
Svetoslav6254f482013-06-04 17:22:14 -07007438 mSource.resetSubtreeAccessibilityStateChanged();
7439 mSource = null;
Alan Viverette77e9a282013-09-12 17:16:09 -07007440 mChangeTypes = 0;
Svetoslav6254f482013-06-04 17:22:14 -07007441 }
7442
Alan Viverette77e9a282013-09-12 17:16:09 -07007443 public void runOrPost(View source, int changeType) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007444 if (mSource != null) {
Svetoslav9dafebb2013-06-18 16:29:25 -07007445 // If there is no common predecessor, then mSource points to
7446 // a removed view, hence in this case always prefer the source.
7447 View predecessor = getCommonPredecessor(mSource, source);
7448 mSource = (predecessor != null) ? predecessor : source;
Alan Viverette77e9a282013-09-12 17:16:09 -07007449 mChangeTypes |= changeType;
Svetoslav6254f482013-06-04 17:22:14 -07007450 return;
7451 }
7452 mSource = source;
Alan Viverette77e9a282013-09-12 17:16:09 -07007453 mChangeTypes = changeType;
Svetoslav6254f482013-06-04 17:22:14 -07007454 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
7455 final long minEventIntevalMillis =
7456 ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
7457 if (timeSinceLastMillis >= minEventIntevalMillis) {
Svetoslav9dafebb2013-06-18 16:29:25 -07007458 mSource.removeCallbacks(this);
Svetoslav6254f482013-06-04 17:22:14 -07007459 run();
7460 } else {
7461 mSource.postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007462 }
7463 }
7464 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007465}