blob: cd9dd97468b3774db1235c423c5cd02552581d00 [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
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -080019import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
20
Romain Guy6b7bd242010-10-06 19:49:23 -070021import android.Manifest;
Chet Haasecca2c982011-05-20 14:34:18 -070022import android.animation.LayoutTransition;
Romain Guy6b7bd242010-10-06 19:49:23 -070023import android.app.ActivityManagerNative;
24import android.content.ClipDescription;
25import android.content.ComponentCallbacks;
26import android.content.Context;
27import android.content.pm.PackageManager;
28import android.content.res.CompatibilityInfo;
29import android.content.res.Configuration;
30import android.content.res.Resources;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.graphics.Canvas;
Alan Viverettefed3f722013-11-14 14:48:20 -080032import android.graphics.Matrix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.graphics.PixelFormat;
Christopher Tate2c095f32010-10-04 14:13:40 -070034import android.graphics.Point;
Christopher Tatea53146c2010-09-07 11:57:52 -070035import android.graphics.PointF;
Romain Guy6b7bd242010-10-06 19:49:23 -070036import android.graphics.PorterDuff;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.graphics.Rect;
38import android.graphics.Region;
Svetoslav Ganov42138042012-03-20 11:51:39 -070039import android.graphics.drawable.Drawable;
Jeff Brownd912e1f2014-04-11 18:46:22 -070040import android.hardware.display.DisplayManager;
41import android.hardware.display.DisplayManager.DisplayListener;
Romain Guy6b7bd242010-10-06 19:49:23 -070042import android.media.AudioManager;
43import android.os.Binder;
Michael Wright5bd69e62015-05-14 14:48:08 +010044import android.os.Build;
Romain Guy6b7bd242010-10-06 19:49:23 -070045import android.os.Bundle;
46import android.os.Debug;
47import android.os.Handler;
Romain Guy6b7bd242010-10-06 19:49:23 -070048import android.os.Looper;
49import android.os.Message;
50import android.os.ParcelFileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.os.Process;
Romain Guy6b7bd242010-10-06 19:49:23 -070052import android.os.RemoteException;
Romain Guy6b7bd242010-10-06 19:49:23 -070053import android.os.SystemClock;
Romain Guy59a12ca2011-06-09 17:48:21 -070054import android.os.SystemProperties;
Jeff Brown481c1572012-03-09 14:41:15 -080055import android.os.Trace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.util.AndroidRuntimeException;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070057import android.util.DisplayMetrics;
Romain Guy6b7bd242010-10-06 19:49:23 -070058import android.util.Log;
Chet Haase949dbf72010-08-11 18:41:06 -070059import android.util.Slog;
John Reckba6adf62015-02-19 14:36:50 -080060import android.util.TimeUtils;
Dianne Hackborn711e62a2010-11-29 16:38:22 -080061import android.util.TypedValue;
John Reck44fd8d22014-02-26 11:00:11 -080062import android.view.Surface.OutOfResourcesException;
Jeff Browna175a5b2012-02-15 19:18:31 -080063import android.view.View.AttachInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import android.view.View.MeasureSpec;
svetoslavganov75986cf2009-05-14 22:28:01 -070065import android.view.accessibility.AccessibilityEvent;
66import android.view.accessibility.AccessibilityManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070067import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
Chris Craikcce47eb2014-07-16 15:12:15 -070068import android.view.accessibility.AccessibilityManager.HighTextContrastChangeListener;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070069import android.view.accessibility.AccessibilityNodeInfo;
Alan Viverette25acc7e2015-05-19 11:32:08 -070070import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
Svetoslav Ganov02107852011-10-03 17:06:56 -070071import android.view.accessibility.AccessibilityNodeProvider;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070072import android.view.accessibility.IAccessibilityInteractionConnection;
73import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
Dianne Hackborn0f761d62010-11-30 22:06:10 -080074import android.view.animation.AccelerateDecelerateInterpolator;
75import android.view.animation.Interpolator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076import android.view.inputmethod.InputConnection;
77import android.view.inputmethod.InputMethodManager;
78import android.widget.Scroller;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070079
Svetoslav Ganov42138042012-03-20 11:51:39 -070080import com.android.internal.R;
Svetoslav Ganov758143e2012-08-06 16:40:27 -070081import com.android.internal.os.SomeArgs;
Adam Powell6711f3b2015-05-06 15:57:09 -070082import com.android.internal.policy.PhoneFallbackEventHandler;
Romain Guy6b7bd242010-10-06 19:49:23 -070083import com.android.internal.view.BaseSurfaceHolder;
Romain Guy6b7bd242010-10-06 19:49:23 -070084import com.android.internal.view.RootViewSurfaceTaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085
Jeff Brown5182c782013-10-15 20:31:52 -070086import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087import java.io.IOException;
88import java.io.OutputStream;
Jeff Brown5182c782013-10-15 20:31:52 -070089import java.io.PrintWriter;
Romain Guy6b7bd242010-10-06 19:49:23 -070090import java.lang.ref.WeakReference;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091import java.util.ArrayList;
Chong Zhang8dbd9ad2015-10-09 10:06:11 -070092import java.util.concurrent.CountDownLatch;
Svetoslav Ganov42138042012-03-20 11:51:39 -070093import java.util.HashSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095/**
96 * The top of a view hierarchy, implementing the needed protocol between View
97 * and the WindowManager. This is for the most part an internal implementation
Jeff Brown98365d72012-08-19 20:30:52 -070098 * detail of {@link WindowManagerGlobal}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 *
100 * {@hide}
101 */
Romain Guy812ccbe2010-06-01 14:07:24 -0700102@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
Jeff Browna175a5b2012-02-15 19:18:31 -0800103public final class ViewRootImpl implements ViewParent,
Jeff Brown4a06c802012-02-15 15:06:01 -0800104 View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
Dianne Hackborn70a3f672011-08-08 14:32:41 -0700105 private static final String TAG = "ViewRootImpl";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 private static final boolean DBG = false;
Romain Guy812ccbe2010-06-01 14:07:24 -0700107 private static final boolean LOCAL_LOGV = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 /** @noinspection PointlessBooleanExpression*/
109 private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
110 private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800111 private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
113 private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
114 private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
115 private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700116 private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
Chet Haase2f2022a2011-10-11 06:41:59 -0700117 private static final boolean DEBUG_FPS = false;
Michael Wright06a79252014-05-05 17:45:29 -0700118 private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119
Romain Guy59a12ca2011-06-09 17:48:21 -0700120 /**
Skuhneb8160872015-09-22 09:51:39 -0700121 * Set to false if we do not want to use the multi threaded renderer. Note that by disabling
122 * this, WindowCallbacks will not fire.
123 */
124 private static final boolean USE_MT_RENDERER = true;
125
126 /**
Romain Guy59a12ca2011-06-09 17:48:21 -0700127 * Set this system property to true to force the view hierarchy to render
128 * at 60 Hz. This can be used to measure the potential framerate.
129 */
Romain Guye9bc11f2013-05-23 12:47:26 -0700130 private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering";
Michael Chan53071d62009-05-13 17:29:48 -0700131
Griff Hazena0938022015-03-13 10:01:41 -0700132 // properties used by emulator to determine display shape
Griff Hazena0938022015-03-13 10:01:41 -0700133 public static final String PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX =
134 "ro.emu.win_outset_bottom_px";
Michael Kolb437d3132014-06-20 13:28:44 -0700135
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 /**
137 * Maximum time we allow the user to roll the trackball enough to generate
138 * a key event, before resetting the counters.
139 */
140 static final int MAX_TRACKBALL_DELAY = 250;
141
Alan Viverettebea0c7da2015-09-01 16:00:20 -0400142 static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143
Skuhneb8160872015-09-22 09:51:39 -0700144 static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList();
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800145 static boolean sFirstDrawComplete = false;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700146
Skuhneb8160872015-09-22 09:51:39 -0700147 static final ArrayList<ComponentCallbacks> sConfigCallbacks = new ArrayList();
Romain Guy59a12ca2011-06-09 17:48:21 -0700148
Chong Zhangdcee1de2015-10-06 10:26:00 -0700149 final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList();
Jeff Brownf9e989d2013-04-04 23:04:03 -0700150 final Context mContext;
Jeff Brown98365d72012-08-19 20:30:52 -0700151 final IWindowSession mWindowSession;
152 final Display mDisplay;
Jeff Brownd912e1f2014-04-11 18:46:22 -0700153 final DisplayManager mDisplayManager;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800154 final String mBasePackageName;
Jeff Brown98365d72012-08-19 20:30:52 -0700155
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 final int[] mTmpLocation = new int[2];
Romain Guy8506ab42009-06-11 17:35:47 -0700157
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800158 final TypedValue mTmpValue = new TypedValue();
Jeff Brownf9e989d2013-04-04 23:04:03 -0700159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 final Thread mThread;
161
162 final WindowLeaked mLocation;
163
164 final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
165
166 final W mWindow;
167
Dianne Hackborn180c4842011-09-13 12:39:25 -0700168 final int mTargetSdkVersion;
169
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700170 int mSeq;
171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 View mView;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700173
174 View mAccessibilityFocusedHost;
175 AccessibilityNodeInfo mAccessibilityFocusedVirtualView;
176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 int mViewVisibility;
178 boolean mAppVisible = true;
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800179 // For recents to freeform transition we need to keep drawing after the app receives information
180 // that it became invisible. This will ignore that information and depend on the decor view
181 // visibility to control drawing. The decor view visibility will get adjusted when the app get
182 // stopped and that's when the app will stop drawing further frames.
183 private boolean mForceDecorViewVisibility = false;
Dianne Hackborn180c4842011-09-13 12:39:25 -0700184 int mOrigWindowType = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185
Alan Viverette64bf97a2015-09-18 16:42:00 -0400186 /** Whether the window had focus during the most recent traversal. */
187 boolean mHadWindowFocus;
188
189 /**
190 * Whether the window lost focus during a previous traversal and has not
191 * yet gained it back. Used to determine whether a WINDOW_STATE_CHANGE
192 * accessibility events should be sent during traversal.
193 */
194 boolean mLostWindowFocus;
195
Dianne Hackbornce418e62011-03-01 14:31:38 -0800196 // Set to true if the owner of this window is in the stopped state,
197 // so the window should no longer be active.
198 boolean mStopped = false;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700199
George Mount41725de2015-04-09 08:23:05 -0700200 // Set to true to stop input during an Activity Transition.
201 boolean mPausedForTransition = false;
202
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700203 boolean mLastInCompatMode = false;
204
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700205 SurfaceHolder.Callback2 mSurfaceHolderCallback;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700206 BaseSurfaceHolder mSurfaceHolder;
207 boolean mIsCreating;
208 boolean mDrawingAllowed;
Craig Mautner8f303ad2013-06-14 11:32:22 -0700209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 final Region mTransparentRegion;
211 final Region mPreviousTransparentRegion;
212
213 int mWidth;
214 int mHeight;
Romain Guy7d7b5492011-01-24 16:33:45 -0800215 Rect mDirty;
Romain Guybb93d552009-03-24 21:04:15 -0700216 boolean mIsAnimating;
Romain Guy8506ab42009-06-11 17:35:47 -0700217
Chong Zhang0275e392015-09-17 10:41:44 -0700218 private boolean mDragResizing;
219 private int mCanvasOffsetX;
220 private int mCanvasOffsetY;
221
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700222 CompatibilityInfo.Translator mTranslator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223
224 final View.AttachInfo mAttachInfo;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700225 InputChannel mInputChannel;
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -0700226 InputQueue.Callback mInputQueueCallback;
227 InputQueue mInputQueue;
Joe Onorato86f67862010-11-05 18:57:34 -0700228 FallbackEventHandler mFallbackEventHandler;
Jeff Brown96e942d2011-11-30 19:55:01 -0800229 Choreographer mChoreographer;
Igor Murashkina86ab6402013-08-30 12:58:36 -0700230
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231 final Rect mTempRect; // used in the transaction to not thrash the heap.
232 final Rect mVisRect; // used to retrieve visible rect of focused view.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233
234 boolean mTraversalScheduled;
Jeff Browne0dbd002012-02-15 19:34:58 -0800235 int mTraversalBarrier;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236 boolean mWillDrawSoon;
Craig Mautnerdf2390a2012-08-29 20:59:22 -0700237 /** Set to true while in performTraversals for detecting when die(true) is called from internal
238 * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */
239 boolean mIsInTraversal;
Adrian Roosfa104232014-06-20 16:10:14 -0700240 boolean mApplyInsetsRequested;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241 boolean mLayoutRequested;
242 boolean mFirst;
243 boolean mReportNextDraw;
244 boolean mFullRedrawNeeded;
245 boolean mNewSurfaceNeeded;
246 boolean mHasHadWindowFocus;
247 boolean mLastWasImTarget;
Chong Zhang8dbd9ad2015-10-09 10:06:11 -0700248 CountDownLatch mWindowDrawCountDown;
Jorim Jaggi827e0fa2015-05-07 11:41:41 -0700249
Romain Guy1f59e5c2012-05-06 14:11:16 -0700250 boolean mIsDrawing;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700251 int mLastSystemUiVisibility;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700252 int mClientWindowLayoutFlags;
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800253 boolean mLastOverscanRequested;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800254
255 // Pool of queued input events.
256 private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
257 private QueuedInputEvent mQueuedInputEventPool;
258 private int mQueuedInputEventPoolSize;
Jeff Brown4952dfd2011-11-30 19:23:22 -0800259
Michael Wrightc8a7e542013-03-20 17:58:33 -0700260 /* Input event queue.
Jeff Brownf9e989d2013-04-04 23:04:03 -0700261 * Pending input events are input events waiting to be delivered to the input stages
262 * and handled by the application.
Michael Wrightc8a7e542013-03-20 17:58:33 -0700263 */
264 QueuedInputEvent mPendingInputEventHead;
265 QueuedInputEvent mPendingInputEventTail;
Michael Wright95ae9422013-03-14 10:58:50 -0700266 int mPendingInputEventCount;
Jeff Brown96e942d2011-11-30 19:55:01 -0800267 boolean mProcessInputEventsScheduled;
Michael Wright9d744c72014-02-18 21:27:42 -0800268 boolean mUnbufferedInputDispatch;
Michael Wright95ae9422013-03-14 10:58:50 -0700269 String mPendingInputEventQueueLengthCounterName = "pq";
Jeff Brownf9e989d2013-04-04 23:04:03 -0700270
271 InputStage mFirstInputStage;
272 InputStage mFirstPostImeInputStage;
Michael Wright899d7052014-04-23 17:23:39 -0700273 InputStage mSyntheticInputStage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274
275 boolean mWindowAttributesChanged = false;
Romain Guyf21c9b02011-09-06 16:56:54 -0700276 int mWindowAttributesChangesFlag = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277
278 // These can be accessed by any thread, must be protected with a lock.
Mathias Agopian5583dc62009-07-09 16:28:11 -0700279 // Surface can never be reassigned or cleared (use Surface.clear()).
John Reckb13de072014-11-19 16:33:47 -0800280 final Surface mSurface = new Surface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281
282 boolean mAdded;
283 boolean mAddedTouchMode;
284
Craig Mautner48d0d182013-06-11 07:53:06 -0700285 final DisplayAdjustments mDisplayAdjustments;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700286
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287 // These are accessed by multiple threads.
288 final Rect mWinFrame; // frame given by window manager.
289
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800290 final Rect mPendingOverscanInsets = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291 final Rect mPendingVisibleInsets = new Rect();
Adrian Roosfa104232014-06-20 16:10:14 -0700292 final Rect mPendingStableInsets = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293 final Rect mPendingContentInsets = new Rect();
Filip Gruszczynski2217f612015-05-26 11:32:08 -0700294 final Rect mPendingOutsets = new Rect();
Jorim Jaggia7262a82015-11-03 15:15:40 +0100295 final Rect mPendingBackDropFrame = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
297 = new ViewTreeObserver.InternalInsetsInfo();
298
Adrian Roosfa104232014-06-20 16:10:14 -0700299 final Rect mDispatchContentInsets = new Rect();
300 final Rect mDispatchStableInsets = new Rect();
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700301
Filip Gruszczynski954289d2015-02-26 15:46:47 -0800302 private WindowInsets mLastWindowInsets;
303
Dianne Hackborn694f79b2010-03-17 19:44:59 -0700304 final Configuration mLastConfiguration = new Configuration();
305 final Configuration mPendingConfiguration = new Configuration();
Romain Guy59a12ca2011-06-09 17:48:21 -0700306
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307 boolean mScrollMayChange;
308 int mSoftInputMode;
Svetoslav Ganov149567f2013-01-08 15:23:34 -0800309 WeakReference<View> mLastScrolledFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310 int mScrollY;
311 int mCurScrollY;
312 Scroller mScroller;
John Recke56e9df2014-02-21 15:45:10 -0800313 static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
Chet Haasecca2c982011-05-20 14:34:18 -0700314 private ArrayList<LayoutTransition> mPendingTransitions;
Romain Guy8506ab42009-06-11 17:35:47 -0700315
Romain Guy8506ab42009-06-11 17:35:47 -0700316 final ViewConfiguration mViewConfiguration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317
Christopher Tatea53146c2010-09-07 11:57:52 -0700318 /* Drag/drop */
319 ClipDescription mDragDescription;
320 View mCurrentDragView;
Christopher Tate7fb8b562011-01-20 13:46:41 -0800321 volatile Object mLocalDragState;
Christopher Tatea53146c2010-09-07 11:57:52 -0700322 final PointF mDragPoint = new PointF();
Christopher Tate2c095f32010-10-04 14:13:40 -0700323 final PointF mLastTouchPoint = new PointF();
Igor Murashkina86ab6402013-08-30 12:58:36 -0700324
325 private boolean mProfileRendering;
Romain Guyd0750312012-11-29 11:34:43 -0800326 private Choreographer.FrameCallback mRenderProfiler;
327 private boolean mRenderProfilingEnabled;
Christopher Tatea53146c2010-09-07 11:57:52 -0700328
Chet Haase2f2022a2011-10-11 06:41:59 -0700329 // Variables to track frames per second, enabled via DEBUG_FPS flag
330 private long mFpsStartTime = -1;
331 private long mFpsPrevTime = -1;
332 private int mFpsNumFrames;
333
Jun Mukai1db53972015-09-11 18:08:31 -0700334 private int mPointerIconShape = PointerIcon.STYLE_NOT_SPECIFIED;
335
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 /**
337 * see {@link #playSoundEffect(int)}
338 */
339 AudioManager mAudioManager;
340
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700341 final AccessibilityManager mAccessibilityManager;
342
Gilles Debunne5ac84422011-10-19 09:35:58 -0700343 AccessibilityInteractionController mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700344
345 AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager;
Chris Craikcce47eb2014-07-16 15:12:15 -0700346 HighContrastTextManager mHighContrastTextManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700347
Svetoslav Ganova0156172011-06-26 17:55:44 -0700348 SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700349
Svetoslav Ganov42138042012-03-20 11:51:39 -0700350 HashSet<View> mTempHashSet;
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800351
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700352 private final int mDensity;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700353 private final int mNoncompatDensity;
Adam Powellb08013c2010-09-16 16:28:11 -0700354
Chet Haase97140572012-09-13 14:56:47 -0700355 private boolean mInLayout = false;
356 ArrayList<View> mLayoutRequesters = new ArrayList<View>();
357 boolean mHandlingLayoutInLayoutRequest = false;
358
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700359 private int mViewLayoutDirectionInitial;
Chet Haase97140572012-09-13 14:56:47 -0700360
Craig Mautner8f303ad2013-06-14 11:32:22 -0700361 /** Set to true once doDie() has been called. */
362 private boolean mRemoved;
363
Jeff Brown21bc5c92011-02-28 18:27:14 -0800364 /**
365 * Consistency verifier for debugging purposes.
366 */
367 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
368 InputEventConsistencyVerifier.isInstrumentationEnabled() ?
369 new InputEventConsistencyVerifier(this, 0) : null;
370
Dianne Hackborn9a230e02011-10-06 11:51:27 -0700371 static final class SystemUiVisibilityInfo {
372 int seq;
373 int globalVisibility;
374 int localValue;
375 int localChanges;
376 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700377
Jeff Brown98365d72012-08-19 20:30:52 -0700378 public ViewRootImpl(Context context, Display display) {
Jeff Brownf9e989d2013-04-04 23:04:03 -0700379 mContext = context;
380 mWindowSession = WindowManagerGlobal.getWindowSession();
Jeff Brown98365d72012-08-19 20:30:52 -0700381 mDisplay = display;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800382 mBasePackageName = context.getBasePackageName();
Jeff Brown98365d72012-08-19 20:30:52 -0700383
Craig Mautner48d0d182013-06-11 07:53:06 -0700384 mDisplayAdjustments = display.getDisplayAdjustments();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700385
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 mThread = Thread.currentThread();
387 mLocation = new WindowLeaked(null);
388 mLocation.fillInStackTrace();
389 mWidth = -1;
390 mHeight = -1;
391 mDirty = new Rect();
392 mTempRect = new Rect();
393 mVisRect = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 mWinFrame = new Rect();
Romain Guyfb8b7632010-08-23 21:05:08 -0700395 mWindow = new W(this);
Dianne Hackborn180c4842011-09-13 12:39:25 -0700396 mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 mViewVisibility = View.GONE;
398 mTransparentRegion = new Region();
399 mPreviousTransparentRegion = new Region();
400 mFirst = true; // true for the first time the view is added
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 mAdded = false;
Chris Craikcce47eb2014-07-16 15:12:15 -0700402 mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700403 mAccessibilityManager = AccessibilityManager.getInstance(context);
404 mAccessibilityInteractionConnectionManager =
405 new AccessibilityInteractionConnectionManager();
Svetoslav Ganov00d0c142012-02-24 11:30:49 -0800406 mAccessibilityManager.addAccessibilityStateChangeListener(
407 mAccessibilityInteractionConnectionManager);
Chris Craikcce47eb2014-07-16 15:12:15 -0700408 mHighContrastTextManager = new HighContrastTextManager();
409 mAccessibilityManager.addHighTextContrastStateChangeListener(
410 mHighContrastTextManager);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 mViewConfiguration = ViewConfiguration.get(context);
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700412 mDensity = context.getResources().getDisplayMetrics().densityDpi;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700413 mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
Jorim Jaggib10e33f2015-02-04 21:57:40 +0100414 mFallbackEventHandler = new PhoneFallbackEventHandler(context);
Jeff Brown96e942d2011-11-30 19:55:01 -0800415 mChoreographer = Choreographer.getInstance();
Jeff Brownd912e1f2014-04-11 18:46:22 -0700416 mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
Dianne Hackborna53de062012-05-08 18:53:51 -0700417 loadSystemProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 }
419
Dianne Hackborn2a9094d2010-02-03 19:20:09 -0800420 public static void addFirstDrawHandler(Runnable callback) {
421 synchronized (sFirstDrawHandlers) {
422 if (!sFirstDrawComplete) {
423 sFirstDrawHandlers.add(callback);
424 }
425 }
426 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700427
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800428 public static void addConfigCallback(ComponentCallbacks callback) {
429 synchronized (sConfigCallbacks) {
430 sConfigCallbacks.add(callback);
431 }
432 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700433
Chong Zhangdcee1de2015-10-06 10:26:00 -0700434 public void addWindowCallbacks(WindowCallbacks callback) {
Skuhneb8160872015-09-22 09:51:39 -0700435 if (USE_MT_RENDERER) {
Chong Zhangdcee1de2015-10-06 10:26:00 -0700436 synchronized (mWindowCallbacks) {
437 mWindowCallbacks.add(callback);
Skuhneb8160872015-09-22 09:51:39 -0700438 }
439 }
440 }
441
Chong Zhangdcee1de2015-10-06 10:26:00 -0700442 public void removeWindowCallbacks(WindowCallbacks callback) {
Skuhneb8160872015-09-22 09:51:39 -0700443 if (USE_MT_RENDERER) {
Chong Zhangdcee1de2015-10-06 10:26:00 -0700444 synchronized (mWindowCallbacks) {
445 mWindowCallbacks.remove(callback);
Skuhneb8160872015-09-22 09:51:39 -0700446 }
447 }
448 }
449
Chong Zhang8dbd9ad2015-10-09 10:06:11 -0700450 public void reportDrawFinish() {
451 if (mWindowDrawCountDown != null) {
452 mWindowDrawCountDown.countDown();
453 }
454 }
455
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456 // FIXME for perf testing only
457 private boolean mProfile = false;
458
459 /**
460 * Call this to profile the next traversal call.
461 * FIXME for perf testing only. Remove eventually
462 */
463 public void profile() {
464 mProfile = true;
465 }
466
467 /**
468 * Indicates whether we are in touch mode. Calling this method triggers an IPC
469 * call and should be avoided whenever possible.
470 *
471 * @return True, if the device is in touch mode, false otherwise.
472 *
473 * @hide
474 */
475 static boolean isInTouchMode() {
Jeff Brown98365d72012-08-19 20:30:52 -0700476 IWindowSession windowSession = WindowManagerGlobal.peekWindowSession();
477 if (windowSession != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 try {
Jeff Brown98365d72012-08-19 20:30:52 -0700479 return windowSession.getInTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480 } catch (RemoteException e) {
481 }
482 }
483 return false;
484 }
485
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 /**
487 * We have one child
488 */
Romain Guye4d01122010-06-16 18:44:05 -0700489 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 synchronized (this) {
491 if (mView == null) {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700492 mView = view;
Jeff Brownd912e1f2014-04-11 18:46:22 -0700493
494 mAttachInfo.mDisplayState = mDisplay.getState();
495 mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
496
Fabrice Di Megliob003e282012-10-17 17:20:19 -0700497 mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
Joe Onorato86f67862010-11-05 18:57:34 -0700498 mFallbackEventHandler.setView(view);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700499 mWindowAttributes.copyFrom(attrs);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800500 if (mWindowAttributes.packageName == null) {
501 mWindowAttributes.packageName = mBasePackageName;
502 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700503 attrs = mWindowAttributes;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700504 // Keep track of the actual window flags supplied by the client.
505 mClientWindowLayoutFlags = attrs.flags;
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700506
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700507 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -0700508
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700509 if (view instanceof RootViewSurfaceTaker) {
510 mSurfaceHolderCallback =
511 ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
512 if (mSurfaceHolderCallback != null) {
513 mSurfaceHolder = new TakenSurfaceHolder();
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700514 mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -0700515 }
516 }
Romain Guy1aec9a22011-01-05 09:37:12 -0800517
Alan Viverette49a22e82014-07-12 20:01:27 -0700518 // Compute surface insets required to draw at specified Z value.
519 // TODO: Use real shadow insets for a constant max Z.
Alan Viverette5435a302015-01-29 10:25:34 -0800520 if (!attrs.hasManualSurfaceInsets) {
521 final int surfaceInset = (int) Math.ceil(view.getZ() * 2);
522 attrs.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
523 }
Alan Viverette49a22e82014-07-12 20:01:27 -0700524
Craig Mautner48d0d182013-06-11 07:53:06 -0700525 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
Romain Guy856d4e12011-10-14 15:47:55 -0700526 mTranslator = compatibilityInfo.getTranslator();
527
Romain Guy1aec9a22011-01-05 09:37:12 -0800528 // If the application owns the surface, don't enable hardware acceleration
529 if (mSurfaceHolder == null) {
Romain Guy3b748a42013-04-17 18:54:38 -0700530 enableHardwareAcceleration(attrs);
Romain Guy1aec9a22011-01-05 09:37:12 -0800531 }
532
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700533 boolean restore = false;
Romain Guy35b38ce2009-10-07 13:38:55 -0700534 if (mTranslator != null) {
Romain Guy856d4e12011-10-14 15:47:55 -0700535 mSurface.setCompatibilityTranslator(mTranslator);
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700536 restore = true;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700537 attrs.backup();
538 mTranslator.translateWindowLayout(attrs);
Mitsuru Oshima3d914922009-05-13 22:29:15 -0700539 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700540 if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
541
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700542 if (!compatibilityInfo.supportsScreen()) {
Adam Lesinski95c42972013-10-02 10:13:27 -0700543 attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700544 mLastInCompatMode = true;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700545 }
546
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547 mSoftInputMode = attrs.softInputMode;
548 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -0700549 mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 mAttachInfo.mRootView = view;
Romain Guy35b38ce2009-10-07 13:38:55 -0700551 mAttachInfo.mScalingRequired = mTranslator != null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700552 mAttachInfo.mApplicationScale =
553 mTranslator == null ? 1.0f : mTranslator.applicationScale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800554 if (panelParentView != null) {
555 mAttachInfo.mPanelParentWindowToken
556 = panelParentView.getApplicationWindowToken();
557 }
558 mAdded = true;
559 int res; /* = WindowManagerImpl.ADD_OKAY; */
Romain Guy8506ab42009-06-11 17:35:47 -0700560
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 // Schedule the first layout -before- adding to the window
562 // manager, to make sure we do the relayout before receiving
563 // any other events from the system.
564 requestLayout();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700565 if ((mWindowAttributes.inputFeatures
566 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
567 mInputChannel = new InputChannel();
568 }
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800569 mForceDecorViewVisibility = (mWindowAttributes.privateFlags
570 & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571 try {
Dianne Hackborn180c4842011-09-13 12:39:25 -0700572 mOrigWindowType = mWindowAttributes.type;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700573 mAttachInfo.mRecomputeGlobalAttributes = true;
574 collectViewAttributes();
Jeff Brown98365d72012-08-19 20:30:52 -0700575 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
576 getHostVisibility(), mDisplay.getDisplayId(),
Filip Gruszczynski0ec13282015-06-25 11:26:01 -0700577 mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
578 mAttachInfo.mOutsets, mInputChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 } catch (RemoteException e) {
580 mAdded = false;
581 mView = null;
582 mAttachInfo.mRootView = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700583 mInputChannel = null;
Joe Onorato86f67862010-11-05 18:57:34 -0700584 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700586 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587 throw new RuntimeException("Adding window failed", e);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700588 } finally {
589 if (restore) {
590 attrs.restore();
591 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 }
Igor Murashkina86ab6402013-08-30 12:58:36 -0700593
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700594 if (mTranslator != null) {
595 mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700596 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -0800597 mPendingOverscanInsets.set(0, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 mPendingContentInsets.set(mAttachInfo.mContentInsets);
Adrian Roosfa104232014-06-20 16:10:14 -0700599 mPendingStableInsets.set(mAttachInfo.mStableInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600 mPendingVisibleInsets.set(0, 0, 0, 0);
Dianne Hackborn711e62a2010-11-29 16:38:22 -0800601 if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
Jeff Brown98365d72012-08-19 20:30:52 -0700602 if (res < WindowManagerGlobal.ADD_OKAY) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603 mAttachInfo.mRootView = null;
604 mAdded = false;
Joe Onorato86f67862010-11-05 18:57:34 -0700605 mFallbackEventHandler.setView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606 unscheduleTraversals();
Svetoslav Ganov45a02e02012-06-17 15:07:29 -0700607 setAccessibilityFocus(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 switch (res) {
Jeff Brown98365d72012-08-19 20:30:52 -0700609 case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
610 case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
611 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800612 "Unable to add window -- token " + attrs.token
613 + " is not valid; is your activity running?");
Jeff Brown98365d72012-08-19 20:30:52 -0700614 case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
615 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800616 "Unable to add window -- token " + attrs.token
617 + " is not for an application");
Jeff Brown98365d72012-08-19 20:30:52 -0700618 case WindowManagerGlobal.ADD_APP_EXITING:
619 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800620 "Unable to add window -- app for token " + attrs.token
621 + " is exiting");
Jeff Brown98365d72012-08-19 20:30:52 -0700622 case WindowManagerGlobal.ADD_DUPLICATE_ADD:
623 throw new WindowManager.BadTokenException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800624 "Unable to add window -- window " + mWindow
625 + " has already been added");
Jeff Brown98365d72012-08-19 20:30:52 -0700626 case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800627 // Silently ignore -- we would have just removed it
628 // right away, anyway.
629 return;
Jeff Brown98365d72012-08-19 20:30:52 -0700630 case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
Alan Viverette73f6d602015-09-14 16:01:19 -0400631 throw new WindowManager.BadTokenException("Unable to add window "
632 + mWindow + " -- another window of type "
633 + mWindowAttributes.type + " already exists");
Jeff Brown98365d72012-08-19 20:30:52 -0700634 case WindowManagerGlobal.ADD_PERMISSION_DENIED:
Alan Viverette73f6d602015-09-14 16:01:19 -0400635 throw new WindowManager.BadTokenException("Unable to add window "
636 + mWindow + " -- permission denied for window type "
637 + mWindowAttributes.type);
Craig Mautner6018aee2012-10-23 14:27:49 -0700638 case WindowManagerGlobal.ADD_INVALID_DISPLAY:
Alan Viverette73f6d602015-09-14 16:01:19 -0400639 throw new WindowManager.InvalidDisplayException("Unable to add window "
640 + mWindow + " -- the specified display can not be found");
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800641 case WindowManagerGlobal.ADD_INVALID_TYPE:
Alan Viverette73f6d602015-09-14 16:01:19 -0400642 throw new WindowManager.InvalidDisplayException("Unable to add window "
643 + mWindow + " -- the specified window type "
644 + mWindowAttributes.type + " is not valid");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800645 }
646 throw new RuntimeException(
Wale Ogunwale74bf0652015-01-12 10:24:36 -0800647 "Unable to add window -- unknown error code " + res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700649
Jeff Brown00fa7bd2010-07-02 15:37:36 -0700650 if (view instanceof RootViewSurfaceTaker) {
651 mInputQueueCallback =
652 ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
653 }
Jeff Browncc4f7db2011-08-30 20:34:48 -0700654 if (mInputChannel != null) {
655 if (mInputQueueCallback != null) {
Michael Wrighta44dd262013-04-10 21:12:00 -0700656 mInputQueue = new InputQueue();
Jeff Browncc4f7db2011-08-30 20:34:48 -0700657 mInputQueueCallback.onInputQueueCreated(mInputQueue);
Jeff Browncc4f7db2011-08-30 20:34:48 -0700658 }
Michael Wrighta44dd262013-04-10 21:12:00 -0700659 mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
660 Looper.myLooper());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700661 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700662
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800663 view.assignParent(this);
Jeff Brown98365d72012-08-19 20:30:52 -0700664 mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
665 mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700666
667 if (mAccessibilityManager.isEnabled()) {
668 mAccessibilityInteractionConnectionManager.ensureConnection();
669 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700670
671 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
672 view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
673 }
Michael Wright95ae9422013-03-14 10:58:50 -0700674
Jeff Brownf9e989d2013-04-04 23:04:03 -0700675 // Set up the input pipeline.
676 CharSequence counterSuffix = attrs.getTitle();
Michael Wright899d7052014-04-23 17:23:39 -0700677 mSyntheticInputStage = new SyntheticInputStage();
678 InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
Jeff Brownf9e989d2013-04-04 23:04:03 -0700679 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
680 "aq:native-post-ime:" + counterSuffix);
681 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
682 InputStage imeStage = new ImeInputStage(earlyPostImeStage,
683 "aq:ime:" + counterSuffix);
684 InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
685 InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
686 "aq:native-pre-ime:" + counterSuffix);
687
688 mFirstInputStage = nativePreImeStage;
689 mFirstPostImeInputStage = earlyPostImeStage;
690 mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691 }
692 }
693 }
694
keunyoung30f420f2013-08-02 14:23:10 -0700695 /** Whether the window is in local focus mode or not */
696 private boolean isInLocalFocusMode() {
697 return (mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0;
698 }
699
Dianne Hackborn49b043f2015-05-07 14:21:38 -0700700 public int getWindowFlags() {
701 return mWindowAttributes.flags;
702 }
703
Dianne Hackbornece0f4f2015-06-11 13:29:01 -0700704 public int getDisplayId() {
705 return mDisplay.getDisplayId();
706 }
707
Dianne Hackborna7bb6fb2015-02-03 18:13:40 -0800708 public CharSequence getTitle() {
709 return mWindowAttributes.getTitle();
710 }
711
Romain Guy8ff6b9e2011-11-09 20:10:18 -0800712 void destroyHardwareResources() {
Romain Guy31f2c2e2011-11-21 10:55:41 -0800713 if (mAttachInfo.mHardwareRenderer != null) {
714 mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
John Reckf47a5942014-06-30 16:20:04 -0700715 mAttachInfo.mHardwareRenderer.destroy();
Romain Guy31f2c2e2011-11-21 10:55:41 -0800716 }
717 }
718
Bo Liu845535a2014-03-21 12:06:23 -0700719 public void detachFunctor(long functor) {
John Reck44ac42a2014-05-16 14:46:07 -0700720 if (mAttachInfo.mHardwareRenderer != null) {
721 // Fence so that any pending invokeFunctor() messages will be processed
722 // before we return from detachFunctor.
John Reckf47a5942014-06-30 16:20:04 -0700723 mAttachInfo.mHardwareRenderer.stopDrawing();
John Reck44ac42a2014-05-16 14:46:07 -0700724 }
Romain Guyba6be8a2012-04-23 18:22:09 -0700725 }
726
John Reck3b202512014-06-23 13:13:08 -0700727 /**
728 * Schedules the functor for execution in either kModeProcess or
729 * kModeProcessNoContext, depending on whether or not there is an EGLContext.
730 *
731 * @param functor The native functor to invoke
732 * @param waitForCompletion If true, this will not return until the functor
733 * has invoked. If false, the functor may be invoked
734 * asynchronously.
735 */
Hui Shu9970aee2014-06-23 17:10:30 -0700736 public void invokeFunctor(long functor, boolean waitForCompletion) {
John Reck3b202512014-06-23 13:13:08 -0700737 ThreadedRenderer.invokeFunctor(functor, waitForCompletion);
Bo Liuae738a72014-04-27 16:22:04 -0700738 }
739
John Reck119907c2014-08-14 09:02:01 -0700740 public void registerAnimatingRenderNode(RenderNode animator) {
741 if (mAttachInfo.mHardwareRenderer != null) {
742 mAttachInfo.mHardwareRenderer.registerAnimatingRenderNode(animator);
743 } else {
744 if (mAttachInfo.mPendingAnimatingRenderNodes == null) {
745 mAttachInfo.mPendingAnimatingRenderNodes = new ArrayList<RenderNode>();
746 }
747 mAttachInfo.mPendingAnimatingRenderNodes.add(animator);
748 }
749 }
750
Romain Guy3b748a42013-04-17 18:54:38 -0700751 private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800752 mAttachInfo.mHardwareAccelerated = false;
753 mAttachInfo.mHardwareAccelerationRequested = false;
Romain Guy4f6aff32011-01-12 16:21:41 -0800754
Romain Guy856d4e12011-10-14 15:47:55 -0700755 // Don't enable hardware acceleration when the application is in compatibility mode
John Reckdd58e792014-04-02 16:54:28 +0000756 if (mTranslator != null) return;
Romain Guy856d4e12011-10-14 15:47:55 -0700757
Dianne Hackborn7eec10e2010-11-12 18:03:47 -0800758 // Try to enable hardware acceleration if requested
Igor Murashkina86ab6402013-08-30 12:58:36 -0700759 final boolean hardwareAccelerated =
Jim Miller1b365922011-03-09 19:38:07 -0800760 (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
761
John Reckdd58e792014-04-02 16:54:28 +0000762 if (hardwareAccelerated) {
Romain Guy1af23a32011-03-24 16:03:55 -0700763 if (!HardwareRenderer.isAvailable()) {
Romain Guy1af23a32011-03-24 16:03:55 -0700764 return;
765 }
766
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700767 // Persistent processes (including the system) should not do
768 // accelerated rendering on low-end devices. In that case,
769 // sRendererDisabled will be set. In addition, the system process
770 // itself should never do accelerated rendering. In that case, both
771 // sRendererDisabled and sSystemRendererDisabled are set. When
772 // sSystemRendererDisabled is set, PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED
773 // can be used by code on the system process to escape that and enable
774 // HW accelerated drawing. (This is basically for the lock screen.)
Jim Miller1b365922011-03-09 19:38:07 -0800775
John Reck61375a82014-09-18 19:27:48 +0000776 final boolean fakeHwAccelerated = (attrs.privateFlags &
777 WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
Dianne Hackborn5d927c22011-09-02 12:22:18 -0700778 final boolean forceHwAccelerated = (attrs.privateFlags &
779 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
Jim Miller1b365922011-03-09 19:38:07 -0800780
John Reck61375a82014-09-18 19:27:48 +0000781 if (fakeHwAccelerated) {
782 // This is exclusively for the preview windows the window manager
783 // shows for launching applications, so they will look more like
784 // the app being launched.
785 mAttachInfo.mHardwareAccelerationRequested = true;
786 } else if (!HardwareRenderer.sRendererDisabled
John Reck1dd0e0f2014-08-12 09:27:33 -0700787 || (HardwareRenderer.sSystemRendererDisabled && forceHwAccelerated)) {
Romain Guyb051e892010-09-28 19:09:36 -0700788 if (mAttachInfo.mHardwareRenderer != null) {
John Reckf47a5942014-06-30 16:20:04 -0700789 mAttachInfo.mHardwareRenderer.destroy();
Romain Guy211370f2012-02-01 16:10:55 -0800790 }
791
Alan Viverette2b12b582014-10-29 11:11:40 -0700792 final Rect insets = attrs.surfaceInsets;
Alan Viverette2cd23e62014-11-04 17:04:02 -0800793 final boolean hasSurfaceInsets = insets.left != 0 || insets.right != 0
794 || insets.top != 0 || insets.bottom != 0;
Alan Viverette2b12b582014-10-29 11:11:40 -0700795 final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;
John Reckb8802b12014-06-16 15:28:50 -0700796 mAttachInfo.mHardwareRenderer = HardwareRenderer.create(mContext, translucent);
Romain Guye55945e2013-04-04 15:26:04 -0700797 if (mAttachInfo.mHardwareRenderer != null) {
798 mAttachInfo.mHardwareRenderer.setName(attrs.getTitle().toString());
799 mAttachInfo.mHardwareAccelerated =
800 mAttachInfo.mHardwareAccelerationRequested = true;
801 }
Romain Guye4d01122010-06-16 18:44:05 -0700802 }
803 }
804 }
805
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800806 public View getView() {
807 return mView;
808 }
809
810 final WindowLeaked getLocation() {
811 return mLocation;
812 }
813
814 void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
815 synchronized (this) {
Alan Viverettedbed8932014-08-06 17:54:52 -0700816 final int oldInsetLeft = mWindowAttributes.surfaceInsets.left;
817 final int oldInsetTop = mWindowAttributes.surfaceInsets.top;
818 final int oldInsetRight = mWindowAttributes.surfaceInsets.right;
819 final int oldInsetBottom = mWindowAttributes.surfaceInsets.bottom;
820 final int oldSoftInputMode = mWindowAttributes.softInputMode;
Alan Viverette5435a302015-01-29 10:25:34 -0800821 final boolean oldHasManualSurfaceInsets = mWindowAttributes.hasManualSurfaceInsets;
Alan Viverettedbed8932014-08-06 17:54:52 -0700822
Dianne Hackborn9d090892012-06-11 18:35:41 -0700823 // Keep track of the actual window flags supplied by the client.
824 mClientWindowLayoutFlags = attrs.flags;
Alan Viverettedbed8932014-08-06 17:54:52 -0700825
826 // Preserve compatible window flag if exists.
827 final int compatibleWindowFlag = mWindowAttributes.privateFlags
Adam Lesinski95c42972013-10-02 10:13:27 -0700828 & WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Alan Viverettedbed8932014-08-06 17:54:52 -0700829
830 // Transfer over system UI visibility values as they carry current state.
Craig Mautner3fe38c02012-05-03 17:28:09 -0700831 attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
832 attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
Alan Viverettedbed8932014-08-06 17:54:52 -0700833
Romain Guyf21c9b02011-09-06 16:56:54 -0700834 mWindowAttributesChangesFlag = mWindowAttributes.copyFrom(attrs);
John Spurlockbd957402013-10-03 11:38:39 -0400835 if ((mWindowAttributesChangesFlag
836 & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) {
837 // Recompute system ui visibility.
838 mAttachInfo.mRecomputeGlobalAttributes = true;
839 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800840 if (mWindowAttributes.packageName == null) {
841 mWindowAttributes.packageName = mBasePackageName;
842 }
Adam Lesinski95c42972013-10-02 10:13:27 -0700843 mWindowAttributes.privateFlags |= compatibleWindowFlag;
Dianne Hackborn9d090892012-06-11 18:35:41 -0700844
Alan Viverettedbed8932014-08-06 17:54:52 -0700845 // Restore old surface insets.
846 mWindowAttributes.surfaceInsets.set(
847 oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
Alan Viverette5435a302015-01-29 10:25:34 -0800848 mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
Alan Viverettedbed8932014-08-06 17:54:52 -0700849
Dianne Hackborn9d090892012-06-11 18:35:41 -0700850 applyKeepScreenOnFlag(mWindowAttributes);
851
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852 if (newView) {
853 mSoftInputMode = attrs.softInputMode;
854 requestLayout();
855 }
Alan Viverettedbed8932014-08-06 17:54:52 -0700856
The Android Open Source Project10592532009-03-18 17:39:46 -0700857 // Don't lose the mode we last auto-computed.
Alan Viverettedbed8932014-08-06 17:54:52 -0700858 if ((attrs.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
The Android Open Source Project10592532009-03-18 17:39:46 -0700859 == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
860 mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
861 & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
Alan Viverettedbed8932014-08-06 17:54:52 -0700862 | (oldSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
The Android Open Source Project10592532009-03-18 17:39:46 -0700863 }
Alan Viverettedbed8932014-08-06 17:54:52 -0700864
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800865 mWindowAttributesChanged = true;
866 scheduleTraversals();
867 }
868 }
869
870 void handleAppVisibility(boolean visible) {
871 if (mAppVisible != visible) {
872 mAppVisible = visible;
873 scheduleTraversals();
John Reck73840ea2014-09-22 07:39:18 -0700874 if (!mAppVisible) {
875 WindowManagerGlobal.trimForeground();
876 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800877 }
878 }
879
880 void handleGetNewSurface() {
881 mNewSurfaceNeeded = true;
882 mFullRedrawNeeded = true;
883 scheduleTraversals();
884 }
885
Jeff Brownd912e1f2014-04-11 18:46:22 -0700886 private final DisplayListener mDisplayListener = new DisplayListener() {
887 @Override
888 public void onDisplayChanged(int displayId) {
889 if (mView != null && mDisplay.getDisplayId() == displayId) {
890 final int oldDisplayState = mAttachInfo.mDisplayState;
891 final int newDisplayState = mDisplay.getState();
892 if (oldDisplayState != newDisplayState) {
893 mAttachInfo.mDisplayState = newDisplayState;
Jeff Brownc2932a12014-11-20 18:04:05 -0800894 pokeDrawLockIfNeeded();
Jeff Brownd912e1f2014-04-11 18:46:22 -0700895 if (oldDisplayState != Display.STATE_UNKNOWN) {
896 final int oldScreenState = toViewScreenState(oldDisplayState);
897 final int newScreenState = toViewScreenState(newDisplayState);
898 if (oldScreenState != newScreenState) {
899 mView.dispatchScreenStateChanged(newScreenState);
900 }
901 if (oldDisplayState == Display.STATE_OFF) {
902 // Draw was suppressed so we need to for it to happen here.
903 mFullRedrawNeeded = true;
904 scheduleTraversals();
905 }
906 }
907 }
Romain Guy7e4e5612012-03-05 14:37:29 -0800908 }
909 }
Jeff Brownd912e1f2014-04-11 18:46:22 -0700910
911 @Override
912 public void onDisplayRemoved(int displayId) {
913 }
914
915 @Override
916 public void onDisplayAdded(int displayId) {
917 }
918
919 private int toViewScreenState(int displayState) {
920 return displayState == Display.STATE_OFF ?
921 View.SCREEN_STATE_OFF : View.SCREEN_STATE_ON;
922 }
923 };
Romain Guy7e4e5612012-03-05 14:37:29 -0800924
Jeff Brownc2932a12014-11-20 18:04:05 -0800925 void pokeDrawLockIfNeeded() {
926 final int displayState = mAttachInfo.mDisplayState;
927 if (mView != null && mAdded && mTraversalScheduled
928 && (displayState == Display.STATE_DOZE
929 || displayState == Display.STATE_DOZE_SUSPEND)) {
930 try {
931 mWindowSession.pokeDrawLock(mWindow);
932 } catch (RemoteException ex) {
933 // System server died, oh well.
934 }
935 }
936 }
937
Craig Mautner6018aee2012-10-23 14:27:49 -0700938 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700939 public void requestFitSystemWindows() {
940 checkThread();
Adrian Roosfa104232014-06-20 16:10:14 -0700941 mApplyInsetsRequested = true;
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700942 scheduleTraversals();
943 }
944
Craig Mautner6018aee2012-10-23 14:27:49 -0700945 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800946 public void requestLayout() {
Chet Haase3efa7b52012-12-03 08:33:17 -0800947 if (!mHandlingLayoutInLayoutRequest) {
948 checkThread();
949 mLayoutRequested = true;
950 scheduleTraversals();
951 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 }
953
Craig Mautner6018aee2012-10-23 14:27:49 -0700954 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800955 public boolean isLayoutRequested() {
956 return mLayoutRequested;
957 }
958
Romain Guycfef1232012-02-23 13:50:37 -0800959 void invalidate() {
960 mDirty.set(0, 0, mWidth, mHeight);
John Recke4267ea2014-06-03 15:53:15 -0700961 if (!mWillDrawSoon) {
962 scheduleTraversals();
963 }
Romain Guycfef1232012-02-23 13:50:37 -0800964 }
965
Dianne Hackborna53de062012-05-08 18:53:51 -0700966 void invalidateWorld(View view) {
967 view.invalidate();
968 if (view instanceof ViewGroup) {
Romain Guyf84208f2012-09-13 22:50:18 -0700969 ViewGroup parent = (ViewGroup) view;
970 for (int i = 0; i < parent.getChildCount(); i++) {
Dianne Hackborna53de062012-05-08 18:53:51 -0700971 invalidateWorld(parent.getChildAt(i));
972 }
973 }
974 }
975
Craig Mautner6018aee2012-10-23 14:27:49 -0700976 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800977 public void invalidateChild(View child, Rect dirty) {
Romain Guycfef1232012-02-23 13:50:37 -0800978 invalidateChildInParent(null, dirty);
979 }
980
Craig Mautner8f303ad2013-06-14 11:32:22 -0700981 @Override
Romain Guycfef1232012-02-23 13:50:37 -0800982 public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 checkThread();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700984 if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
Romain Guycfef1232012-02-23 13:50:37 -0800985
Chet Haase70d4ba12010-10-06 09:46:45 -0700986 if (dirty == null) {
Chet Haase70d4ba12010-10-06 09:46:45 -0700987 invalidate();
Romain Guycfef1232012-02-23 13:50:37 -0800988 return null;
Chet Haase3561d062012-10-23 12:54:51 -0700989 } else if (dirty.isEmpty() && !mIsAnimating) {
Chet Haase05e91ed2012-07-03 14:17:57 -0700990 return null;
Chet Haase70d4ba12010-10-06 09:46:45 -0700991 }
Romain Guycfef1232012-02-23 13:50:37 -0800992
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700993 if (mCurScrollY != 0 || mTranslator != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 mTempRect.set(dirty);
Romain Guy1e095972009-07-07 11:22:45 -0700995 dirty = mTempRect;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700996 if (mCurScrollY != 0) {
Romain Guycfef1232012-02-23 13:50:37 -0800997 dirty.offset(0, -mCurScrollY);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700998 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700999 if (mTranslator != null) {
Romain Guy1e095972009-07-07 11:22:45 -07001000 mTranslator.translateRectInAppWindowToScreen(dirty);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001001 }
Romain Guy1e095972009-07-07 11:22:45 -07001002 if (mAttachInfo.mScalingRequired) {
1003 dirty.inset(-1, -1);
1004 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005 }
Romain Guycfef1232012-02-23 13:50:37 -08001006
Alan Viverettea7ea65e2015-05-15 11:30:21 -07001007 invalidateRectOnScreen(dirty);
1008
1009 return null;
1010 }
1011
1012 private void invalidateRectOnScreen(Rect dirty) {
Romain Guycfef1232012-02-23 13:50:37 -08001013 final Rect localDirty = mDirty;
1014 if (!localDirty.isEmpty() && !localDirty.contains(dirty)) {
Romain Guy02ccac62011-06-24 13:20:23 -07001015 mAttachInfo.mSetIgnoreDirtyState = true;
Romain Guy7d695942010-12-01 17:22:29 -08001016 mAttachInfo.mIgnoreDirtyState = true;
1017 }
Romain Guycfef1232012-02-23 13:50:37 -08001018
1019 // Add the new dirty rect to the current one
1020 localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom);
1021 // Intersect with the bounds of the window to skip
1022 // updates that lie outside of the visible region
Romain Guy7b2f8b82012-03-19 17:18:54 -07001023 final float appScale = mAttachInfo.mApplicationScale;
Chet Haase3561d062012-10-23 12:54:51 -07001024 final boolean intersected = localDirty.intersect(0, 0,
1025 (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
1026 if (!intersected) {
Chet Haaseb78ee0e2012-10-17 11:32:01 -07001027 localDirty.setEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 }
Chet Haase3561d062012-10-23 12:54:51 -07001029 if (!mWillDrawSoon && (intersected || mIsAnimating)) {
1030 scheduleTraversals();
1031 }
Romain Guy0d9275e2010-10-26 14:22:30 -07001032 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033
George Mount41725de2015-04-09 08:23:05 -07001034 void setWindowStopped(boolean stopped) {
Dianne Hackbornce418e62011-03-01 14:31:38 -08001035 if (mStopped != stopped) {
1036 mStopped = stopped;
George Mount41725de2015-04-09 08:23:05 -07001037 if (!mStopped) {
Dianne Hackbornce418e62011-03-01 14:31:38 -08001038 scheduleTraversals();
1039 }
1040 }
1041 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001042
George Mount41725de2015-04-09 08:23:05 -07001043 /**
1044 * Block the input events during an Activity Transition. The KEYCODE_BACK event is allowed
1045 * through to allow quick reversal of the Activity Transition.
1046 *
1047 * @param paused true to pause, false to resume.
1048 */
1049 public void setPausedForTransition(boolean paused) {
1050 mPausedForTransition = paused;
1051 }
1052
Craig Mautner8f303ad2013-06-14 11:32:22 -07001053 @Override
Romain Guycfef1232012-02-23 13:50:37 -08001054 public ViewParent getParent() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 return null;
1056 }
1057
Craig Mautner8f303ad2013-06-14 11:32:22 -07001058 @Override
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001059 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001060 if (child != mView) {
1061 throw new RuntimeException("child is not mine, honest!");
1062 }
1063 // Note: don't apply scroll offset, because we want to know its
1064 // visibility in the virtual canvas being given to the view hierarchy.
1065 return r.intersect(0, 0, mWidth, mHeight);
1066 }
1067
Igor Murashkina86ab6402013-08-30 12:58:36 -07001068 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001069 public void bringChildToFront(View child) {
1070 }
1071
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 int getHostVisibility() {
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08001073 return (mAppVisible || mForceDecorViewVisibility) ? mView.getVisibility() : View.GONE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 }
Romain Guy8506ab42009-06-11 17:35:47 -07001075
Chet Haasecca2c982011-05-20 14:34:18 -07001076 /**
1077 * Add LayoutTransition to the list of transitions to be started in the next traversal.
1078 * This list will be cleared after the transitions on the list are start()'ed. These
1079 * transitionsa re added by LayoutTransition itself when it sets up animations. The setup
1080 * happens during the layout phase of traversal, which we want to complete before any of the
1081 * animations are started (because those animations may side-effect properties that layout
1082 * depends upon, like the bounding rectangles of the affected views). So we add the transition
1083 * to the list and it is started just prior to starting the drawing phase of traversal.
1084 *
1085 * @param transition The LayoutTransition to be started on the next traversal.
1086 *
1087 * @hide
1088 */
1089 public void requestTransitionStart(LayoutTransition transition) {
1090 if (mPendingTransitions == null || !mPendingTransitions.contains(transition)) {
1091 if (mPendingTransitions == null) {
1092 mPendingTransitions = new ArrayList<LayoutTransition>();
1093 }
1094 mPendingTransitions.add(transition);
1095 }
1096 }
1097
John Recka5dda642014-05-22 15:43:54 -07001098 /**
1099 * Notifies the HardwareRenderer that a new frame will be coming soon.
1100 * Currently only {@link ThreadedRenderer} cares about this, and uses
1101 * this knowledge to adjust the scheduling of off-thread animations
1102 */
1103 void notifyRendererOfFramePending() {
1104 if (mAttachInfo.mHardwareRenderer != null) {
1105 mAttachInfo.mHardwareRenderer.notifyFramePending();
1106 }
1107 }
1108
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001109 void scheduleTraversals() {
1110 if (!mTraversalScheduled) {
1111 mTraversalScheduled = true;
Jeff Brown3d4e7efe2015-02-26 15:34:16 -08001112 mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001113 mChoreographer.postCallback(
1114 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
Michael Wright9d744c72014-02-18 21:27:42 -08001115 if (!mUnbufferedInputDispatch) {
1116 scheduleConsumeBatchedInput();
1117 }
John Recka5dda642014-05-22 15:43:54 -07001118 notifyRendererOfFramePending();
Jeff Brownc2932a12014-11-20 18:04:05 -08001119 pokeDrawLockIfNeeded();
Jeff Brown96e942d2011-11-30 19:55:01 -08001120 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001121 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001122
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001123 void unscheduleTraversals() {
1124 if (mTraversalScheduled) {
1125 mTraversalScheduled = false;
Jeff Brown3d4e7efe2015-02-26 15:34:16 -08001126 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001127 mChoreographer.removeCallbacks(
1128 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
1129 }
1130 }
1131
1132 void doTraversal() {
1133 if (mTraversalScheduled) {
1134 mTraversalScheduled = false;
Jeff Brown3d4e7efe2015-02-26 15:34:16 -08001135 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001136
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001137 if (mProfile) {
1138 Debug.startMethodTracing("ViewAncestor");
Jeff Brown96e942d2011-11-30 19:55:01 -08001139 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001140
Chris Craike22c59b2015-05-21 18:33:37 -07001141 performTraversals();
Jeff Brown96e942d2011-11-30 19:55:01 -08001142
Jeff Brownebb2d8d2012-03-23 17:14:34 -07001143 if (mProfile) {
1144 Debug.stopMethodTracing();
1145 mProfile = false;
1146 }
Jeff Brown96e942d2011-11-30 19:55:01 -08001147 }
1148 }
1149
Dianne Hackborn9d090892012-06-11 18:35:41 -07001150 private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) {
1151 // Update window's global keep screen on flag: if a view has requested
1152 // that the screen be kept on, then it is always set; otherwise, it is
1153 // set to whatever the client last requested for the global state.
1154 if (mAttachInfo.mKeepScreenOn) {
1155 params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
1156 } else {
1157 params.flags = (params.flags&~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
1158 | (mClientWindowLayoutFlags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1159 }
1160 }
1161
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001162 private boolean collectViewAttributes() {
Chris Craikd36a81f2014-07-17 10:16:51 -07001163 if (mAttachInfo.mRecomputeGlobalAttributes) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001164 //Log.i(TAG, "Computing view hierarchy attributes!");
Chris Craikd36a81f2014-07-17 10:16:51 -07001165 mAttachInfo.mRecomputeGlobalAttributes = false;
1166 boolean oldScreenOn = mAttachInfo.mKeepScreenOn;
1167 mAttachInfo.mKeepScreenOn = false;
1168 mAttachInfo.mSystemUiVisibility = 0;
1169 mAttachInfo.mHasSystemUiListeners = false;
1170 mView.dispatchCollectViewAttributes(mAttachInfo, 0);
1171 mAttachInfo.mSystemUiVisibility &= ~mAttachInfo.mDisabledSystemUiVisibility;
Craig Mautner7eac0f52012-09-13 13:14:14 -07001172 WindowManager.LayoutParams params = mWindowAttributes;
Chris Craikd36a81f2014-07-17 10:16:51 -07001173 mAttachInfo.mSystemUiVisibility |= getImpliedSystemUiVisibility(params);
1174 if (mAttachInfo.mKeepScreenOn != oldScreenOn
1175 || mAttachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
1176 || mAttachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
Dianne Hackborn9d090892012-06-11 18:35:41 -07001177 applyKeepScreenOnFlag(params);
Chris Craikd36a81f2014-07-17 10:16:51 -07001178 params.subtreeSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
1179 params.hasSystemUiListeners = mAttachInfo.mHasSystemUiListeners;
1180 mView.dispatchWindowSystemUiVisiblityChanged(mAttachInfo.mSystemUiVisibility);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001181 return true;
1182 }
1183 }
1184 return false;
1185 }
1186
John Spurlockbd957402013-10-03 11:38:39 -04001187 private int getImpliedSystemUiVisibility(WindowManager.LayoutParams params) {
1188 int vis = 0;
1189 // Translucent decor window flags imply stable system ui visibility.
1190 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) != 0) {
1191 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
1192 }
1193 if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) != 0) {
1194 vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
1195 }
1196 return vis;
1197 }
1198
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001199 private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
1200 final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
1201 int childWidthMeasureSpec;
1202 int childHeightMeasureSpec;
1203 boolean windowSizeMayChange = false;
1204
1205 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
1206 "Measuring " + host + " in display " + desiredWindowWidth
1207 + "x" + desiredWindowHeight + "...");
1208
1209 boolean goodMeasure = false;
1210 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
1211 // On large screens, we don't want to allow dialogs to just
1212 // stretch to fill the entire width of the screen to display
1213 // one line of text. First try doing the layout at a smaller
1214 // size to see if it will fit.
1215 final DisplayMetrics packageMetrics = res.getDisplayMetrics();
1216 res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
1217 int baseSize = 0;
1218 if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
1219 baseSize = (int)mTmpValue.getDimension(packageMetrics);
1220 }
1221 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize);
1222 if (baseSize != 0 && desiredWindowWidth > baseSize) {
1223 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
1224 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001225 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001226 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
1227 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1228 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1229 goodMeasure = true;
1230 } else {
1231 // Didn't fit in that size... try expanding a bit.
1232 baseSize = (baseSize+desiredWindowWidth)/2;
1233 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
1234 + baseSize);
1235 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001236 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001237 if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
1238 + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
1239 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
1240 if (DEBUG_DIALOG) Log.v(TAG, "Good!");
1241 goodMeasure = true;
1242 }
1243 }
1244 }
1245 }
1246
1247 if (!goodMeasure) {
1248 childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
1249 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001250 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001251 if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
1252 windowSizeMayChange = true;
1253 }
1254 }
1255
1256 if (DBG) {
1257 System.out.println("======================================");
1258 System.out.println("performTraversals -- after measure");
1259 host.debug();
1260 }
1261
1262 return windowSizeMayChange;
1263 }
1264
Alan Viverettefed3f722013-11-14 14:48:20 -08001265 /**
1266 * Modifies the input matrix such that it maps view-local coordinates to
1267 * on-screen coordinates.
1268 *
1269 * @param m input matrix to modify
1270 */
1271 void transformMatrixToGlobal(Matrix m) {
Dake Gu7bf379c2014-07-15 16:29:38 -07001272 m.preTranslate(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
Alan Viverettefed3f722013-11-14 14:48:20 -08001273 }
1274
1275 /**
1276 * Modifies the input matrix such that it maps on-screen coordinates to
1277 * view-local coordinates.
1278 *
1279 * @param m input matrix to modify
1280 */
1281 void transformMatrixToLocal(Matrix m) {
Dake Gu7bf379c2014-07-15 16:29:38 -07001282 m.postTranslate(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
Alan Viverettefed3f722013-11-14 14:48:20 -08001283 }
1284
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001285 /* package */ WindowInsets getWindowInsets(boolean forceConstruct) {
1286 if (mLastWindowInsets == null || forceConstruct) {
1287 mDispatchContentInsets.set(mAttachInfo.mContentInsets);
1288 mDispatchStableInsets.set(mAttachInfo.mStableInsets);
1289 Rect contentInsets = mDispatchContentInsets;
1290 Rect stableInsets = mDispatchStableInsets;
1291 // For dispatch we preserve old logic, but for direct requests from Views we allow to
1292 // immediately use pending insets.
1293 if (!forceConstruct
1294 && (!mPendingContentInsets.equals(contentInsets) ||
1295 !mPendingStableInsets.equals(stableInsets))) {
1296 contentInsets = mPendingContentInsets;
1297 stableInsets = mPendingStableInsets;
1298 }
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001299 Rect outsets = mAttachInfo.mOutsets;
1300 if (outsets.left > 0 || outsets.top > 0 || outsets.right > 0 || outsets.bottom > 0) {
1301 contentInsets = new Rect(contentInsets.left + outsets.left,
1302 contentInsets.top + outsets.top, contentInsets.right + outsets.right,
1303 contentInsets.bottom + outsets.bottom);
1304 }
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001305 mLastWindowInsets = new WindowInsets(contentInsets,
Adam Powell01f280d2015-05-18 16:07:42 -07001306 null /* windowDecorInsets */, stableInsets,
1307 mContext.getResources().getConfiguration().isScreenRound());
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001308 }
1309 return mLastWindowInsets;
1310 }
1311
Adam Powell2accbf92014-04-16 23:14:57 +00001312 void dispatchApplyInsets(View host) {
Filip Gruszczynski954289d2015-02-26 15:46:47 -08001313 host.dispatchApplyWindowInsets(getWindowInsets(true /* forceConstruct */));
Adam Powell2accbf92014-04-16 23:14:57 +00001314 }
1315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001316 private void performTraversals() {
1317 // cache mView since it is used so much below...
1318 final View host = mView;
1319
1320 if (DBG) {
1321 System.out.println("======================================");
1322 System.out.println("performTraversals");
1323 host.debug();
1324 }
1325
1326 if (host == null || !mAdded)
1327 return;
1328
Craig Mautnerdf2390a2012-08-29 20:59:22 -07001329 mIsInTraversal = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001330 mWillDrawSoon = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001331 boolean windowSizeMayChange = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001332 boolean newSurface = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001333 boolean surfaceChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001334 WindowManager.LayoutParams lp = mWindowAttributes;
1335
1336 int desiredWindowWidth;
1337 int desiredWindowHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001338
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001339 final int viewVisibility = getHostVisibility();
1340 boolean viewVisibilityChanged = mViewVisibility != viewVisibility
1341 || mNewSurfaceNeeded;
1342
1343 WindowManager.LayoutParams params = null;
1344 if (mWindowAttributesChanged) {
1345 mWindowAttributesChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001346 surfaceChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001347 params = lp;
1348 }
Craig Mautner48d0d182013-06-11 07:53:06 -07001349 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001350 if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
1351 params = lp;
Jeff Brown96e942d2011-11-30 19:55:01 -08001352 mFullRedrawNeeded = true;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001353 mLayoutRequested = true;
1354 if (mLastInCompatMode) {
Adam Lesinski95c42972013-10-02 10:13:27 -07001355 params.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001356 mLastInCompatMode = false;
1357 } else {
Adam Lesinski95c42972013-10-02 10:13:27 -07001358 params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001359 mLastInCompatMode = true;
1360 }
1361 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001362
Romain Guyf21c9b02011-09-06 16:56:54 -07001363 mWindowAttributesChangesFlag = 0;
Igor Murashkina86ab6402013-08-30 12:58:36 -07001364
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001365 Rect frame = mWinFrame;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366 if (mFirst) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001367 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001368 mLayoutRequested = true;
1369
John Spurlockf8508272013-10-14 21:06:52 -04001370 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL
1371 || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
Dianne Hackborna239c842011-06-01 12:28:20 -07001372 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001373 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001374 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001375 desiredWindowWidth = size.x;
1376 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001377 } else {
1378 DisplayMetrics packageMetrics =
1379 mView.getContext().getResources().getDisplayMetrics();
1380 desiredWindowWidth = packageMetrics.widthPixels;
1381 desiredWindowHeight = packageMetrics.heightPixels;
1382 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001383
Romain Guyc5d55862011-01-21 19:01:46 -08001384 // We used to use the following condition to choose 32 bits drawing caches:
1385 // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
1386 // However, windows are now always 32 bits by default, so choose 32 bits
Chris Craikd36a81f2014-07-17 10:16:51 -07001387 mAttachInfo.mUse32BitDrawingCache = true;
1388 mAttachInfo.mHasWindowFocus = false;
1389 mAttachInfo.mWindowVisibility = viewVisibility;
1390 mAttachInfo.mRecomputeGlobalAttributes = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001391 viewVisibilityChanged = false;
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001392 mLastConfiguration.setTo(host.getResources().getConfiguration());
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001393 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Fabrice Di Megliob003e282012-10-17 17:20:19 -07001394 // Set the layout direction if it has not been set before (inherit is the default)
1395 if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
1396 host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
1397 }
Chris Craikd36a81f2014-07-17 10:16:51 -07001398 host.dispatchAttachedToWindow(mAttachInfo, 0);
1399 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
Adam Powell2accbf92014-04-16 23:14:57 +00001400 dispatchApplyInsets(host);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401 //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
svetoslavganov75986cf2009-05-14 22:28:01 -07001402
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001403 } else {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001404 desiredWindowWidth = frame.width();
1405 desiredWindowHeight = frame.height();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001406 if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07001407 if (DEBUG_ORIENTATION) Log.v(TAG,
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001408 "View " + host + " resized to: " + frame);
Jeff Brown96e942d2011-11-30 19:55:01 -08001409 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001410 mLayoutRequested = true;
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001411 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001412 }
1413 }
1414
1415 if (viewVisibilityChanged) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001416 mAttachInfo.mWindowVisibility = viewVisibility;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001417 host.dispatchWindowVisibilityChanged(viewVisibility);
1418 if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
Skuhneb8160872015-09-22 09:51:39 -07001419 endDragResizing();
Romain Guy65b345f2011-07-27 18:51:50 -07001420 destroyHardwareResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001421 }
1422 if (viewVisibility == View.GONE) {
1423 // After making a window gone, we will count it as being
1424 // shown for the first time the next time it gets focus.
1425 mHasHadWindowFocus = false;
1426 }
1427 }
1428
Alan Viverette7dbc3bf2015-01-28 16:14:36 -08001429 // Non-visible windows can't hold accessibility focus.
1430 if (mAttachInfo.mWindowVisibility != View.VISIBLE) {
1431 host.clearAccessibilityFocus();
1432 }
1433
Chet Haaseb78c2842012-04-19 13:39:50 -07001434 // Execute enqueued actions on every traversal in case a detached view enqueued an action
Chris Craikd36a81f2014-07-17 10:16:51 -07001435 getRunQueue().executeActions(mAttachInfo.mHandler);
Chet Haaseb78c2842012-04-19 13:39:50 -07001436
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001437 boolean insetsChanged = false;
Romain Guy8506ab42009-06-11 17:35:47 -07001438
Craig Mautner72d6f212015-02-19 16:33:09 -08001439 boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001440 if (layoutRequested) {
Romain Guy15df6702009-08-17 20:17:30 -07001441
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001442 final Resources res = mView.getContext().getResources();
1443
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001444 if (mFirst) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001445 // make sure touch mode code executes by setting cached value
1446 // to opposite of the added touch mode.
1447 mAttachInfo.mInTouchMode = !mAddedTouchMode;
Romain Guy2d4cff62010-04-09 15:39:00 -07001448 ensureTouchModeLocally(mAddedTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001449 } else {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001450 if (!mPendingOverscanInsets.equals(mAttachInfo.mOverscanInsets)) {
1451 insetsChanged = true;
1452 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001453 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001454 insetsChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001455 }
Adrian Roosfa104232014-06-20 16:10:14 -07001456 if (!mPendingStableInsets.equals(mAttachInfo.mStableInsets)) {
1457 insetsChanged = true;
1458 }
Dianne Hackbornfa6b35b2011-08-24 17:03:54 -07001459 if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1461 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1462 + mAttachInfo.mVisibleInsets);
1463 }
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001464 if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) {
1465 insetsChanged = true;
1466 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001467 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
1468 || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
Dianne Hackborn711e62a2010-11-29 16:38:22 -08001469 windowSizeMayChange = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001470
John Spurlockf8508272013-10-14 21:06:52 -04001471 if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL
1472 || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
Dianne Hackborna239c842011-06-01 12:28:20 -07001473 // NOTE -- system code, won't try to do compat mode.
Jeff Brownbc68a592011-07-25 12:58:12 -07001474 Point size = new Point();
Jeff Brown98365d72012-08-19 20:30:52 -07001475 mDisplay.getRealSize(size);
Jeff Brownbc68a592011-07-25 12:58:12 -07001476 desiredWindowWidth = size.x;
1477 desiredWindowHeight = size.y;
Dianne Hackborna239c842011-06-01 12:28:20 -07001478 } else {
1479 DisplayMetrics packageMetrics = res.getDisplayMetrics();
1480 desiredWindowWidth = packageMetrics.widthPixels;
1481 desiredWindowHeight = packageMetrics.heightPixels;
1482 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001483 }
1484 }
1485
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486 // Ask host how big it wants to be
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001487 windowSizeMayChange |= measureHierarchy(host, lp, res,
1488 desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 }
1490
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001491 if (collectViewAttributes()) {
1492 params = lp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001493 }
Chris Craikd36a81f2014-07-17 10:16:51 -07001494 if (mAttachInfo.mForceReportNewAttributes) {
1495 mAttachInfo.mForceReportNewAttributes = false;
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001496 params = lp;
1497 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001498
Chris Craikd36a81f2014-07-17 10:16:51 -07001499 if (mFirst || mAttachInfo.mViewVisibilityChanged) {
1500 mAttachInfo.mViewVisibilityChanged = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001501 int resizeMode = mSoftInputMode &
1502 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
1503 // If we are in auto resize mode, then we need to determine
1504 // what mode to use now.
1505 if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001506 final int N = mAttachInfo.mScrollContainers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001507 for (int i=0; i<N; i++) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001508 if (mAttachInfo.mScrollContainers.get(i).isShown()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001509 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
1510 }
1511 }
1512 if (resizeMode == 0) {
1513 resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
1514 }
1515 if ((lp.softInputMode &
1516 WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) {
1517 lp.softInputMode = (lp.softInputMode &
1518 ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) |
1519 resizeMode;
1520 params = lp;
1521 }
1522 }
1523 }
Romain Guy8506ab42009-06-11 17:35:47 -07001524
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001525 if (params != null) {
1526 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
1527 if (!PixelFormat.formatHasAlpha(params.format)) {
1528 params.format = PixelFormat.TRANSLUCENT;
1529 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001530 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001531 mAttachInfo.mOverscanRequested = (params.flags
1532 & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001533 }
1534
Adrian Roosfa104232014-06-20 16:10:14 -07001535 if (mApplyInsetsRequested) {
1536 mApplyInsetsRequested = false;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001537 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Adam Powell2accbf92014-04-16 23:14:57 +00001538 dispatchApplyInsets(host);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001539 if (mLayoutRequested) {
1540 // Short-circuit catching a new layout request here, so
1541 // we don't need to go through two layout passes when things
1542 // change due to fitting system windows, which can happen a lot.
1543 windowSizeMayChange |= measureHierarchy(host, lp,
1544 mView.getContext().getResources(),
1545 desiredWindowWidth, desiredWindowHeight);
1546 }
1547 }
1548
1549 if (layoutRequested) {
1550 // Clear this now, so that if anything requests a layout in the
1551 // rest of this function we will catch it and re-run a full
1552 // layout pass.
1553 mLayoutRequested = false;
1554 }
1555
1556 boolean windowShouldResize = layoutRequested && windowSizeMayChange
Dianne Hackborn189ee182010-12-02 21:48:53 -08001557 && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
Romain Guy2e4f4262010-04-06 11:07:52 -07001558 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
1559 frame.width() < desiredWindowWidth && frame.width() != mWidth)
1560 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
1561 frame.height() < desiredWindowHeight && frame.height() != mHeight));
Chong Zhang0275e392015-09-17 10:41:44 -07001562 windowShouldResize |= mDragResizing;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001563
Jorim Jaggia7262a82015-11-03 15:15:40 +01001564 // If the backdrop frame doesn't equal to a frame, we are starting a resize operation, so
1565 // force it to be resized.
1566 windowShouldResize |= !mPendingBackDropFrame.equals(mWinFrame);
1567
Jeff Brown2e05ec32013-09-30 15:57:43 -07001568 // Determine whether to compute insets.
1569 // If there are no inset listeners remaining then we may still need to compute
1570 // insets in case the old insets were non-empty and must be reset.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001571 final boolean computesInternalInsets =
Chris Craikd36a81f2014-07-17 10:16:51 -07001572 mAttachInfo.mTreeObserver.hasComputeInternalInsetsListeners()
1573 || mAttachInfo.mHasNonEmptyGivenInternalInsets;
Romain Guy812ccbe2010-06-01 14:07:24 -07001574
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001575 boolean insetsPending = false;
1576 int relayoutResult = 0;
Romain Guy812ccbe2010-06-01 14:07:24 -07001577
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08001578 final boolean isViewVisible = viewVisibility == View.VISIBLE;
Romain Guy812ccbe2010-06-01 14:07:24 -07001579 if (mFirst || windowShouldResize || insetsChanged ||
1580 viewVisibilityChanged || params != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001581
Alan Viverette64bf97a2015-09-18 16:42:00 -04001582 if (isViewVisible) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001583 // If this window is giving internal insets to the window
1584 // manager, and it is being added or changing its visibility,
1585 // then we want to first give the window manager "fake"
1586 // insets to cause it to effectively ignore the content of
1587 // the window during layout. This avoids it briefly causing
1588 // other windows to resize/move based on the raw frame of the
1589 // window, waiting until we can finish laying out this window
1590 // and get back to the window manager with the ultimately
1591 // computed insets.
Romain Guy812ccbe2010-06-01 14:07:24 -07001592 insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001593 }
1594
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001595 if (mSurfaceHolder != null) {
1596 mSurfaceHolder.mSurfaceLock.lock();
1597 mDrawingAllowed = true;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001598 }
Romain Guy812ccbe2010-06-01 14:07:24 -07001599
Romain Guyc361da82010-10-25 15:29:10 -07001600 boolean hwInitialized = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001601 boolean contentInsetsChanged = false;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001602 boolean hadSurface = mSurface.isValid();
Romain Guy812ccbe2010-06-01 14:07:24 -07001603
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604 try {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001605 if (DEBUG_LAYOUT) {
Dianne Hackborn189ee182010-12-02 21:48:53 -08001606 Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" +
1607 host.getMeasuredHeight() + ", params=" + params);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001608 }
Romain Guy2a83f002011-01-18 18:28:21 -08001609
John Reckf7d9c1d2014-04-09 10:01:03 -07001610 if (mAttachInfo.mHardwareRenderer != null) {
1611 // relayoutWindow may decide to destroy mSurface. As that decision
1612 // happens in WindowManager service, we need to be defensive here
1613 // and stop using the surface in case it gets destroyed.
John Reck01a5ea32014-12-03 13:01:07 -08001614 if (mAttachInfo.mHardwareRenderer.pauseSurface(mSurface)) {
1615 // Animations were running so we need to push a frame
1616 // to resume them
1617 mDirty.set(0, 0, mWidth, mHeight);
1618 }
John Reckba6adf62015-02-19 14:36:50 -08001619 mChoreographer.mFrameInfo.addFlags(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED);
John Reckf7d9c1d2014-04-09 10:01:03 -07001620 }
Romain Guy2a83f002011-01-18 18:28:21 -08001621 final int surfaceGenerationId = mSurface.getGenerationId();
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001622 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
1623
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001624 if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001625 + " overscan=" + mPendingOverscanInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001626 + " content=" + mPendingContentInsets.toShortString()
1627 + " visible=" + mPendingVisibleInsets.toShortString()
Adrian Roosfa104232014-06-20 16:10:14 -07001628 + " visible=" + mPendingStableInsets.toShortString()
Filip Gruszczynski0ec13282015-06-25 11:26:01 -07001629 + " outsets=" + mPendingOutsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001630 + " surface=" + mSurface);
Romain Guy8506ab42009-06-11 17:35:47 -07001631
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001632 if (mPendingConfiguration.seq != 0) {
1633 if (DEBUG_CONFIGURATION) Log.v(TAG, "Visible with new config: "
1634 + mPendingConfiguration);
riddle_hsu164725c2015-11-12 14:07:12 +08001635 updateConfiguration(new Configuration(mPendingConfiguration), !mFirst);
Dianne Hackborn694f79b2010-03-17 19:44:59 -07001636 mPendingConfiguration.seq = 0;
1637 }
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001638
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001639 final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
1640 mAttachInfo.mOverscanInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001641 contentInsetsChanged = !mPendingContentInsets.equals(
1642 mAttachInfo.mContentInsets);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001643 final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001644 mAttachInfo.mVisibleInsets);
Adrian Roosfa104232014-06-20 16:10:14 -07001645 final boolean stableInsetsChanged = !mPendingStableInsets.equals(
1646 mAttachInfo.mStableInsets);
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001647 final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets);
Chong Zhangf4abc2b2015-11-12 23:40:58 -08001648 final boolean surfaceSizeChanged = (relayoutResult
1649 & WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001650 if (contentInsetsChanged) {
1651 mAttachInfo.mContentInsets.set(mPendingContentInsets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001652 if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
1653 + mAttachInfo.mContentInsets);
1654 }
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001655 if (overscanInsetsChanged) {
1656 mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets);
1657 if (DEBUG_LAYOUT) Log.v(TAG, "Overscan insets changing to: "
1658 + mAttachInfo.mOverscanInsets);
1659 // Need to relayout with content insets.
1660 contentInsetsChanged = true;
1661 }
Adrian Roosfa104232014-06-20 16:10:14 -07001662 if (stableInsetsChanged) {
1663 mAttachInfo.mStableInsets.set(mPendingStableInsets);
1664 if (DEBUG_LAYOUT) Log.v(TAG, "Decor insets changing to: "
1665 + mAttachInfo.mStableInsets);
1666 // Need to relayout with content insets.
1667 contentInsetsChanged = true;
1668 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001669 if (contentInsetsChanged || mLastSystemUiVisibility !=
Adrian Roosfa104232014-06-20 16:10:14 -07001670 mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001671 || mLastOverscanRequested != mAttachInfo.mOverscanRequested
1672 || outsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001673 mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08001674 mLastOverscanRequested = mAttachInfo.mOverscanRequested;
Filip Gruszczynski2217f612015-05-26 11:32:08 -07001675 mAttachInfo.mOutsets.set(mPendingOutsets);
Adrian Roosfa104232014-06-20 16:10:14 -07001676 mApplyInsetsRequested = false;
Adam Powell2accbf92014-04-16 23:14:57 +00001677 dispatchApplyInsets(host);
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001678 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001679 if (visibleInsetsChanged) {
1680 mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
1681 if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
1682 + mAttachInfo.mVisibleInsets);
1683 }
1684
1685 if (!hadSurface) {
1686 if (mSurface.isValid()) {
1687 // If we are creating a new surface, then we need to
1688 // completely redraw it. Also, when we get to the
1689 // point of drawing it we will hold off and schedule
1690 // a new traversal instead. This is so we can tell the
1691 // window manager about all of the windows being displayed
1692 // before actually drawing them, so it can display then
1693 // all at once.
1694 newSurface = true;
Jeff Brown96e942d2011-11-30 19:55:01 -08001695 mFullRedrawNeeded = true;
Jack Palevich61a6e682009-10-09 17:37:50 -07001696 mPreviousTransparentRegion.setEmpty();
Romain Guy8506ab42009-06-11 17:35:47 -07001697
John Reck63005e62015-05-19 15:00:13 -07001698 // Only initialize up-front if transparent regions are not
1699 // requested, otherwise defer to see if the entire window
1700 // will be transparent
Romain Guyb051e892010-09-28 19:09:36 -07001701 if (mAttachInfo.mHardwareRenderer != null) {
Dianne Hackborn64825172011-03-02 21:32:58 -08001702 try {
Romain Guy786fc932012-07-24 16:24:56 -07001703 hwInitialized = mAttachInfo.mHardwareRenderer.initialize(
John Reck79d81e62013-11-05 13:26:57 -08001704 mSurface);
John Reck63005e62015-05-19 15:00:13 -07001705 if (hwInitialized && (host.mPrivateFlags
1706 & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
1707 // Don't pre-allocate if transparent regions
1708 // are requested as they may not be needed
1709 mSurface.allocateBuffers();
1710 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001711 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08001712 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08001713 return;
1714 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001715 }
1716 }
1717 } else if (!mSurface.isValid()) {
1718 // If the surface has been removed, then reset the scroll
1719 // positions.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08001720 if (mLastScrolledFocus != null) {
1721 mLastScrolledFocus.clear();
1722 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001723 mScrollY = mCurScrollY = 0;
Adrian Roos0e7ae4e2014-10-01 15:33:22 +02001724 if (mView instanceof RootViewSurfaceTaker) {
1725 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
1726 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001727 if (mScroller != null) {
1728 mScroller.abortAnimation();
1729 }
Romain Guy1d0c7082011-08-03 16:22:24 -07001730 // Our surface is gone
1731 if (mAttachInfo.mHardwareRenderer != null &&
1732 mAttachInfo.mHardwareRenderer.isEnabled()) {
John Reckf47a5942014-06-30 16:20:04 -07001733 mAttachInfo.mHardwareRenderer.destroy();
Romain Guy1d0c7082011-08-03 16:22:24 -07001734 }
Chong Zhangf4abc2b2015-11-12 23:40:58 -08001735 } else if ((surfaceGenerationId != mSurface.getGenerationId()
1736 || surfaceSizeChanged)
1737 && mSurfaceHolder == null
1738 && mAttachInfo.mHardwareRenderer != null) {
Jeff Brown96e942d2011-11-30 19:55:01 -08001739 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08001740 try {
Chong Zhangf4abc2b2015-11-12 23:40:58 -08001741 // Need to do updateSurface (which leads to CanvasContext::setSurface and
1742 // re-create the EGLSurface) if either the Surface changed (as indicated by
1743 // generation id), or WindowManager changed the surface size. The latter is
1744 // because on some chips, changing the consumer side's BufferQueue size may
1745 // not take effect immediately unless we create a new EGLSurface.
1746 // Note that frame size change doesn't always imply surface size change (eg.
1747 // drag resizing uses fullscreen surface), need to check surfaceSizeChanged
1748 // flag from WindowManager.
John Reck79d81e62013-11-05 13:26:57 -08001749 mAttachInfo.mHardwareRenderer.updateSurface(mSurface);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001750 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08001751 handleOutOfResourcesException(e);
Dianne Hackborn64825172011-03-02 21:32:58 -08001752 return;
1753 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001754 }
Chong Zhang0275e392015-09-17 10:41:44 -07001755
1756 final boolean dragResizing = (relayoutResult
1757 & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING) != 0;
1758 if (mDragResizing != dragResizing) {
Skuhneb8160872015-09-22 09:51:39 -07001759 if (dragResizing) {
Jorim Jaggia7262a82015-11-03 15:15:40 +01001760 startDragResizing(mPendingBackDropFrame);
Skuhneb8160872015-09-22 09:51:39 -07001761 } else {
1762 // We shouldn't come here, but if we come we should end the resize.
1763 endDragResizing();
1764 }
Chong Zhang0275e392015-09-17 10:41:44 -07001765 }
Skuhneb8160872015-09-22 09:51:39 -07001766 if (!USE_MT_RENDERER) {
1767 if (dragResizing) {
1768 mCanvasOffsetX = mWinFrame.left;
1769 mCanvasOffsetY = mWinFrame.top;
1770 } else {
1771 mCanvasOffsetX = mCanvasOffsetY = 0;
1772 }
Chong Zhang0275e392015-09-17 10:41:44 -07001773 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001774 } catch (RemoteException e) {
1775 }
Romain Guy1d0c7082011-08-03 16:22:24 -07001776
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001777 if (DEBUG_ORIENTATION) Log.v(
Jeff Brownc5ed5912010-07-14 18:48:53 -07001778 TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001779
Chris Craikd36a81f2014-07-17 10:16:51 -07001780 mAttachInfo.mWindowLeft = frame.left;
1781 mAttachInfo.mWindowTop = frame.top;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001782
1783 // !!FIXME!! This next section handles the case where we did not get the
1784 // window size we asked for. We should avoid this by getting a maximum size from
1785 // the window session beforehand.
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001786 if (mWidth != frame.width() || mHeight != frame.height()) {
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07001787 mWidth = frame.width();
1788 mHeight = frame.height();
1789 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001790
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001791 if (mSurfaceHolder != null) {
1792 // The app owns the surface; tell it about what is going on.
1793 if (mSurface.isValid()) {
1794 // XXX .copyFrom() doesn't work!
1795 //mSurfaceHolder.mSurface.copyFrom(mSurface);
1796 mSurfaceHolder.mSurface = mSurface;
1797 }
Jeff Brown30bc34f2011-01-25 12:56:56 -08001798 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001799 mSurfaceHolder.mSurfaceLock.unlock();
1800 if (mSurface.isValid()) {
1801 if (!hadSurface) {
1802 mSurfaceHolder.ungetCallbacks();
1803
1804 mIsCreating = true;
1805 mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder);
1806 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1807 if (callbacks != null) {
1808 for (SurfaceHolder.Callback c : callbacks) {
1809 c.surfaceCreated(mSurfaceHolder);
1810 }
1811 }
1812 surfaceChanged = true;
1813 }
1814 if (surfaceChanged) {
1815 mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
1816 lp.format, mWidth, mHeight);
1817 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1818 if (callbacks != null) {
1819 for (SurfaceHolder.Callback c : callbacks) {
1820 c.surfaceChanged(mSurfaceHolder, lp.format,
1821 mWidth, mHeight);
1822 }
1823 }
1824 }
1825 mIsCreating = false;
1826 } else if (hadSurface) {
1827 mSurfaceHolder.ungetCallbacks();
1828 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
1829 mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
1830 if (callbacks != null) {
1831 for (SurfaceHolder.Callback c : callbacks) {
1832 c.surfaceDestroyed(mSurfaceHolder);
1833 }
1834 }
1835 mSurfaceHolder.mSurfaceLock.lock();
Jozef BABJAK93c5b6a2011-02-22 09:33:19 +01001836 try {
1837 mSurfaceHolder.mSurface = new Surface();
1838 } finally {
1839 mSurfaceHolder.mSurfaceLock.unlock();
1840 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07001841 }
1842 }
Romain Guy53389bd2010-09-07 17:16:32 -07001843
Alan Viverette50210d92015-05-14 18:05:36 -07001844 final HardwareRenderer hardwareRenderer = mAttachInfo.mHardwareRenderer;
1845 if (hardwareRenderer != null && hardwareRenderer.isEnabled()) {
1846 if (hwInitialized
1847 || mWidth != hardwareRenderer.getWidth()
1848 || mHeight != hardwareRenderer.getHeight()) {
1849 hardwareRenderer.setup(mWidth, mHeight, mAttachInfo,
1850 mWindowAttributes.surfaceInsets);
Romain Guy03985752011-07-11 15:33:51 -07001851 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001852 }
1853
Craig Mautner72d6f212015-02-19 16:33:09 -08001854 if (!mStopped || mReportNextDraw) {
Dianne Hackbornce418e62011-03-01 14:31:38 -08001855 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
Jeff Brown98365d72012-08-19 20:30:52 -07001856 (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001857 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
1858 || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001859 int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
1860 int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001861
Dianne Hackbornce418e62011-03-01 14:31:38 -08001862 if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed! mWidth="
1863 + mWidth + " measuredWidth=" + host.getMeasuredWidth()
1864 + " mHeight=" + mHeight
1865 + " measuredHeight=" + host.getMeasuredHeight()
1866 + " coveredInsetsChanged=" + contentInsetsChanged);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001867
Dianne Hackbornce418e62011-03-01 14:31:38 -08001868 // Ask host how big it wants to be
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001869 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Igor Murashkina86ab6402013-08-30 12:58:36 -07001870
Dianne Hackbornce418e62011-03-01 14:31:38 -08001871 // Implementation of weights from WindowManager.LayoutParams
1872 // We just grow the dimensions as needed and re-measure if
1873 // needs be
1874 int width = host.getMeasuredWidth();
1875 int height = host.getMeasuredHeight();
1876 boolean measureAgain = false;
Igor Murashkina86ab6402013-08-30 12:58:36 -07001877
Dianne Hackbornce418e62011-03-01 14:31:38 -08001878 if (lp.horizontalWeight > 0.0f) {
1879 width += (int) ((mWidth - width) * lp.horizontalWeight);
1880 childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
1881 MeasureSpec.EXACTLY);
1882 measureAgain = true;
1883 }
1884 if (lp.verticalWeight > 0.0f) {
1885 height += (int) ((mHeight - height) * lp.verticalWeight);
1886 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
1887 MeasureSpec.EXACTLY);
1888 measureAgain = true;
1889 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001890
Dianne Hackbornce418e62011-03-01 14:31:38 -08001891 if (measureAgain) {
1892 if (DEBUG_LAYOUT) Log.v(TAG,
1893 "And hey let's measure once more: width=" + width
1894 + " height=" + height);
Jeff Brownc8d2668b2012-05-16 17:23:59 -07001895 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
Dianne Hackbornce418e62011-03-01 14:31:38 -08001896 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07001897
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001898 layoutRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001899 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001900 }
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001901 } else {
1902 // Not the first pass and no window/insets/visibility change but the window
1903 // may have moved and we need check that and if so to update the left and right
1904 // in the attach info. We translate only the window frame since on window move
1905 // the window manager tells us only for the new frame but the insets are the
1906 // same and we do not want to translate them more than once.
1907
1908 // TODO: Well, we are checking whether the frame has changed similarly
1909 // to how this is done for the insets. This is however incorrect since
1910 // the insets and the frame are translated. For example, the old frame
1911 // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new
1912 // reported frame is (2, 2 - 2, 2) which implies no change but this is not
1913 // true since we are comparing a not translated value to a translated one.
1914 // This scenario is rare but we may want to fix that.
1915
Chris Craikd36a81f2014-07-17 10:16:51 -07001916 final boolean windowMoved = (mAttachInfo.mWindowLeft != frame.left
1917 || mAttachInfo.mWindowTop != frame.top);
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001918 if (windowMoved) {
1919 if (mTranslator != null) {
1920 mTranslator.translateRectInScreenToAppWinFrame(frame);
1921 }
Chris Craikd36a81f2014-07-17 10:16:51 -07001922 mAttachInfo.mWindowLeft = frame.left;
1923 mAttachInfo.mWindowTop = frame.top;
Alan Viverette50210d92015-05-14 18:05:36 -07001924
1925 // Update the light position for the new window offsets.
1926 if (mAttachInfo.mHardwareRenderer != null) {
1927 mAttachInfo.mHardwareRenderer.setLightCenter(mAttachInfo);
1928 }
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001929 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001930 }
1931
Craig Mautner72d6f212015-02-19 16:33:09 -08001932 final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001933 boolean triggerGlobalLayoutListener = didLayout
Chris Craikd36a81f2014-07-17 10:16:51 -07001934 || mAttachInfo.mRecomputeGlobalAttributes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001935 if (didLayout) {
Chet Haase3efa7b52012-12-03 08:33:17 -08001936 performLayout(lp, desiredWindowWidth, desiredWindowHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001937
Mathias Agopian54e3d3842013-04-12 15:13:12 -07001938 // By this point all views have been sized and positioned
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001939 // We can compute the transparent area
1940
Dianne Hackborn4702a852012-08-17 15:18:29 -07001941 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001942 // start out transparent
1943 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
1944 host.getLocationInWindow(mTmpLocation);
1945 mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
1946 mTmpLocation[0] + host.mRight - host.mLeft,
1947 mTmpLocation[1] + host.mBottom - host.mTop);
1948
1949 host.gatherTransparentRegion(mTransparentRegion);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07001950 if (mTranslator != null) {
1951 mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
1952 }
1953
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001954 if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
1955 mPreviousTransparentRegion.set(mTransparentRegion);
Mathias Agopian54e3d3842013-04-12 15:13:12 -07001956 mFullRedrawNeeded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001957 // reconfigure window manager
1958 try {
Jeff Brown98365d72012-08-19 20:30:52 -07001959 mWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001960 } catch (RemoteException e) {
1961 }
1962 }
1963 }
1964
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001965 if (DBG) {
1966 System.out.println("======================================");
1967 System.out.println("performTraversals -- after setFrame");
1968 host.debug();
1969 }
1970 }
1971
1972 if (triggerGlobalLayoutListener) {
Chris Craikd36a81f2014-07-17 10:16:51 -07001973 mAttachInfo.mRecomputeGlobalAttributes = false;
1974 mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001975 }
1976
1977 if (computesInternalInsets) {
Jeff Brownfbf09772011-01-16 14:06:57 -08001978 // Clear the original insets.
Chris Craikd36a81f2014-07-17 10:16:51 -07001979 final ViewTreeObserver.InternalInsetsInfo insets = mAttachInfo.mGivenInternalInsets;
Jeff Brownfbf09772011-01-16 14:06:57 -08001980 insets.reset();
1981
1982 // Compute new insets in place.
Chris Craikd36a81f2014-07-17 10:16:51 -07001983 mAttachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
1984 mAttachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty();
Jeff Brownfbf09772011-01-16 14:06:57 -08001985
1986 // Tell the window manager.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001987 if (insetsPending || !mLastGivenInsets.equals(insets)) {
1988 mLastGivenInsets.set(insets);
Jeff Brownfbf09772011-01-16 14:06:57 -08001989
1990 // Translate insets to screen coordinates if needed.
1991 final Rect contentInsets;
1992 final Rect visibleInsets;
1993 final Region touchableRegion;
1994 if (mTranslator != null) {
1995 contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
1996 visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
1997 touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
1998 } else {
1999 contentInsets = insets.contentInsets;
2000 visibleInsets = insets.visibleInsets;
2001 touchableRegion = insets.touchableRegion;
2002 }
2003
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002004 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002005 mWindowSession.setInsets(mWindow, insets.mTouchableInsets,
Jeff Brownfbf09772011-01-16 14:06:57 -08002006 contentInsets, visibleInsets, touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002007 } catch (RemoteException e) {
2008 }
2009 }
2010 }
Romain Guy8506ab42009-06-11 17:35:47 -07002011
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002012 if (mFirst) {
2013 // handle first focus request
2014 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()="
2015 + mView.hasFocus());
2016 if (mView != null) {
2017 if (!mView.hasFocus()) {
2018 mView.requestFocus(View.FOCUS_FORWARD);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002019 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view="
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002020 + mView.findFocus());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002021 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002022 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view="
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002023 + mView.findFocus());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002024 }
2025 }
2026 }
2027
Alan Viverette64bf97a2015-09-18 16:42:00 -04002028 final boolean changedVisibility = (viewVisibilityChanged || mFirst) && isViewVisible;
2029 final boolean hasWindowFocus = mAttachInfo.mHasWindowFocus && isViewVisible;
2030 final boolean regainedFocus = hasWindowFocus && mLostWindowFocus;
2031 if (regainedFocus) {
2032 mLostWindowFocus = false;
2033 } else if (!hasWindowFocus && mHadWindowFocus) {
2034 mLostWindowFocus = true;
2035 }
2036
2037 if (changedVisibility || regainedFocus) {
2038 host.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
2039 }
2040
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002041 mFirst = false;
2042 mWillDrawSoon = false;
2043 mNewSurfaceNeeded = false;
2044 mViewVisibility = viewVisibility;
Alan Viverette64bf97a2015-09-18 16:42:00 -04002045 mHadWindowFocus = hasWindowFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002046
Alan Viverette64bf97a2015-09-18 16:42:00 -04002047 if (hasWindowFocus && !isInLocalFocusMode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002048 final boolean imTarget = WindowManager.LayoutParams
2049 .mayUseInputMethod(mWindowAttributes.flags);
2050 if (imTarget != mLastWasImTarget) {
2051 mLastWasImTarget = imTarget;
2052 InputMethodManager imm = InputMethodManager.peekInstance();
2053 if (imm != null && imTarget) {
Alan Viverette64bf97a2015-09-18 16:42:00 -04002054 imm.onPreWindowFocus(mView, hasWindowFocus);
Yohei Yukawa5f059652015-05-14 22:16:41 -07002055 imm.onPostWindowFocus(mView, mView.findFocus(),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002056 mWindowAttributes.softInputMode,
2057 !mHasHadWindowFocus, mWindowAttributes.flags);
2058 }
2059 }
2060 }
Romain Guy8506ab42009-06-11 17:35:47 -07002061
Jeff Brown96e942d2011-11-30 19:55:01 -08002062 // Remember if we must report the next draw.
Jeff Brown98365d72012-08-19 20:30:52 -07002063 if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
Jeff Brown96e942d2011-11-30 19:55:01 -08002064 mReportNextDraw = true;
2065 }
2066
Alan Viverette64bf97a2015-09-18 16:42:00 -04002067 boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002068
Chet Haase61158c62011-09-06 22:19:45 -07002069 if (!cancelDraw && !newSurface) {
Chet Haase9c450412015-10-01 13:25:58 -07002070 if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
2071 for (int i = 0; i < mPendingTransitions.size(); ++i) {
2072 mPendingTransitions.get(i).startChangingAnimations();
Chet Haased56c6952011-09-07 08:46:23 -07002073 }
Chet Haase9c450412015-10-01 13:25:58 -07002074 mPendingTransitions.clear();
Chet Haased56c6952011-09-07 08:46:23 -07002075 }
Chet Haase9c450412015-10-01 13:25:58 -07002076
2077 performDraw();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002078 } else {
Alan Viverette64bf97a2015-09-18 16:42:00 -04002079 if (isViewVisible) {
Chris Wren78cb7cf2012-05-15 12:36:44 -04002080 // Try again
2081 scheduleTraversals();
2082 } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
Chet Haased56c6952011-09-07 08:46:23 -07002083 for (int i = 0; i < mPendingTransitions.size(); ++i) {
2084 mPendingTransitions.get(i).endChangingAnimations();
2085 }
2086 mPendingTransitions.clear();
2087 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002088 }
Craig Mautnerdf2390a2012-08-29 20:59:22 -07002089
2090 mIsInTraversal = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002091 }
2092
Romain Guy3696779b2013-01-28 14:04:07 -08002093 private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
2094 Log.e(TAG, "OutOfResourcesException initializing HW surface", e);
2095 try {
2096 if (!mWindowSession.outOfMemory(mWindow) &&
2097 Process.myUid() != Process.SYSTEM_UID) {
2098 Slog.w(TAG, "No processes killed for memory; killing self");
2099 Process.killProcess(Process.myPid());
2100 }
2101 } catch (RemoteException ex) {
2102 }
2103 mLayoutRequested = true; // ask wm for a new surface next time.
2104 }
2105
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002106 private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
2107 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
2108 try {
2109 mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
2110 } finally {
2111 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2112 }
2113 }
2114
Chet Haase97140572012-09-13 14:56:47 -07002115 /**
2116 * Called by {@link android.view.View#isInLayout()} to determine whether the view hierarchy
2117 * is currently undergoing a layout pass.
2118 *
2119 * @return whether the view hierarchy is currently undergoing a layout pass
2120 */
2121 boolean isInLayout() {
2122 return mInLayout;
2123 }
2124
2125 /**
Chet Haasecc699b42012-12-13 09:06:55 -08002126 * Called by {@link android.view.View#requestLayout()} if the view hierarchy is currently
2127 * undergoing a layout pass. requestLayout() should not generally be called during layout,
2128 * unless the container hierarchy knows what it is doing (i.e., it is fine as long as
2129 * all children in that container hierarchy are measured and laid out at the end of the layout
2130 * pass for that container). If requestLayout() is called anyway, we handle it correctly
2131 * by registering all requesters during a frame as it proceeds. At the end of the frame,
2132 * we check all of those views to see if any still have pending layout requests, which
2133 * indicates that they were not correctly handled by their container hierarchy. If that is
2134 * the case, we clear all such flags in the tree, to remove the buggy flag state that leads
2135 * to blank containers, and force a second request/measure/layout pass in this frame. If
Chet Haase97140572012-09-13 14:56:47 -07002136 * more requestLayout() calls are received during that second layout pass, we post those
Chet Haasecc699b42012-12-13 09:06:55 -08002137 * requests to the next frame to avoid possible infinite loops.
2138 *
2139 * <p>The return value from this method indicates whether the request should proceed
2140 * (if it is a request during the first layout pass) or should be skipped and posted to the
2141 * next frame (if it is a request during the second layout pass).</p>
Chet Haase97140572012-09-13 14:56:47 -07002142 *
2143 * @param view the view that requested the layout.
Chet Haasecc699b42012-12-13 09:06:55 -08002144 *
2145 * @return true if request should proceed, false otherwise.
Chet Haase97140572012-09-13 14:56:47 -07002146 */
Chet Haasecc699b42012-12-13 09:06:55 -08002147 boolean requestLayoutDuringLayout(final View view) {
2148 if (view.mParent == null || view.mAttachInfo == null) {
2149 // Would not normally trigger another layout, so just let it pass through as usual
2150 return true;
2151 }
Chet Haase107a4822013-03-13 06:46:50 -07002152 if (!mLayoutRequesters.contains(view)) {
2153 mLayoutRequesters.add(view);
2154 }
Chet Haase97140572012-09-13 14:56:47 -07002155 if (!mHandlingLayoutInLayoutRequest) {
Chet Haase107a4822013-03-13 06:46:50 -07002156 // Let the request proceed normally; it will be processed in a second layout pass
2157 // if necessary
Chet Haasecc699b42012-12-13 09:06:55 -08002158 return true;
Chet Haase97140572012-09-13 14:56:47 -07002159 } else {
Chet Haase107a4822013-03-13 06:46:50 -07002160 // Don't let the request proceed during the second layout pass.
2161 // It will post to the next frame instead.
Chet Haasecc699b42012-12-13 09:06:55 -08002162 return false;
Chet Haase97140572012-09-13 14:56:47 -07002163 }
2164 }
2165
Chet Haase3efa7b52012-12-03 08:33:17 -08002166 private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
2167 int desiredWindowHeight) {
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002168 mLayoutRequested = false;
2169 mScrollMayChange = true;
Chet Haase97140572012-09-13 14:56:47 -07002170 mInLayout = true;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002171
2172 final View host = mView;
2173 if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
2174 Log.v(TAG, "Laying out " + host + " to (" +
2175 host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
2176 }
2177
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002178 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
2179 try {
2180 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haasecc699b42012-12-13 09:06:55 -08002181
Chet Haased5a83522012-11-21 16:24:44 -08002182 mInLayout = false;
Chet Haase97140572012-09-13 14:56:47 -07002183 int numViewsRequestingLayout = mLayoutRequesters.size();
2184 if (numViewsRequestingLayout > 0) {
Chet Haasecc699b42012-12-13 09:06:55 -08002185 // requestLayout() was called during layout.
2186 // If no layout-request flags are set on the requesting views, there is no problem.
2187 // If some requests are still pending, then we need to clear those flags and do
2188 // a full request/measure/layout pass to handle this situation.
Chet Haase107a4822013-03-13 06:46:50 -07002189 ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
2190 false);
2191 if (validLayoutRequesters != null) {
2192 // Set this flag to indicate that any further requests are happening during
2193 // the second pass, which may result in posting those requests to the next
2194 // frame instead
Chet Haasecc699b42012-12-13 09:06:55 -08002195 mHandlingLayoutInLayoutRequest = true;
Chet Haase107a4822013-03-13 06:46:50 -07002196
2197 // Process fresh layout requests, then measure and layout
2198 int numValidRequests = validLayoutRequesters.size();
Chet Haasecc699b42012-12-13 09:06:55 -08002199 for (int i = 0; i < numValidRequests; ++i) {
Chet Haase107a4822013-03-13 06:46:50 -07002200 final View view = validLayoutRequesters.get(i);
2201 Log.w("View", "requestLayout() improperly called by " + view +
2202 " during layout: running second layout pass");
2203 view.requestLayout();
Chet Haasecc699b42012-12-13 09:06:55 -08002204 }
2205 measureHierarchy(host, lp, mView.getContext().getResources(),
2206 desiredWindowWidth, desiredWindowHeight);
2207 mInLayout = true;
2208 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
Chet Haase107a4822013-03-13 06:46:50 -07002209
Chet Haasecc699b42012-12-13 09:06:55 -08002210 mHandlingLayoutInLayoutRequest = false;
Chet Haase107a4822013-03-13 06:46:50 -07002211
2212 // Check the valid requests again, this time without checking/clearing the
2213 // layout flags, since requests happening during the second pass get noop'd
2214 validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);
2215 if (validLayoutRequesters != null) {
2216 final ArrayList<View> finalRequesters = validLayoutRequesters;
2217 // Post second-pass requests to the next frame
2218 getRunQueue().post(new Runnable() {
2219 @Override
2220 public void run() {
2221 int numValidRequests = finalRequesters.size();
2222 for (int i = 0; i < numValidRequests; ++i) {
2223 final View view = finalRequesters.get(i);
2224 Log.w("View", "requestLayout() improperly called by " + view +
2225 " during second layout pass: posting in next frame");
2226 view.requestLayout();
2227 }
2228 }
2229 });
2230 }
Chet Haasecc699b42012-12-13 09:06:55 -08002231 }
Chet Haase107a4822013-03-13 06:46:50 -07002232
Chet Haase97140572012-09-13 14:56:47 -07002233 }
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002234 } finally {
2235 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2236 }
Chet Haase97140572012-09-13 14:56:47 -07002237 mInLayout = false;
Jeff Brownc8d2668b2012-05-16 17:23:59 -07002238 }
2239
Chet Haase107a4822013-03-13 06:46:50 -07002240 /**
2241 * This method is called during layout when there have been calls to requestLayout() during
2242 * layout. It walks through the list of views that requested layout to determine which ones
2243 * still need it, based on visibility in the hierarchy and whether they have already been
2244 * handled (as is usually the case with ListView children).
2245 *
2246 * @param layoutRequesters The list of views that requested layout during layout
2247 * @param secondLayoutRequests Whether the requests were issued during the second layout pass.
2248 * If so, the FORCE_LAYOUT flag was not set on requesters.
2249 * @return A list of the actual views that still need to be laid out.
2250 */
2251 private ArrayList<View> getValidLayoutRequesters(ArrayList<View> layoutRequesters,
2252 boolean secondLayoutRequests) {
2253
2254 int numViewsRequestingLayout = layoutRequesters.size();
2255 ArrayList<View> validLayoutRequesters = null;
2256 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2257 View view = layoutRequesters.get(i);
2258 if (view != null && view.mAttachInfo != null && view.mParent != null &&
2259 (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) ==
2260 View.PFLAG_FORCE_LAYOUT)) {
2261 boolean gone = false;
2262 View parent = view;
2263 // Only trigger new requests for views in a non-GONE hierarchy
2264 while (parent != null) {
2265 if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) {
2266 gone = true;
2267 break;
2268 }
2269 if (parent.mParent instanceof View) {
2270 parent = (View) parent.mParent;
2271 } else {
2272 parent = null;
2273 }
2274 }
2275 if (!gone) {
2276 if (validLayoutRequesters == null) {
2277 validLayoutRequesters = new ArrayList<View>();
2278 }
2279 validLayoutRequesters.add(view);
2280 }
2281 }
2282 }
2283 if (!secondLayoutRequests) {
2284 // If we're checking the layout flags, then we need to clean them up also
2285 for (int i = 0; i < numViewsRequestingLayout; ++i) {
2286 View view = layoutRequesters.get(i);
2287 while (view != null &&
2288 (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
2289 view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
2290 if (view.mParent instanceof View) {
2291 view = (View) view.mParent;
2292 } else {
2293 view = null;
2294 }
2295 }
2296 }
2297 }
2298 layoutRequesters.clear();
2299 return validLayoutRequesters;
2300 }
2301
Igor Murashkina86ab6402013-08-30 12:58:36 -07002302 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002303 public void requestTransparentRegion(View child) {
2304 // the test below should not fail unless someone is messing with us
2305 checkThread();
2306 if (mView == child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002307 mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002308 // Need to make sure we re-evaluate the window attributes next
2309 // time around, to ensure the window has the correct format.
2310 mWindowAttributesChanged = true;
Romain Guyf21c9b02011-09-06 16:56:54 -07002311 mWindowAttributesChangesFlag = 0;
Mathias Agopian1bd80ad2010-11-04 17:13:39 -07002312 requestLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002313 }
2314 }
2315
2316 /**
2317 * Figures out the measure spec for the root view in a window based on it's
2318 * layout params.
2319 *
2320 * @param windowSize
2321 * The available width or height of the window
2322 *
2323 * @param rootDimension
2324 * The layout params for one dimension (width or height) of the
2325 * window.
2326 *
2327 * @return The measure spec to use to measure the root view.
2328 */
Romain Guya998dff2012-03-23 18:58:36 -07002329 private static int getRootMeasureSpec(int windowSize, int rootDimension) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002330 int measureSpec;
2331 switch (rootDimension) {
2332
Romain Guy980a9382010-01-08 15:06:28 -08002333 case ViewGroup.LayoutParams.MATCH_PARENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002334 // Window can't resize. Force root view to be windowSize.
2335 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
2336 break;
2337 case ViewGroup.LayoutParams.WRAP_CONTENT:
2338 // Window can resize. Set max size for root view.
2339 measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
2340 break;
2341 default:
2342 // Window wants to be an exact size. Force root view to be that size.
2343 measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
2344 break;
2345 }
2346 return measureSpec;
2347 }
2348
Alan Viveretteccb11e12014-07-08 16:04:02 -07002349 int mHardwareXOffset;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002350 int mHardwareYOffset;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002351
Igor Murashkina86ab6402013-08-30 12:58:36 -07002352 @Override
Chris Craikf6829a02015-03-10 10:28:59 -07002353 public void onHardwarePreDraw(DisplayListCanvas canvas) {
Alan Viveretteccb11e12014-07-08 16:04:02 -07002354 canvas.translate(-mHardwareXOffset, -mHardwareYOffset);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002355 }
2356
Igor Murashkina86ab6402013-08-30 12:58:36 -07002357 @Override
Chris Craikf6829a02015-03-10 10:28:59 -07002358 public void onHardwarePostDraw(DisplayListCanvas canvas) {
Alan Viverette632af842014-10-28 13:45:11 -07002359 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002360 }
2361
Chet Haaseed30fd82011-04-22 16:18:45 -07002362 /**
2363 * @hide
2364 */
2365 void outputDisplayList(View view) {
Chris Craik356b5fe2015-07-07 10:39:36 -07002366 view.mRenderNode.output();
John Recke248bd12015-08-05 13:53:53 -07002367 if (mAttachInfo.mHardwareRenderer != null) {
2368 ((ThreadedRenderer)mAttachInfo.mHardwareRenderer).serializeDisplayListTree();
2369 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002370 }
2371
2372 /**
2373 * @see #PROPERTY_PROFILE_RENDERING
2374 */
2375 private void profileRendering(boolean enabled) {
2376 if (mProfileRendering) {
2377 mRenderProfilingEnabled = enabled;
Chris Craikae4f32042013-02-07 12:57:10 -08002378
2379 if (mRenderProfiler != null) {
2380 mChoreographer.removeFrameCallback(mRenderProfiler);
2381 }
2382 if (mRenderProfilingEnabled) {
2383 if (mRenderProfiler == null) {
2384 mRenderProfiler = new Choreographer.FrameCallback() {
2385 @Override
2386 public void doFrame(long frameTimeNanos) {
2387 mDirty.set(0, 0, mWidth, mHeight);
2388 scheduleTraversals();
2389 if (mRenderProfilingEnabled) {
2390 mChoreographer.postFrameCallback(mRenderProfiler);
2391 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002392 }
Chris Craikae4f32042013-02-07 12:57:10 -08002393 };
2394 }
Romain Guy5bb3c732012-11-29 17:52:58 -08002395 mChoreographer.postFrameCallback(mRenderProfiler);
Romain Guy59a12ca2011-06-09 17:48:21 -07002396 } else {
Romain Guy59a12ca2011-06-09 17:48:21 -07002397 mRenderProfiler = null;
Chet Haaseed30fd82011-04-22 16:18:45 -07002398 }
2399 }
2400 }
2401
Chet Haase2f2022a2011-10-11 06:41:59 -07002402 /**
2403 * Called from draw() when DEBUG_FPS is enabled
2404 */
2405 private void trackFPS() {
2406 // Tracks frames per second drawn. First value in a series of draws may be bogus
2407 // because it down not account for the intervening idle time
2408 long nowTime = System.currentTimeMillis();
2409 if (mFpsStartTime < 0) {
2410 mFpsStartTime = mFpsPrevTime = nowTime;
2411 mFpsNumFrames = 0;
2412 } else {
2413 ++mFpsNumFrames;
2414 String thisHash = Integer.toHexString(System.identityHashCode(this));
2415 long frameTime = nowTime - mFpsPrevTime;
2416 long totalTime = nowTime - mFpsStartTime;
2417 Log.v(TAG, "0x" + thisHash + "\tFrame time:\t" + frameTime);
2418 mFpsPrevTime = nowTime;
2419 if (totalTime > 1000) {
2420 float fps = (float) mFpsNumFrames * 1000 / totalTime;
2421 Log.v(TAG, "0x" + thisHash + "\tFPS:\t" + fps);
2422 mFpsStartTime = nowTime;
2423 mFpsNumFrames = 0;
2424 }
2425 }
2426 }
2427
Jeff Brown96e942d2011-11-30 19:55:01 -08002428 private void performDraw() {
Jeff Brownd912e1f2014-04-11 18:46:22 -07002429 if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
Craig Mautner006f0e42012-03-21 11:00:32 -07002430 return;
2431 }
Romain Guy7e4e5612012-03-05 14:37:29 -08002432
Jeff Brown96e942d2011-11-30 19:55:01 -08002433 final boolean fullRedrawNeeded = mFullRedrawNeeded;
2434 mFullRedrawNeeded = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002435
Romain Guy1f59e5c2012-05-06 14:11:16 -07002436 mIsDrawing = true;
Jeff Brown481c1572012-03-09 14:41:15 -08002437 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
2438 try {
2439 draw(fullRedrawNeeded);
2440 } finally {
Romain Guy1f59e5c2012-05-06 14:11:16 -07002441 mIsDrawing = false;
Jeff Brown481c1572012-03-09 14:41:15 -08002442 Trace.traceEnd(Trace.TRACE_TAG_VIEW);
2443 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002444
John Reck119907c2014-08-14 09:02:01 -07002445 // For whatever reason we didn't create a HardwareRenderer, end any
2446 // hardware animations that are now dangling
2447 if (mAttachInfo.mPendingAnimatingRenderNodes != null) {
2448 final int count = mAttachInfo.mPendingAnimatingRenderNodes.size();
2449 for (int i = 0; i < count; i++) {
2450 mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators();
2451 }
2452 mAttachInfo.mPendingAnimatingRenderNodes.clear();
2453 }
2454
Jeff Brown96e942d2011-11-30 19:55:01 -08002455 if (mReportNextDraw) {
2456 mReportNextDraw = false;
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07002457
2458 // if we're using multi-thread renderer, wait for the window frame draws
2459 if (mWindowDrawCountDown != null) {
2460 try {
2461 mWindowDrawCountDown.await();
2462 } catch (InterruptedException e) {
2463 Log.e(TAG, "Window redraw count down interruped!");
2464 }
2465 mWindowDrawCountDown = null;
2466 }
2467
John Reck28ad7b52014-04-07 16:59:25 -07002468 if (mAttachInfo.mHardwareRenderer != null) {
2469 mAttachInfo.mHardwareRenderer.fence();
2470 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002471
2472 if (LOCAL_LOGV) {
2473 Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
2474 }
2475 if (mSurfaceHolder != null && mSurface.isValid()) {
2476 mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
2477 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
2478 if (callbacks != null) {
2479 for (SurfaceHolder.Callback c : callbacks) {
2480 if (c instanceof SurfaceHolder.Callback2) {
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08002481 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(mSurfaceHolder);
Jeff Brown96e942d2011-11-30 19:55:01 -08002482 }
2483 }
2484 }
2485 }
2486 try {
Jeff Brown98365d72012-08-19 20:30:52 -07002487 mWindowSession.finishDrawing(mWindow);
Jeff Brown96e942d2011-11-30 19:55:01 -08002488 } catch (RemoteException e) {
2489 }
2490 }
2491 }
2492
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002493 private void draw(boolean fullRedrawNeeded) {
2494 Surface surface = mSurface;
Romain Guyfbb93fa2012-12-03 18:50:35 -08002495 if (!surface.isValid()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002496 return;
2497 }
2498
Chet Haase2f2022a2011-10-11 06:41:59 -07002499 if (DEBUG_FPS) {
2500 trackFPS();
2501 }
2502
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002503 if (!sFirstDrawComplete) {
2504 synchronized (sFirstDrawHandlers) {
2505 sFirstDrawComplete = true;
Romain Guy812ccbe2010-06-01 14:07:24 -07002506 final int count = sFirstDrawHandlers.size();
2507 for (int i = 0; i< count; i++) {
Jeff Browna175a5b2012-02-15 19:18:31 -08002508 mHandler.post(sFirstDrawHandlers.get(i));
Dianne Hackborn2a9094d2010-02-03 19:20:09 -08002509 }
2510 }
2511 }
Romain Guy59a12ca2011-06-09 17:48:21 -07002512
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002513 scrollToRectOrFocus(null, false);
2514
Chris Craikd36a81f2014-07-17 10:16:51 -07002515 if (mAttachInfo.mViewScrollChanged) {
2516 mAttachInfo.mViewScrollChanged = false;
2517 mAttachInfo.mTreeObserver.dispatchOnScrollChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002518 }
Romain Guy8506ab42009-06-11 17:35:47 -07002519
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002520 boolean animating = mScroller != null && mScroller.computeScrollOffset();
Alan Viveretteccb11e12014-07-08 16:04:02 -07002521 final int curScrollY;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002522 if (animating) {
Alan Viveretteccb11e12014-07-08 16:04:02 -07002523 curScrollY = mScroller.getCurrY();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002524 } else {
Alan Viveretteccb11e12014-07-08 16:04:02 -07002525 curScrollY = mScrollY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002526 }
Alan Viveretteccb11e12014-07-08 16:04:02 -07002527 if (mCurScrollY != curScrollY) {
2528 mCurScrollY = curScrollY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002529 fullRedrawNeeded = true;
Adrian Roos0e7ae4e2014-10-01 15:33:22 +02002530 if (mView instanceof RootViewSurfaceTaker) {
2531 ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
2532 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002533 }
Jeff Brown96e942d2011-11-30 19:55:01 -08002534
Chris Craikd36a81f2014-07-17 10:16:51 -07002535 final float appScale = mAttachInfo.mApplicationScale;
2536 final boolean scalingRequired = mAttachInfo.mScalingRequired;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002537
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002538 int resizeAlpha = 0;
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002539
Jeff Brown96e942d2011-11-30 19:55:01 -08002540 final Rect dirty = mDirty;
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002541 if (mSurfaceHolder != null) {
2542 // The app owns the surface, we won't draw.
2543 dirty.setEmpty();
Derek Sollenberger8d948352015-07-16 09:27:59 -04002544 if (animating && mScroller != null) {
2545 mScroller.abortAnimation();
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002546 }
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07002547 return;
2548 }
Romain Guy58ef7fb2010-09-13 12:52:37 -07002549
2550 if (fullRedrawNeeded) {
Chris Craikd36a81f2014-07-17 10:16:51 -07002551 mAttachInfo.mIgnoreDirtyState = true;
Romain Guyc3166e12011-08-08 15:00:03 -07002552 dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
Romain Guy58ef7fb2010-09-13 12:52:37 -07002553 }
Chet Haasead4f7032011-06-22 09:18:31 -07002554
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002555 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Jeff Brownc5ed5912010-07-14 18:48:53 -07002556 Log.v(TAG, "Draw " + mView + "/"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002557 + mWindowAttributes.getTitle()
2558 + ": dirty={" + dirty.left + "," + dirty.top
2559 + "," + dirty.right + "," + dirty.bottom + "} surface="
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002560 + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
2561 appScale + ", width=" + mWidth + ", height=" + mHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002562 }
2563
Chris Craikd36a81f2014-07-17 10:16:51 -07002564 mAttachInfo.mTreeObserver.dispatchOnDraw();
Romain Guy25eba5c2012-04-04 17:29:03 -07002565
Chong Zhang0275e392015-09-17 10:41:44 -07002566 int xOffset = -mCanvasOffsetX;
2567 int yOffset = -mCanvasOffsetY + curScrollY;
Alan Viverettea51cab92014-07-16 15:15:49 -07002568 final WindowManager.LayoutParams params = mWindowAttributes;
2569 final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
2570 if (surfaceInsets != null) {
2571 xOffset -= surfaceInsets.left;
2572 yOffset -= surfaceInsets.top;
2573
2574 // Offset dirty rect for surface insets.
2575 dirty.offset(surfaceInsets.left, surfaceInsets.right);
2576 }
2577
Alan Viverette632af842014-10-28 13:45:11 -07002578 boolean accessibilityFocusDirty = false;
2579 final Drawable drawable = mAttachInfo.mAccessibilityFocusDrawable;
2580 if (drawable != null) {
2581 final Rect bounds = mAttachInfo.mTmpInvalRect;
2582 final boolean hasFocus = getAccessibilityFocusedRect(bounds);
2583 if (!hasFocus) {
2584 bounds.setEmpty();
2585 }
2586 if (!bounds.equals(drawable.getBounds())) {
2587 accessibilityFocusDirty = true;
2588 }
2589 }
2590
John Reckba6adf62015-02-19 14:36:50 -08002591 mAttachInfo.mDrawingTime =
2592 mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
2593
Alan Viverette632af842014-10-28 13:45:11 -07002594 if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
Chris Craikd36a81f2014-07-17 10:16:51 -07002595 if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
Alan Viverette632af842014-10-28 13:45:11 -07002596 // If accessibility focus moved, always invalidate the root.
2597 boolean invalidateRoot = accessibilityFocusDirty;
2598
Jeff Brown96e942d2011-11-30 19:55:01 -08002599 // Draw with hardware renderer.
2600 mIsAnimating = false;
Alan Viverette632af842014-10-28 13:45:11 -07002601
John Reck0a973302014-07-16 13:29:45 -07002602 if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
2603 mHardwareYOffset = yOffset;
2604 mHardwareXOffset = xOffset;
Alan Viverette632af842014-10-28 13:45:11 -07002605 invalidateRoot = true;
Alan Viverettef6cf1a02014-08-11 14:13:02 -07002606 }
2607
Alan Viverette632af842014-10-28 13:45:11 -07002608 if (invalidateRoot) {
2609 mAttachInfo.mHardwareRenderer.invalidateRoot();
2610 }
2611
Jeff Brown96e942d2011-11-30 19:55:01 -08002612 dirty.setEmpty();
2613
Skuhne980ee472015-10-06 11:31:31 -07002614 // Stage the content drawn size now. It will be transferred to the renderer
2615 // shortly before the draw commands get send to the renderer.
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07002616 final boolean updated = updateContentDrawBounds();
2617
John Reck61375a82014-09-18 19:27:48 +00002618 mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this);
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07002619
2620 if (updated) {
2621 requestDrawWindow();
2622 }
Romain Guy3696779b2013-01-28 14:04:07 -08002623 } else {
2624 // If we get here with a disabled & requested hardware renderer, something went
2625 // wrong (an invalidate posted right before we destroyed the hardware surface
2626 // for instance) so we should just bail out. Locking the surface with software
2627 // rendering at this point would lock it forever and prevent hardware renderer
2628 // from doing its job when it comes back.
2629 // Before we request a new frame we must however attempt to reinitiliaze the
2630 // hardware renderer if it's in requested state. This would happen after an
2631 // eglTerminate() for instance.
Chris Craikd36a81f2014-07-17 10:16:51 -07002632 if (mAttachInfo.mHardwareRenderer != null &&
2633 !mAttachInfo.mHardwareRenderer.isEnabled() &&
2634 mAttachInfo.mHardwareRenderer.isRequested()) {
Romain Guy3696779b2013-01-28 14:04:07 -08002635
2636 try {
Chris Craikd36a81f2014-07-17 10:16:51 -07002637 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
Alan Viverette50210d92015-05-14 18:05:36 -07002638 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
Igor Murashkina86ab6402013-08-30 12:58:36 -07002639 } catch (OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002640 handleOutOfResourcesException(e);
2641 return;
2642 }
2643
2644 mFullRedrawNeeded = true;
2645 scheduleTraversals();
2646 return;
2647 }
2648
Chris Craikd36a81f2014-07-17 10:16:51 -07002649 if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
Romain Guy3696779b2013-01-28 14:04:07 -08002650 return;
2651 }
Jeff Brown95db2b22011-11-30 19:54:41 -08002652 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002653 }
Romain Guy8506ab42009-06-11 17:35:47 -07002654
Dianne Hackborn0f761d62010-11-30 22:06:10 -08002655 if (animating) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002656 mFullRedrawNeeded = true;
2657 scheduleTraversals();
2658 }
2659 }
2660
Romain Guy25eba5c2012-04-04 17:29:03 -07002661 /**
Alan Viveretteccb11e12014-07-08 16:04:02 -07002662 * @return true if drawing was successful, false if an error occurred
Romain Guy25eba5c2012-04-04 17:29:03 -07002663 */
Alan Viveretteccb11e12014-07-08 16:04:02 -07002664 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
Romain Guy25eba5c2012-04-04 17:29:03 -07002665 boolean scalingRequired, Rect dirty) {
2666
2667 // Draw with software renderer.
Alan Viverettea51cab92014-07-16 15:15:49 -07002668 final Canvas canvas;
Romain Guy25eba5c2012-04-04 17:29:03 -07002669 try {
Alan Viverettea51cab92014-07-16 15:15:49 -07002670 final int left = dirty.left;
2671 final int top = dirty.top;
2672 final int right = dirty.right;
2673 final int bottom = dirty.bottom;
Romain Guy25eba5c2012-04-04 17:29:03 -07002674
Romain Guy25eba5c2012-04-04 17:29:03 -07002675 canvas = mSurface.lockCanvas(dirty);
2676
Romain Guye55945e2013-04-04 15:26:04 -07002677 // The dirty rectangle can be modified by Surface.lockCanvas()
2678 //noinspection ConstantConditions
Alan Viverettea51cab92014-07-16 15:15:49 -07002679 if (left != dirty.left || top != dirty.top || right != dirty.right
2680 || bottom != dirty.bottom) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002681 attachInfo.mIgnoreDirtyState = true;
2682 }
2683
2684 // TODO: Do this in native
2685 canvas.setDensity(mDensity);
2686 } catch (Surface.OutOfResourcesException e) {
Romain Guy3696779b2013-01-28 14:04:07 -08002687 handleOutOfResourcesException(e);
Romain Guy25eba5c2012-04-04 17:29:03 -07002688 return false;
2689 } catch (IllegalArgumentException e) {
Romain Guydddcd222012-05-18 15:33:57 -07002690 Log.e(TAG, "Could not lock surface", e);
Romain Guy25eba5c2012-04-04 17:29:03 -07002691 // Don't assume this is due to out of memory, it could be
2692 // something else, and if it is something else then we could
2693 // kill stuff (or ourself) for no reason.
2694 mLayoutRequested = true; // ask wm for a new surface next time.
2695 return false;
2696 }
2697
2698 try {
2699 if (DEBUG_ORIENTATION || DEBUG_DRAW) {
2700 Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
2701 + canvas.getWidth() + ", h=" + canvas.getHeight());
2702 //canvas.drawARGB(255, 255, 0, 0);
2703 }
2704
Romain Guy25eba5c2012-04-04 17:29:03 -07002705 // If this bitmap's format includes an alpha channel, we
2706 // need to clear it before drawing so that the child will
2707 // properly re-composite its drawing on a transparent
2708 // background. This automatically respects the clip/dirty region
2709 // or
2710 // If we are applying an offset, we need to clear the area
2711 // where the offset doesn't appear to avoid having garbage
2712 // left in the blank areas.
Alan Viveretteccb11e12014-07-08 16:04:02 -07002713 if (!canvas.isOpaque() || yoff != 0 || xoff != 0) {
Romain Guy25eba5c2012-04-04 17:29:03 -07002714 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
2715 }
2716
2717 dirty.setEmpty();
2718 mIsAnimating = false;
Dianne Hackborn4702a852012-08-17 15:18:29 -07002719 mView.mPrivateFlags |= View.PFLAG_DRAWN;
Romain Guy25eba5c2012-04-04 17:29:03 -07002720
2721 if (DEBUG_DRAW) {
2722 Context cxt = mView.getContext();
2723 Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
2724 ", metrics=" + cxt.getResources().getDisplayMetrics() +
2725 ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
2726 }
2727 try {
Alan Viveretteccb11e12014-07-08 16:04:02 -07002728 canvas.translate(-xoff, -yoff);
Romain Guy25eba5c2012-04-04 17:29:03 -07002729 if (mTranslator != null) {
2730 mTranslator.translateCanvas(canvas);
2731 }
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002732 canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
Romain Guy25eba5c2012-04-04 17:29:03 -07002733 attachInfo.mSetIgnoreDirtyState = false;
2734
Romain Guy25eba5c2012-04-04 17:29:03 -07002735 mView.draw(canvas);
Alan Viverette632af842014-10-28 13:45:11 -07002736
2737 drawAccessibilityFocusedDrawableIfNeeded(canvas);
Romain Guy25eba5c2012-04-04 17:29:03 -07002738 } finally {
2739 if (!attachInfo.mSetIgnoreDirtyState) {
2740 // Only clear the flag if it was not set during the mView.draw() call
2741 attachInfo.mIgnoreDirtyState = false;
2742 }
2743 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002744 } finally {
Romain Guydddcd222012-05-18 15:33:57 -07002745 try {
2746 surface.unlockCanvasAndPost(canvas);
2747 } catch (IllegalArgumentException e) {
2748 Log.e(TAG, "Could not unlock surface", e);
2749 mLayoutRequested = true; // ask wm for a new surface next time.
2750 //noinspection ReturnInsideFinallyBlock
2751 return false;
2752 }
Romain Guy25eba5c2012-04-04 17:29:03 -07002753
Romain Guy25eba5c2012-04-04 17:29:03 -07002754 if (LOCAL_LOGV) {
2755 Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
2756 }
2757 }
2758 return true;
2759 }
2760
Alan Viverette632af842014-10-28 13:45:11 -07002761 /**
2762 * We want to draw a highlight around the current accessibility focused.
2763 * Since adding a style for all possible view is not a viable option we
2764 * have this specialized drawing method.
2765 *
2766 * Note: We are doing this here to be able to draw the highlight for
2767 * virtual views in addition to real ones.
2768 *
2769 * @param canvas The canvas on which to draw.
2770 */
2771 private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
2772 final Rect bounds = mAttachInfo.mTmpInvalRect;
2773 if (getAccessibilityFocusedRect(bounds)) {
2774 final Drawable drawable = getAccessibilityFocusedDrawable();
2775 if (drawable != null) {
2776 drawable.setBounds(bounds);
2777 drawable.draw(canvas);
2778 }
2779 } else if (mAttachInfo.mAccessibilityFocusDrawable != null) {
2780 mAttachInfo.mAccessibilityFocusDrawable.setBounds(0, 0, 0, 0);
2781 }
2782 }
2783
2784 private boolean getAccessibilityFocusedRect(Rect bounds) {
2785 final AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
2786 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
2787 return false;
2788 }
2789
2790 final View host = mAccessibilityFocusedHost;
2791 if (host == null || host.mAttachInfo == null) {
2792 return false;
2793 }
2794
2795 final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
2796 if (provider == null) {
Svetoslavded133c2015-01-30 20:28:41 -08002797 host.getBoundsOnScreen(bounds, true);
Alan Viverette632af842014-10-28 13:45:11 -07002798 } else if (mAccessibilityFocusedVirtualView != null) {
2799 mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
2800 } else {
2801 return false;
2802 }
2803
Alan Viverette2232add2015-05-26 15:24:18 -07002804 // Transform the rect into window-relative coordinates.
Alan Viverette632af842014-10-28 13:45:11 -07002805 final AttachInfo attachInfo = mAttachInfo;
Alan Viverette2232add2015-05-26 15:24:18 -07002806 bounds.offset(0, attachInfo.mViewRootImpl.mScrollY);
Alan Viverette632af842014-10-28 13:45:11 -07002807 bounds.offset(-attachInfo.mWindowLeft, -attachInfo.mWindowTop);
Doris Liu9607fbe2015-05-28 17:17:28 -07002808 if (!bounds.intersect(0, 0, attachInfo.mViewRootImpl.mWidth,
2809 attachInfo.mViewRootImpl.mHeight)) {
2810 // If no intersection, set bounds to empty.
2811 bounds.setEmpty();
2812 }
Alan Viverette632af842014-10-28 13:45:11 -07002813 return !bounds.isEmpty();
2814 }
2815
2816 private Drawable getAccessibilityFocusedDrawable() {
Chris Craikd36a81f2014-07-17 10:16:51 -07002817 // Lazily load the accessibility focus drawable.
2818 if (mAttachInfo.mAccessibilityFocusDrawable == null) {
Alan Viverettef6cf1a02014-08-11 14:13:02 -07002819 final TypedValue value = new TypedValue();
Chris Craikd36a81f2014-07-17 10:16:51 -07002820 final boolean resolved = mView.mContext.getTheme().resolveAttribute(
2821 R.attr.accessibilityFocusedDrawable, value, true);
2822 if (resolved) {
2823 mAttachInfo.mAccessibilityFocusDrawable =
Alan Viverette8eea3ea2014-02-03 18:40:20 -08002824 mView.mContext.getDrawable(value.resourceId);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002825 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002826 }
Chris Craikd36a81f2014-07-17 10:16:51 -07002827 return mAttachInfo.mAccessibilityFocusDrawable;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002828 }
2829
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002830 boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
Chris Craikd36a81f2014-07-17 10:16:51 -07002831 final Rect ci = mAttachInfo.mContentInsets;
2832 final Rect vi = mAttachInfo.mVisibleInsets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002833 int scrollY = 0;
2834 boolean handled = false;
Romain Guy8506ab42009-06-11 17:35:47 -07002835
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002836 if (vi.left > ci.left || vi.top > ci.top
2837 || vi.right > ci.right || vi.bottom > ci.bottom) {
2838 // We'll assume that we aren't going to change the scroll
2839 // offset, since we want to avoid that unless it is actually
2840 // going to make the focus visible... otherwise we scroll
2841 // all over the place.
2842 scrollY = mScrollY;
2843 // We can be called for two different situations: during a draw,
2844 // to update the scroll position if the focus has changed (in which
2845 // case 'rectangle' is null), or in response to a
2846 // requestChildRectangleOnScreen() call (in which case 'rectangle'
2847 // is non-null and we just want to scroll to whatever that
2848 // rectangle is).
Craig Mautner26a84df2013-04-11 19:09:05 -07002849 final View focus = mView.findFocus();
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002850 if (focus == null) {
Romain Guye8b16522009-07-14 13:06:42 -07002851 return false;
2852 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002853 View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null;
Craig Mautner26a84df2013-04-11 19:09:05 -07002854 if (focus != lastScrolledFocus) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002855 // If the focus has changed, then ignore any requests to scroll
2856 // to a rectangle; first we want to make sure the entire focus
2857 // view is visible.
2858 rectangle = null;
2859 }
2860 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus
2861 + " rectangle=" + rectangle + " ci=" + ci
2862 + " vi=" + vi);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002863 if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002864 // Optimization: if the focus hasn't changed since last
2865 // time, and no layout has happened, then just leave things
2866 // as they are.
2867 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y="
2868 + mScrollY + " vi=" + vi.toShortString());
Craig Mautner26a84df2013-04-11 19:09:05 -07002869 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002870 // We need to determine if the currently focused view is
2871 // within the visible part of the window and, if not, apply
2872 // a pan so it can be seen.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08002873 mLastScrolledFocus = new WeakReference<View>(focus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002874 mScrollMayChange = false;
2875 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?");
2876 // Try to find the rectangle from the focus view.
2877 if (focus.getGlobalVisibleRect(mVisRect, null)) {
2878 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w="
2879 + mView.getWidth() + " h=" + mView.getHeight()
2880 + " ci=" + ci.toShortString()
2881 + " vi=" + vi.toShortString());
2882 if (rectangle == null) {
2883 focus.getFocusedRect(mTempRect);
2884 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus
2885 + ": focusRect=" + mTempRect.toShortString());
Dianne Hackborn1c6a8942010-03-23 16:34:20 -07002886 if (mView instanceof ViewGroup) {
2887 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
2888 focus, mTempRect);
2889 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002890 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2891 "Focus in window: focusRect="
2892 + mTempRect.toShortString()
2893 + " visRect=" + mVisRect.toShortString());
2894 } else {
2895 mTempRect.set(rectangle);
2896 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2897 "Request scroll to rect: "
2898 + mTempRect.toShortString()
2899 + " visRect=" + mVisRect.toShortString());
2900 }
2901 if (mTempRect.intersect(mVisRect)) {
2902 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2903 "Focus window visible rect: "
2904 + mTempRect.toShortString());
2905 if (mTempRect.height() >
2906 (mView.getHeight()-vi.top-vi.bottom)) {
2907 // If the focus simply is not going to fit, then
2908 // best is probably just to leave things as-is.
2909 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2910 "Too tall; leaving scrollY=" + scrollY);
2911 } else if ((mTempRect.top-scrollY) < vi.top) {
2912 scrollY -= vi.top - (mTempRect.top-scrollY);
2913 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2914 "Top covered; scrollY=" + scrollY);
2915 } else if ((mTempRect.bottom-scrollY)
2916 > (mView.getHeight()-vi.bottom)) {
2917 scrollY += (mTempRect.bottom-scrollY)
2918 - (mView.getHeight()-vi.bottom);
2919 if (DEBUG_INPUT_RESIZE) Log.v(TAG,
2920 "Bottom covered; scrollY=" + scrollY);
2921 }
2922 handled = true;
2923 }
2924 }
2925 }
2926 }
Romain Guy8506ab42009-06-11 17:35:47 -07002927
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002928 if (scrollY != mScrollY) {
2929 if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
2930 + mScrollY + " , new=" + scrollY);
Derek Sollenberger8d948352015-07-16 09:27:59 -04002931 if (!immediate) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002932 if (mScroller == null) {
2933 mScroller = new Scroller(mView.getContext());
2934 }
2935 mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY);
2936 } else if (mScroller != null) {
2937 mScroller.abortAnimation();
2938 }
2939 mScrollY = scrollY;
2940 }
Romain Guy8506ab42009-06-11 17:35:47 -07002941
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002942 return handled;
2943 }
Romain Guy8506ab42009-06-11 17:35:47 -07002944
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07002945 /**
2946 * @hide
2947 */
2948 public View getAccessibilityFocusedHost() {
2949 return mAccessibilityFocusedHost;
2950 }
2951
2952 /**
2953 * @hide
2954 */
2955 public AccessibilityNodeInfo getAccessibilityFocusedVirtualView() {
2956 return mAccessibilityFocusedVirtualView;
2957 }
2958
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002959 void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002960 // If we have a virtual view with accessibility focus we need
2961 // to clear the focus and invalidate the virtual view bounds.
2962 if (mAccessibilityFocusedVirtualView != null) {
2963
2964 AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
2965 View focusHost = mAccessibilityFocusedHost;
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002966
2967 // Wipe the state of the current accessibility focus since
2968 // the call into the provider to clear accessibility focus
2969 // will fire an accessibility event which will end up calling
2970 // this method and we want to have clean state when this
2971 // invocation happens.
2972 mAccessibilityFocusedHost = null;
2973 mAccessibilityFocusedVirtualView = null;
2974
Alan Viverette239a0c02013-05-07 17:17:35 -07002975 // Clear accessibility focus on the host after clearing state since
2976 // this method may be reentrant.
2977 focusHost.clearAccessibilityFocusNoCallbacks();
2978
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002979 AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
2980 if (provider != null) {
2981 // Invalidate the area of the cleared accessibility focus.
2982 focusNode.getBoundsInParent(mTempRect);
2983 focusHost.invalidate(mTempRect);
2984 // Clear accessibility focus in the virtual node.
2985 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
2986 focusNode.getSourceNodeId());
2987 provider.performAction(virtualNodeId,
2988 AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
2989 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002990 focusNode.recycle();
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002991 }
2992 if (mAccessibilityFocusedHost != null) {
2993 // Clear accessibility focus in the view.
Svetoslav Ganov42138042012-03-20 11:51:39 -07002994 mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks();
2995 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07002996
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07002997 // Set the new focus host and node.
2998 mAccessibilityFocusedHost = view;
2999 mAccessibilityFocusedVirtualView = node;
John Reck0a973302014-07-16 13:29:45 -07003000
3001 if (mAttachInfo.mHardwareRenderer != null) {
3002 mAttachInfo.mHardwareRenderer.invalidateRoot();
3003 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07003004 }
3005
Igor Murashkina86ab6402013-08-30 12:58:36 -07003006 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003007 public void requestChildFocus(View child, View focused) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003008 if (DEBUG_INPUT_RESIZE) {
3009 Log.v(TAG, "Request child focus: focus now " + focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003010 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003011 checkThread();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003012 scheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003013 }
3014
Igor Murashkina86ab6402013-08-30 12:58:36 -07003015 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003016 public void clearChildFocus(View child) {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003017 if (DEBUG_INPUT_RESIZE) {
3018 Log.v(TAG, "Clearing child focus");
Amith Yamasani73eb97f2012-02-14 15:45:15 -08003019 }
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003020 checkThread();
3021 scheduleTraversals();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -08003022 }
Amith Yamasani73eb97f2012-02-14 15:45:15 -08003023
Svetoslav Ganov42138042012-03-20 11:51:39 -07003024 @Override
3025 public ViewParent getParentForAccessibility() {
3026 return null;
3027 }
3028
Igor Murashkina86ab6402013-08-30 12:58:36 -07003029 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003030 public void focusableViewAvailable(View v) {
3031 checkThread();
Romain Guy1c90f032011-05-24 14:59:50 -07003032 if (mView != null) {
3033 if (!mView.hasFocus()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003034 v.requestFocus();
Romain Guy1c90f032011-05-24 14:59:50 -07003035 } else {
3036 // the one case where will transfer focus away from the current one
3037 // is if the current view is a view group that prefers to give focus
3038 // to its children first AND the view is a descendant of it.
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003039 View focused = mView.findFocus();
3040 if (focused instanceof ViewGroup) {
3041 ViewGroup group = (ViewGroup) focused;
3042 if (group.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
3043 && isViewDescendantOf(v, focused)) {
3044 v.requestFocus();
3045 }
Romain Guy1c90f032011-05-24 14:59:50 -07003046 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003047 }
3048 }
3049 }
3050
Igor Murashkina86ab6402013-08-30 12:58:36 -07003051 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003052 public void recomputeViewAttributes(View child) {
3053 checkThread();
3054 if (mView == child) {
3055 mAttachInfo.mRecomputeGlobalAttributes = true;
3056 if (!mWillDrawSoon) {
3057 scheduleTraversals();
3058 }
3059 }
3060 }
3061
3062 void dispatchDetachedFromWindow() {
Romain Guy90fc03b2011-01-16 13:07:15 -08003063 if (mView != null && mView.mAttachInfo != null) {
Dianne Hackborn961cae92013-03-20 14:59:43 -07003064 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003065 mView.dispatchDetachedFromWindow();
3066 }
3067
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003068 mAccessibilityInteractionConnectionManager.ensureNoConnection();
3069 mAccessibilityManager.removeAccessibilityStateChangeListener(
3070 mAccessibilityInteractionConnectionManager);
Chris Craikcce47eb2014-07-16 15:12:15 -07003071 mAccessibilityManager.removeHighTextContrastStateChangeListener(
3072 mHighContrastTextManager);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07003073 removeSendWindowContentChangedCallback();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003074
Romain Guya998dff2012-03-23 18:58:36 -07003075 destroyHardwareRenderer();
3076
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003077 setAccessibilityFocus(null, null);
Svetoslav Ganov791fd312012-05-14 15:12:30 -07003078
Craig Mautner8f303ad2013-06-14 11:32:22 -07003079 mView.assignParent(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003080 mView = null;
3081 mAttachInfo.mRootView = null;
3082
Dianne Hackborn0586a1b2009-09-06 21:08:27 -07003083 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003084
Jeff Browncc4f7db2011-08-30 20:34:48 -07003085 if (mInputQueueCallback != null && mInputQueue != null) {
3086 mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
Michael Wrighta44dd262013-04-10 21:12:00 -07003087 mInputQueue.dispose();
Jeff Browncc4f7db2011-08-30 20:34:48 -07003088 mInputQueueCallback = null;
3089 mInputQueue = null;
Michael Wrighta44dd262013-04-10 21:12:00 -07003090 }
3091 if (mInputEventReceiver != null) {
Jeff Brown32cbc38552011-12-01 14:01:49 -08003092 mInputEventReceiver.dispose();
3093 mInputEventReceiver = null;
Jeff Brown46b9ac02010-04-22 18:58:52 -07003094 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003095 try {
Jeff Brown98365d72012-08-19 20:30:52 -07003096 mWindowSession.remove(mWindow);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003097 } catch (RemoteException e) {
3098 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003099
Jeff Brown00fa7bd2010-07-02 15:37:36 -07003100 // Dispose the input channel after removing the window so the Window Manager
3101 // doesn't interpret the input channel being closed as an abnormal termination.
3102 if (mInputChannel != null) {
3103 mInputChannel.dispose();
3104 mInputChannel = null;
Jeff Brown349703e2010-06-22 01:27:15 -07003105 }
Jeff Brown96e942d2011-11-30 19:55:01 -08003106
Jeff Brownd912e1f2014-04-11 18:46:22 -07003107 mDisplayManager.unregisterDisplayListener(mDisplayListener);
3108
Jeff Brownebb2d8d2012-03-23 17:14:34 -07003109 unscheduleTraversals();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003110 }
Romain Guy8506ab42009-06-11 17:35:47 -07003111
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003112 void updateConfiguration(Configuration config, boolean force) {
3113 if (DEBUG_CONFIGURATION) Log.v(TAG,
3114 "Applying new config to window "
3115 + mWindowAttributes.getTitle()
3116 + ": " + config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07003117
Craig Mautner48d0d182013-06-11 07:53:06 -07003118 CompatibilityInfo ci = mDisplayAdjustments.getCompatibilityInfo();
3119 if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
Dianne Hackborn5fd21692011-06-07 14:09:47 -07003120 config = new Configuration(config);
Dianne Hackborn908aecc2012-07-31 16:37:34 -07003121 ci.applyToConfiguration(mNoncompatDensity, config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07003122 }
3123
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003124 synchronized (sConfigCallbacks) {
3125 for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
3126 sConfigCallbacks.get(i).onConfigurationChanged(config);
3127 }
3128 }
3129 if (mView != null) {
3130 // At this point the resources have been updated to
3131 // have the most recent config, whatever that is. Use
Dianne Hackborn908aecc2012-07-31 16:37:34 -07003132 // the one in them which may be newer.
Romain Guy1c90f032011-05-24 14:59:50 -07003133 config = mView.getResources().getConfiguration();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003134 if (force || mLastConfiguration.diff(config) != 0) {
Fabrice Di Megliocf128972012-10-16 20:51:12 -07003135 final int lastLayoutDirection = mLastConfiguration.getLayoutDirection();
3136 final int currentLayoutDirection = config.getLayoutDirection();
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003137 mLastConfiguration.setTo(config);
Fabrice Di Megliob003e282012-10-17 17:20:19 -07003138 if (lastLayoutDirection != currentLayoutDirection &&
3139 mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
Fabrice Di Megliocf128972012-10-16 20:51:12 -07003140 mView.setLayoutDirection(currentLayoutDirection);
3141 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07003142 mView.dispatchConfigurationChanged(config);
3143 }
3144 }
3145 }
John Reck05e85842014-04-23 14:48:28 -07003146
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003147 /**
3148 * Return true if child is an ancestor of parent, (or equal to the parent).
3149 */
Svetoslav Ganove5dfa47d2012-05-08 15:58:32 -07003150 public static boolean isViewDescendantOf(View child, View parent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003151 if (child == parent) {
3152 return true;
3153 }
3154
3155 final ViewParent theParent = child.getParent();
3156 return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
3157 }
3158
Yohei Yukawad2e56472015-07-28 17:00:33 -07003159 private static void forceLayout(View view) {
3160 view.forceLayout();
3161 if (view instanceof ViewGroup) {
3162 ViewGroup group = (ViewGroup) view;
3163 final int count = group.getChildCount();
3164 for (int i = 0; i < count; i++) {
3165 forceLayout(group.getChildAt(i));
3166 }
3167 }
3168 }
3169
Jeff Browna175a5b2012-02-15 19:18:31 -08003170 private final static int MSG_INVALIDATE = 1;
3171 private final static int MSG_INVALIDATE_RECT = 2;
3172 private final static int MSG_DIE = 3;
3173 private final static int MSG_RESIZED = 4;
3174 private final static int MSG_RESIZED_REPORT = 5;
3175 private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
keunyoung30f420f2013-08-02 14:23:10 -07003176 private final static int MSG_DISPATCH_INPUT_EVENT = 7;
Jeff Browna175a5b2012-02-15 19:18:31 -08003177 private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
3178 private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
Jeff Browna175a5b2012-02-15 19:18:31 -08003179 private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
3180 private final static int MSG_FINISH_INPUT_CONNECTION = 12;
3181 private final static int MSG_CHECK_FOCUS = 13;
3182 private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
3183 private final static int MSG_DISPATCH_DRAG_EVENT = 15;
3184 private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
3185 private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
3186 private final static int MSG_UPDATE_CONFIGURATION = 18;
Svetoslav Ganov42138042012-03-20 11:51:39 -07003187 private final static int MSG_PROCESS_INPUT_EVENTS = 19;
Romain Guyfbb93fa2012-12-03 18:50:35 -08003188 private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
Jorim Jaggi827e0fa2015-05-07 11:41:41 -07003189 private final static int MSG_INVALIDATE_WORLD = 22;
3190 private final static int MSG_WINDOW_MOVED = 23;
3191 private final static int MSG_SYNTHESIZE_INPUT_EVENT = 24;
3192 private final static int MSG_DISPATCH_WINDOW_SHOWN = 25;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003193
Jeff Browna175a5b2012-02-15 19:18:31 -08003194 final class ViewRootHandler extends Handler {
3195 @Override
3196 public String getMessageName(Message message) {
3197 switch (message.what) {
3198 case MSG_INVALIDATE:
3199 return "MSG_INVALIDATE";
3200 case MSG_INVALIDATE_RECT:
3201 return "MSG_INVALIDATE_RECT";
3202 case MSG_DIE:
3203 return "MSG_DIE";
3204 case MSG_RESIZED:
3205 return "MSG_RESIZED";
3206 case MSG_RESIZED_REPORT:
3207 return "MSG_RESIZED_REPORT";
3208 case MSG_WINDOW_FOCUS_CHANGED:
3209 return "MSG_WINDOW_FOCUS_CHANGED";
keunyoung30f420f2013-08-02 14:23:10 -07003210 case MSG_DISPATCH_INPUT_EVENT:
3211 return "MSG_DISPATCH_INPUT_EVENT";
Jeff Browna175a5b2012-02-15 19:18:31 -08003212 case MSG_DISPATCH_APP_VISIBILITY:
3213 return "MSG_DISPATCH_APP_VISIBILITY";
3214 case MSG_DISPATCH_GET_NEW_SURFACE:
3215 return "MSG_DISPATCH_GET_NEW_SURFACE";
Jeff Browna175a5b2012-02-15 19:18:31 -08003216 case MSG_DISPATCH_KEY_FROM_IME:
3217 return "MSG_DISPATCH_KEY_FROM_IME";
3218 case MSG_FINISH_INPUT_CONNECTION:
3219 return "MSG_FINISH_INPUT_CONNECTION";
3220 case MSG_CHECK_FOCUS:
3221 return "MSG_CHECK_FOCUS";
3222 case MSG_CLOSE_SYSTEM_DIALOGS:
3223 return "MSG_CLOSE_SYSTEM_DIALOGS";
3224 case MSG_DISPATCH_DRAG_EVENT:
3225 return "MSG_DISPATCH_DRAG_EVENT";
3226 case MSG_DISPATCH_DRAG_LOCATION_EVENT:
3227 return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
3228 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
3229 return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
3230 case MSG_UPDATE_CONFIGURATION:
3231 return "MSG_UPDATE_CONFIGURATION";
Jeff Browna175a5b2012-02-15 19:18:31 -08003232 case MSG_PROCESS_INPUT_EVENTS:
3233 return "MSG_PROCESS_INPUT_EVENTS";
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003234 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
3235 return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
Craig Mautner5702d4d2012-06-30 14:10:16 -07003236 case MSG_WINDOW_MOVED:
3237 return "MSG_WINDOW_MOVED";
Michael Wright899d7052014-04-23 17:23:39 -07003238 case MSG_SYNTHESIZE_INPUT_EVENT:
3239 return "MSG_SYNTHESIZE_INPUT_EVENT";
Craig Mautner9c795042014-10-28 19:59:59 -07003240 case MSG_DISPATCH_WINDOW_SHOWN:
3241 return "MSG_DISPATCH_WINDOW_SHOWN";
Jeff Browna175a5b2012-02-15 19:18:31 -08003242 }
3243 return super.getMessageName(message);
Romain Guyf9284692011-07-13 18:46:21 -07003244 }
Romain Guyf9284692011-07-13 18:46:21 -07003245
Jeff Browna175a5b2012-02-15 19:18:31 -08003246 @Override
3247 public void handleMessage(Message msg) {
3248 switch (msg.what) {
3249 case MSG_INVALIDATE:
3250 ((View) msg.obj).invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003251 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003252 case MSG_INVALIDATE_RECT:
3253 final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
3254 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08003255 info.recycle();
Jeff Browna175a5b2012-02-15 19:18:31 -08003256 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003257 case MSG_PROCESS_INPUT_EVENTS:
3258 mProcessInputEventsScheduled = false;
3259 doProcessInputEvents();
3260 break;
3261 case MSG_DISPATCH_APP_VISIBILITY:
3262 handleAppVisibility(msg.arg1 != 0);
3263 break;
3264 case MSG_DISPATCH_GET_NEW_SURFACE:
3265 handleGetNewSurface();
3266 break;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003267 case MSG_RESIZED: {
3268 // Recycled in the fall through...
3269 SomeArgs args = (SomeArgs) msg.obj;
Romain Guydfab3632012-10-03 14:53:25 -07003270 if (mWinFrame.equals(args.arg1)
Dianne Hackbornc4aad012013-02-22 15:05:25 -08003271 && mPendingOverscanInsets.equals(args.arg5)
Romain Guydfab3632012-10-03 14:53:25 -07003272 && mPendingContentInsets.equals(args.arg2)
Adrian Roosfa104232014-06-20 16:10:14 -07003273 && mPendingStableInsets.equals(args.arg6)
Romain Guydfab3632012-10-03 14:53:25 -07003274 && mPendingVisibleInsets.equals(args.arg3)
Filip Gruszczynski2217f612015-05-26 11:32:08 -07003275 && mPendingOutsets.equals(args.arg7)
Romain Guydfab3632012-10-03 14:53:25 -07003276 && args.arg4 == null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003277 break;
Romain Guycdb86672010-03-18 18:54:50 -07003278 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003279 } // fall through...
Jeff Browna175a5b2012-02-15 19:18:31 -08003280 case MSG_RESIZED_REPORT:
3281 if (mAdded) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003282 SomeArgs args = (SomeArgs) msg.obj;
3283
3284 Configuration config = (Configuration) args.arg4;
Jeff Browna175a5b2012-02-15 19:18:31 -08003285 if (config != null) {
3286 updateConfiguration(config, false);
3287 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003288
3289 mWinFrame.set((Rect) args.arg1);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08003290 mPendingOverscanInsets.set((Rect) args.arg5);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003291 mPendingContentInsets.set((Rect) args.arg2);
Adrian Roosfa104232014-06-20 16:10:14 -07003292 mPendingStableInsets.set((Rect) args.arg6);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003293 mPendingVisibleInsets.set((Rect) args.arg3);
Filip Gruszczynski2217f612015-05-26 11:32:08 -07003294 mPendingOutsets.set((Rect) args.arg7);
Jorim Jaggia7262a82015-11-03 15:15:40 +01003295 mPendingBackDropFrame.set((Rect) args.arg8);
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003296
3297 args.recycle();
3298
Jeff Browna175a5b2012-02-15 19:18:31 -08003299 if (msg.what == MSG_RESIZED_REPORT) {
3300 mReportNextDraw = true;
3301 }
Romain Guy59a12ca2011-06-09 17:48:21 -07003302
Yohei Yukawad2e56472015-07-28 17:00:33 -07003303 if (mView != null) {
3304 forceLayout(mView);
3305 }
3306
Jeff Browna175a5b2012-02-15 19:18:31 -08003307 requestLayout();
3308 }
3309 break;
Craig Mautner5702d4d2012-06-30 14:10:16 -07003310 case MSG_WINDOW_MOVED:
3311 if (mAdded) {
3312 final int w = mWinFrame.width();
3313 final int h = mWinFrame.height();
3314 final int l = msg.arg1;
3315 final int t = msg.arg2;
3316 mWinFrame.left = l;
3317 mWinFrame.right = l + w;
3318 mWinFrame.top = t;
3319 mWinFrame.bottom = t + h;
3320
Jorim Jaggia7262a82015-11-03 15:15:40 +01003321 mPendingBackDropFrame.set(mWinFrame);
3322
Yohei Yukawad2e56472015-07-28 17:00:33 -07003323 if (mView != null) {
3324 forceLayout(mView);
3325 }
Craig Mautner5702d4d2012-06-30 14:10:16 -07003326 requestLayout();
3327 }
3328 break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003329 case MSG_WINDOW_FOCUS_CHANGED: {
3330 if (mAdded) {
3331 boolean hasWindowFocus = msg.arg1 != 0;
3332 mAttachInfo.mHasWindowFocus = hasWindowFocus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003333
Jeff Browna175a5b2012-02-15 19:18:31 -08003334 profileRendering(hasWindowFocus);
3335
3336 if (hasWindowFocus) {
3337 boolean inTouchMode = msg.arg2 != 0;
3338 ensureTouchModeLocally(inTouchMode);
3339
Romain Guye55945e2013-04-04 15:26:04 -07003340 if (mAttachInfo.mHardwareRenderer != null && mSurface.isValid()){
Jeff Browna175a5b2012-02-15 19:18:31 -08003341 mFullRedrawNeeded = true;
Dianne Hackborn64825172011-03-02 21:32:58 -08003342 try {
Alan Viveretteccb11e12014-07-08 16:04:02 -07003343 final WindowManager.LayoutParams lp = mWindowAttributes;
Alan Viverette49a22e82014-07-12 20:01:27 -07003344 final Rect surfaceInsets = lp != null ? lp.surfaceInsets : null;
Romain Guy3696779b2013-01-28 14:04:07 -08003345 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
Alan Viverette50210d92015-05-14 18:05:36 -07003346 mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
Igor Murashkina86ab6402013-08-30 12:58:36 -07003347 } catch (OutOfResourcesException e) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003348 Log.e(TAG, "OutOfResourcesException locking surface", e);
3349 try {
Jeff Brown98365d72012-08-19 20:30:52 -07003350 if (!mWindowSession.outOfMemory(mWindow)) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003351 Slog.w(TAG, "No processes killed for memory; killing self");
3352 Process.killProcess(Process.myPid());
3353 }
3354 } catch (RemoteException ex) {
Dianne Hackborn64825172011-03-02 21:32:58 -08003355 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003356 // Retry in a bit.
3357 sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
3358 return;
Dianne Hackborn64825172011-03-02 21:32:58 -08003359 }
Dianne Hackborn64825172011-03-02 21:32:58 -08003360 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003361 }
Romain Guy8506ab42009-06-11 17:35:47 -07003362
Jeff Browna175a5b2012-02-15 19:18:31 -08003363 mLastWasImTarget = WindowManager.LayoutParams
3364 .mayUseInputMethod(mWindowAttributes.flags);
Romain Guy8506ab42009-06-11 17:35:47 -07003365
Jeff Browna175a5b2012-02-15 19:18:31 -08003366 InputMethodManager imm = InputMethodManager.peekInstance();
Yohei Yukawa5f059652015-05-14 22:16:41 -07003367 if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
3368 imm.onPreWindowFocus(mView, hasWindowFocus);
3369 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003370 if (mView != null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08003371 mAttachInfo.mKeyDispatchState.reset();
3372 mView.dispatchWindowFocusChanged(hasWindowFocus);
Dianne Hackborn961cae92013-03-20 14:59:43 -07003373 mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003374 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003375
Jeff Browna175a5b2012-02-15 19:18:31 -08003376 // Note: must be done after the focus change callbacks,
3377 // so all of the view state is set up correctly.
3378 if (hasWindowFocus) {
keunyoung30f420f2013-08-02 14:23:10 -07003379 if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
Yohei Yukawa5f059652015-05-14 22:16:41 -07003380 imm.onPostWindowFocus(mView, mView.findFocus(),
Jeff Browna175a5b2012-02-15 19:18:31 -08003381 mWindowAttributes.softInputMode,
3382 !mHasHadWindowFocus, mWindowAttributes.flags);
3383 }
3384 // Clear the forward bit. We can just do this directly, since
3385 // the window manager doesn't care about it.
3386 mWindowAttributes.softInputMode &=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003387 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
Jeff Browna175a5b2012-02-15 19:18:31 -08003388 ((WindowManager.LayoutParams)mView.getLayoutParams())
3389 .softInputMode &=
3390 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
3391 mHasHadWindowFocus = true;
3392 }
svetoslavganov75986cf2009-05-14 22:28:01 -07003393 }
Jeff Browna175a5b2012-02-15 19:18:31 -08003394 } break;
3395 case MSG_DIE:
3396 doDie();
3397 break;
keunyoung30f420f2013-08-02 14:23:10 -07003398 case MSG_DISPATCH_INPUT_EVENT: {
Jae Seo6a6059a2014-04-17 21:35:29 -07003399 SomeArgs args = (SomeArgs)msg.obj;
3400 InputEvent event = (InputEvent)args.arg1;
3401 InputEventReceiver receiver = (InputEventReceiver)args.arg2;
3402 enqueueInputEvent(event, receiver, 0, true);
3403 args.recycle();
Jeff Browna175a5b2012-02-15 19:18:31 -08003404 } break;
Michael Wright899d7052014-04-23 17:23:39 -07003405 case MSG_SYNTHESIZE_INPUT_EVENT: {
3406 InputEvent event = (InputEvent)msg.obj;
3407 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_UNHANDLED, true);
3408 } break;
Jeff Browna175a5b2012-02-15 19:18:31 -08003409 case MSG_DISPATCH_KEY_FROM_IME: {
3410 if (LOCAL_LOGV) Log.v(
3411 TAG, "Dispatching key "
3412 + msg.obj + " from IME to " + mView);
3413 KeyEvent event = (KeyEvent)msg.obj;
3414 if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
3415 // The IME is trying to say this event is from the
3416 // system! Bad bad bad!
3417 //noinspection UnusedAssignment
Michael Wright899d7052014-04-23 17:23:39 -07003418 event = KeyEvent.changeFlags(event, event.getFlags() &
3419 ~KeyEvent.FLAG_FROM_SYSTEM);
Jeff Browna175a5b2012-02-15 19:18:31 -08003420 }
3421 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
3422 } break;
3423 case MSG_FINISH_INPUT_CONNECTION: {
3424 InputMethodManager imm = InputMethodManager.peekInstance();
3425 if (imm != null) {
3426 imm.reportFinishInputConnection((InputConnection)msg.obj);
3427 }
3428 } break;
3429 case MSG_CHECK_FOCUS: {
3430 InputMethodManager imm = InputMethodManager.peekInstance();
3431 if (imm != null) {
3432 imm.checkFocus();
3433 }
3434 } break;
3435 case MSG_CLOSE_SYSTEM_DIALOGS: {
3436 if (mView != null) {
3437 mView.onCloseSystemDialogs((String)msg.obj);
3438 }
3439 } break;
3440 case MSG_DISPATCH_DRAG_EVENT:
3441 case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
3442 DragEvent event = (DragEvent)msg.obj;
3443 event.mLocalState = mLocalDragState; // only present when this app called startDrag()
3444 handleDragEvent(event);
3445 } break;
3446 case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
Romain Guyfbb93fa2012-12-03 18:50:35 -08003447 handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj);
Jeff Browna175a5b2012-02-15 19:18:31 -08003448 } break;
3449 case MSG_UPDATE_CONFIGURATION: {
3450 Configuration config = (Configuration)msg.obj;
3451 if (config.isOtherSeqNewer(mLastConfiguration)) {
3452 config = mLastConfiguration;
3453 }
3454 updateConfiguration(config, false);
3455 } break;
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003456 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07003457 setAccessibilityFocus(null, null);
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07003458 } break;
Dianne Hackborna53de062012-05-08 18:53:51 -07003459 case MSG_INVALIDATE_WORLD: {
Romain Guyf84208f2012-09-13 22:50:18 -07003460 if (mView != null) {
3461 invalidateWorld(mView);
3462 }
Dianne Hackborna53de062012-05-08 18:53:51 -07003463 } break;
Craig Mautner9c795042014-10-28 19:59:59 -07003464 case MSG_DISPATCH_WINDOW_SHOWN: {
3465 handleDispatchWindowShown();
3466 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003467 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003468 }
3469 }
Romain Guy51e4d4d2012-03-15 18:30:47 -07003470
Jeff Browna175a5b2012-02-15 19:18:31 -08003471 final ViewRootHandler mHandler = new ViewRootHandler();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003472
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003473 /**
3474 * Something in the current window tells us we need to change the touch mode. For
3475 * example, we are not in touch mode, and the user touches the screen.
3476 *
3477 * If the touch mode has changed, tell the window manager, and handle it locally.
3478 *
3479 * @param inTouchMode Whether we want to be in touch mode.
3480 * @return True if the touch mode changed and focus changed was changed as a result
3481 */
3482 boolean ensureTouchMode(boolean inTouchMode) {
3483 if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
3484 + "touch mode is " + mAttachInfo.mInTouchMode);
3485 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3486
3487 // tell the window manager
3488 try {
keunyoung30f420f2013-08-02 14:23:10 -07003489 if (!isInLocalFocusMode()) {
3490 mWindowSession.setInTouchMode(inTouchMode);
3491 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003492 } catch (RemoteException e) {
3493 throw new RuntimeException(e);
3494 }
3495
3496 // handle the change
Romain Guy2d4cff62010-04-09 15:39:00 -07003497 return ensureTouchModeLocally(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003498 }
3499
3500 /**
3501 * Ensure that the touch mode for this window is set, and if it is changing,
3502 * take the appropriate action.
3503 * @param inTouchMode Whether we want to be in touch mode.
3504 * @return True if the touch mode changed and focus changed was changed as a result
3505 */
Romain Guy2d4cff62010-04-09 15:39:00 -07003506 private boolean ensureTouchModeLocally(boolean inTouchMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003507 if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
3508 + "touch mode is " + mAttachInfo.mInTouchMode);
3509
3510 if (mAttachInfo.mInTouchMode == inTouchMode) return false;
3511
3512 mAttachInfo.mInTouchMode = inTouchMode;
3513 mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
3514
Romain Guy2d4cff62010-04-09 15:39:00 -07003515 return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003516 }
3517
3518 private boolean enterTouchMode() {
Alan Viveretteed7821a2013-07-24 15:49:23 -07003519 if (mView != null && mView.hasFocus()) {
3520 // note: not relying on mFocusedView here because this could
3521 // be when the window is first being added, and mFocused isn't
3522 // set yet.
3523 final View focused = mView.findFocus();
3524 if (focused != null && !focused.isFocusableInTouchMode()) {
3525 final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
3526 if (ancestorToTakeFocus != null) {
3527 // there is an ancestor that wants focus after its
3528 // descendants that is focusable in touch mode.. give it
3529 // focus
3530 return ancestorToTakeFocus.requestFocus();
3531 } else {
Alan Viverette973f3b42013-08-13 16:57:28 -07003532 // There's nothing to focus. Clear and propagate through the
3533 // hierarchy, but don't attempt to place new focus.
Alan Viverette223622a2013-12-17 13:29:02 -08003534 focused.clearFocusInternal(null, true, false);
Alan Viveretteed7821a2013-07-24 15:49:23 -07003535 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003536 }
3537 }
3538 }
3539 return false;
3540 }
3541
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003542 /**
3543 * Find an ancestor of focused that wants focus after its descendants and is
3544 * focusable in touch mode.
3545 * @param focused The currently focused view.
3546 * @return An appropriate view, or null if no such view exists.
3547 */
Romain Guya998dff2012-03-23 18:58:36 -07003548 private static ViewGroup findAncestorToTakeFocusInTouchMode(View focused) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003549 ViewParent parent = focused.getParent();
3550 while (parent instanceof ViewGroup) {
3551 final ViewGroup vgParent = (ViewGroup) parent;
3552 if (vgParent.getDescendantFocusability() == ViewGroup.FOCUS_AFTER_DESCENDANTS
3553 && vgParent.isFocusableInTouchMode()) {
3554 return vgParent;
3555 }
3556 if (vgParent.isRootNamespace()) {
3557 return null;
3558 } else {
3559 parent = vgParent.getParent();
3560 }
3561 }
3562 return null;
3563 }
3564
3565 private boolean leaveTouchMode() {
3566 if (mView != null) {
3567 if (mView.hasFocus()) {
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003568 View focusedView = mView.findFocus();
3569 if (!(focusedView instanceof ViewGroup)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003570 // some view has focus, let it keep it
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003571 return false;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003572 } else if (((ViewGroup) focusedView).getDescendantFocusability() !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003573 ViewGroup.FOCUS_AFTER_DESCENDANTS) {
3574 // some view group has focus, and doesn't prefer its children
3575 // over itself for focus, so let them keep it.
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003576 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003577 }
3578 }
Svetoslav Ganovcf8a3b82012-04-30 16:49:59 -07003579
3580 // find the best view to give focus to in this brave new non-touch-mode
3581 // world
3582 final View focused = focusSearch(null, View.FOCUS_DOWN);
3583 if (focused != null) {
3584 return focused.requestFocus(View.FOCUS_DOWN);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003585 }
3586 }
3587 return false;
3588 }
3589
Jeff Brownf9e989d2013-04-04 23:04:03 -07003590 /**
3591 * Base class for implementing a stage in the chain of responsibility
3592 * for processing input events.
3593 * <p>
3594 * Events are delivered to the stage by the {@link #deliver} method. The stage
3595 * then has the choice of finishing the event or forwarding it to the next stage.
3596 * </p>
3597 */
3598 abstract class InputStage {
3599 private final InputStage mNext;
3600
3601 protected static final int FORWARD = 0;
3602 protected static final int FINISH_HANDLED = 1;
3603 protected static final int FINISH_NOT_HANDLED = 2;
3604
3605 /**
3606 * Creates an input stage.
3607 * @param next The next stage to which events should be forwarded.
3608 */
3609 public InputStage(InputStage next) {
3610 mNext = next;
3611 }
3612
3613 /**
3614 * Delivers an event to be processed.
3615 */
3616 public final void deliver(QueuedInputEvent q) {
3617 if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
3618 forward(q);
Michael Wright17d28ca2013-10-31 17:47:45 -07003619 } else if (shouldDropInputEvent(q)) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003620 finish(q, false);
3621 } else {
3622 apply(q, onProcess(q));
3623 }
3624 }
3625
3626 /**
3627 * Marks the the input event as finished then forwards it to the next stage.
3628 */
3629 protected void finish(QueuedInputEvent q, boolean handled) {
3630 q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
3631 if (handled) {
3632 q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
3633 }
3634 forward(q);
3635 }
3636
3637 /**
3638 * Forwards the event to the next stage.
3639 */
3640 protected void forward(QueuedInputEvent q) {
3641 onDeliverToNext(q);
3642 }
3643
3644 /**
3645 * Applies a result code from {@link #onProcess} to the specified event.
3646 */
3647 protected void apply(QueuedInputEvent q, int result) {
3648 if (result == FORWARD) {
3649 forward(q);
3650 } else if (result == FINISH_HANDLED) {
3651 finish(q, true);
3652 } else if (result == FINISH_NOT_HANDLED) {
3653 finish(q, false);
3654 } else {
3655 throw new IllegalArgumentException("Invalid result: " + result);
3656 }
3657 }
3658
3659 /**
3660 * Called when an event is ready to be processed.
3661 * @return A result code indicating how the event was handled.
3662 */
3663 protected int onProcess(QueuedInputEvent q) {
3664 return FORWARD;
3665 }
3666
3667 /**
3668 * Called when an event is being delivered to the next stage.
3669 */
3670 protected void onDeliverToNext(QueuedInputEvent q) {
Michael Wright06a79252014-05-05 17:45:29 -07003671 if (DEBUG_INPUT_STAGES) {
3672 Log.v(TAG, "Done with " + getClass().getSimpleName() + ". " + q);
3673 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003674 if (mNext != null) {
3675 mNext.deliver(q);
3676 } else {
3677 finishInputEvent(q);
3678 }
3679 }
Jeff Brown5182c782013-10-15 20:31:52 -07003680
Michael Wright17d28ca2013-10-31 17:47:45 -07003681 protected boolean shouldDropInputEvent(QueuedInputEvent q) {
3682 if (mView == null || !mAdded) {
3683 Slog.w(TAG, "Dropping event due to root view being removed: " + q.mEvent);
3684 return true;
George Mount41725de2015-04-09 08:23:05 -07003685 } else if ((!mAttachInfo.mHasWindowFocus
3686 && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) || mStopped
3687 || (mPausedForTransition && !isBack(q.mEvent))) {
Wale Ogunwalec3672cd2014-11-05 15:17:35 -08003688 // This is a focus event and the window doesn't currently have input focus or
3689 // has stopped. This could be an event that came back from the previous stage
3690 // but the window has lost focus or stopped in the meantime.
3691 if (isTerminalInputEvent(q.mEvent)) {
3692 // Don't drop terminal input events, however mark them as canceled.
3693 q.mEvent.cancel();
3694 Slog.w(TAG, "Cancelling event due to no window focus: " + q.mEvent);
3695 return false;
3696 }
3697
3698 // Drop non-terminal input events.
Michael Wright17d28ca2013-10-31 17:47:45 -07003699 Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent);
3700 return true;
3701 }
3702 return false;
3703 }
3704
Jeff Brown5182c782013-10-15 20:31:52 -07003705 void dump(String prefix, PrintWriter writer) {
3706 if (mNext != null) {
3707 mNext.dump(prefix, writer);
3708 }
3709 }
George Mount41725de2015-04-09 08:23:05 -07003710
3711 private boolean isBack(InputEvent event) {
3712 if (event instanceof KeyEvent) {
3713 return ((KeyEvent) event).getKeyCode() == KeyEvent.KEYCODE_BACK;
3714 } else {
3715 return false;
3716 }
3717 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003718 }
3719
3720 /**
3721 * Base class for implementing an input pipeline stage that supports
3722 * asynchronous and out-of-order processing of input events.
3723 * <p>
3724 * In addition to what a normal input stage can do, an asynchronous
3725 * input stage may also defer an input event that has been delivered to it
3726 * and finish or forward it later.
3727 * </p>
3728 */
3729 abstract class AsyncInputStage extends InputStage {
3730 private final String mTraceCounter;
3731
3732 private QueuedInputEvent mQueueHead;
3733 private QueuedInputEvent mQueueTail;
3734 private int mQueueLength;
3735
3736 protected static final int DEFER = 3;
3737
3738 /**
3739 * Creates an asynchronous input stage.
3740 * @param next The next stage to which events should be forwarded.
3741 * @param traceCounter The name of a counter to record the size of
3742 * the queue of pending events.
3743 */
3744 public AsyncInputStage(InputStage next, String traceCounter) {
3745 super(next);
3746 mTraceCounter = traceCounter;
3747 }
3748
3749 /**
3750 * Marks the event as deferred, which is to say that it will be handled
3751 * asynchronously. The caller is responsible for calling {@link #forward}
3752 * or {@link #finish} later when it is done handling the event.
3753 */
3754 protected void defer(QueuedInputEvent q) {
3755 q.mFlags |= QueuedInputEvent.FLAG_DEFERRED;
3756 enqueue(q);
3757 }
3758
3759 @Override
3760 protected void forward(QueuedInputEvent q) {
3761 // Clear the deferred flag.
3762 q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED;
3763
3764 // Fast path if the queue is empty.
3765 QueuedInputEvent curr = mQueueHead;
3766 if (curr == null) {
3767 super.forward(q);
3768 return;
3769 }
3770
3771 // Determine whether the event must be serialized behind any others
3772 // before it can be delivered to the next stage. This is done because
3773 // deferred events might be handled out of order by the stage.
3774 final int deviceId = q.mEvent.getDeviceId();
3775 QueuedInputEvent prev = null;
3776 boolean blocked = false;
3777 while (curr != null && curr != q) {
3778 if (!blocked && deviceId == curr.mEvent.getDeviceId()) {
3779 blocked = true;
3780 }
3781 prev = curr;
3782 curr = curr.mNext;
3783 }
3784
3785 // If the event is blocked, then leave it in the queue to be delivered later.
3786 // Note that the event might not yet be in the queue if it was not previously
3787 // deferred so we will enqueue it if needed.
3788 if (blocked) {
3789 if (curr == null) {
3790 enqueue(q);
3791 }
3792 return;
3793 }
3794
3795 // The event is not blocked. Deliver it immediately.
3796 if (curr != null) {
3797 curr = curr.mNext;
3798 dequeue(q, prev);
3799 }
3800 super.forward(q);
3801
3802 // Dequeuing this event may have unblocked successors. Deliver them.
3803 while (curr != null) {
3804 if (deviceId == curr.mEvent.getDeviceId()) {
3805 if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) {
3806 break;
3807 }
3808 QueuedInputEvent next = curr.mNext;
3809 dequeue(curr, prev);
3810 super.forward(curr);
3811 curr = next;
3812 } else {
3813 prev = curr;
3814 curr = curr.mNext;
3815 }
3816 }
3817 }
3818
3819 @Override
3820 protected void apply(QueuedInputEvent q, int result) {
3821 if (result == DEFER) {
3822 defer(q);
3823 } else {
3824 super.apply(q, result);
3825 }
3826 }
3827
3828 private void enqueue(QueuedInputEvent q) {
3829 if (mQueueTail == null) {
3830 mQueueHead = q;
3831 mQueueTail = q;
3832 } else {
3833 mQueueTail.mNext = q;
3834 mQueueTail = q;
3835 }
3836
3837 mQueueLength += 1;
3838 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
3839 }
3840
3841 private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) {
3842 if (prev == null) {
3843 mQueueHead = q.mNext;
3844 } else {
3845 prev.mNext = q.mNext;
3846 }
3847 if (mQueueTail == q) {
3848 mQueueTail = prev;
3849 }
3850 q.mNext = null;
3851
3852 mQueueLength -= 1;
3853 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
3854 }
Jeff Brown5182c782013-10-15 20:31:52 -07003855
3856 @Override
3857 void dump(String prefix, PrintWriter writer) {
3858 writer.print(prefix);
3859 writer.print(getClass().getName());
3860 writer.print(": mQueueLength=");
3861 writer.println(mQueueLength);
3862
3863 super.dump(prefix, writer);
3864 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003865 }
3866
3867 /**
3868 * Delivers pre-ime input events to a native activity.
3869 * Does not support pointer events.
3870 */
Michael Wrighta44dd262013-04-10 21:12:00 -07003871 final class NativePreImeInputStage extends AsyncInputStage
3872 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003873 public NativePreImeInputStage(InputStage next, String traceCounter) {
3874 super(next, traceCounter);
3875 }
3876
3877 @Override
3878 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07003879 if (mInputQueue != null && q.mEvent instanceof KeyEvent) {
3880 mInputQueue.sendInputEvent(q.mEvent, q, true, this);
3881 return DEFER;
3882 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003883 return FORWARD;
3884 }
Michael Wrighta44dd262013-04-10 21:12:00 -07003885
3886 @Override
3887 public void onFinishedInputEvent(Object token, boolean handled) {
3888 QueuedInputEvent q = (QueuedInputEvent)token;
3889 if (handled) {
3890 finish(q, true);
3891 return;
3892 }
3893 forward(q);
3894 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003895 }
3896
3897 /**
3898 * Delivers pre-ime input events to the view hierarchy.
3899 * Does not support pointer events.
3900 */
3901 final class ViewPreImeInputStage extends InputStage {
3902 public ViewPreImeInputStage(InputStage next) {
3903 super(next);
3904 }
3905
3906 @Override
3907 protected int onProcess(QueuedInputEvent q) {
Jeff Brown481c1572012-03-09 14:41:15 -08003908 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003909 return processKeyEvent(q);
3910 }
3911 return FORWARD;
3912 }
3913
3914 private int processKeyEvent(QueuedInputEvent q) {
3915 final KeyEvent event = (KeyEvent)q.mEvent;
3916 if (mView.dispatchKeyEventPreIme(event)) {
3917 return FINISH_HANDLED;
3918 }
3919 return FORWARD;
3920 }
3921 }
3922
3923 /**
3924 * Delivers input events to the ime.
3925 * Does not support pointer events.
3926 */
3927 final class ImeInputStage extends AsyncInputStage
3928 implements InputMethodManager.FinishedInputEventCallback {
3929 public ImeInputStage(InputStage next, String traceCounter) {
3930 super(next, traceCounter);
3931 }
3932
3933 @Override
3934 protected int onProcess(QueuedInputEvent q) {
keunyoung30f420f2013-08-02 14:23:10 -07003935 if (mLastWasImTarget && !isInLocalFocusMode()) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003936 InputMethodManager imm = InputMethodManager.peekInstance();
3937 if (imm != null) {
3938 final InputEvent event = q.mEvent;
3939 if (DEBUG_IMF) Log.v(TAG, "Sending input event to IME: " + event);
3940 int result = imm.dispatchInputEvent(event, q, this, mHandler);
3941 if (result == InputMethodManager.DISPATCH_HANDLED) {
3942 return FINISH_HANDLED;
3943 } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
Adam Lesinskic0f6eed2013-10-28 16:03:19 -07003944 // The IME could not handle it, so skip along to the next InputStage
3945 return FORWARD;
Jeff Brownf9e989d2013-04-04 23:04:03 -07003946 } else {
3947 return DEFER; // callback will be invoked later
3948 }
3949 }
3950 }
3951 return FORWARD;
3952 }
3953
3954 @Override
3955 public void onFinishedInputEvent(Object token, boolean handled) {
3956 QueuedInputEvent q = (QueuedInputEvent)token;
3957 if (handled) {
3958 finish(q, true);
3959 return;
3960 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003961 forward(q);
3962 }
3963 }
3964
3965 /**
3966 * Performs early processing of post-ime input events.
3967 */
3968 final class EarlyPostImeInputStage extends InputStage {
3969 public EarlyPostImeInputStage(InputStage next) {
3970 super(next);
3971 }
3972
3973 @Override
3974 protected int onProcess(QueuedInputEvent q) {
3975 if (q.mEvent instanceof KeyEvent) {
3976 return processKeyEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08003977 } else {
Jeff Brown481c1572012-03-09 14:41:15 -08003978 final int source = q.mEvent.getSource();
3979 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07003980 return processPointerEvent(q);
Jeff Brown481c1572012-03-09 14:41:15 -08003981 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08003982 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07003983 return FORWARD;
3984 }
3985
3986 private int processKeyEvent(QueuedInputEvent q) {
3987 final KeyEvent event = (KeyEvent)q.mEvent;
3988
3989 // If the key's purpose is to exit touch mode then we consume it
3990 // and consider it handled.
3991 if (checkForLeavingTouchModeAndConsume(event)) {
3992 return FINISH_HANDLED;
3993 }
3994
3995 // Make sure the fallback event policy sees all keys that will be
3996 // delivered to the view hierarchy.
3997 mFallbackEventHandler.preDispatchKeyEvent(event);
3998 return FORWARD;
3999 }
4000
4001 private int processPointerEvent(QueuedInputEvent q) {
4002 final MotionEvent event = (MotionEvent)q.mEvent;
4003
4004 // Translate the pointer event for compatibility, if needed.
4005 if (mTranslator != null) {
4006 mTranslator.translateEventInScreenToAppWindow(event);
4007 }
4008
4009 // Enter touch mode on down or scroll.
4010 final int action = event.getAction();
4011 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
4012 ensureTouchMode(true);
4013 }
4014
4015 // Offset the scroll position.
4016 if (mCurScrollY != 0) {
4017 event.offsetLocation(0, mCurScrollY);
4018 }
4019
4020 // Remember the touch position for possible drag-initiation.
4021 if (event.isTouchEvent()) {
4022 mLastTouchPoint.x = event.getRawX();
4023 mLastTouchPoint.y = event.getRawY();
4024 }
4025 return FORWARD;
Jeff Brown4952dfd2011-11-30 19:23:22 -08004026 }
4027 }
4028
Jeff Brownf9e989d2013-04-04 23:04:03 -07004029 /**
4030 * Delivers post-ime input events to a native activity.
4031 */
Michael Wrighta44dd262013-04-10 21:12:00 -07004032 final class NativePostImeInputStage extends AsyncInputStage
4033 implements InputQueue.FinishedInputEventCallback {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004034 public NativePostImeInputStage(InputStage next, String traceCounter) {
4035 super(next, traceCounter);
4036 }
4037
4038 @Override
4039 protected int onProcess(QueuedInputEvent q) {
Michael Wrighta44dd262013-04-10 21:12:00 -07004040 if (mInputQueue != null) {
4041 mInputQueue.sendInputEvent(q.mEvent, q, false, this);
4042 return DEFER;
4043 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004044 return FORWARD;
4045 }
Michael Wrighta44dd262013-04-10 21:12:00 -07004046
4047 @Override
4048 public void onFinishedInputEvent(Object token, boolean handled) {
4049 QueuedInputEvent q = (QueuedInputEvent)token;
4050 if (handled) {
4051 finish(q, true);
4052 return;
4053 }
4054 forward(q);
4055 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004056 }
4057
4058 /**
4059 * Delivers post-ime input events to the view hierarchy.
4060 */
4061 final class ViewPostImeInputStage extends InputStage {
4062 public ViewPostImeInputStage(InputStage next) {
4063 super(next);
4064 }
4065
4066 @Override
4067 protected int onProcess(QueuedInputEvent q) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08004068 if (q.mEvent instanceof KeyEvent) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004069 return processKeyEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08004070 } else {
4071 final int source = q.mEvent.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004072 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
4073 return processPointerEvent(q);
4074 } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
4075 return processTrackballEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08004076 } else {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004077 return processGenericMotionEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08004078 }
4079 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08004080 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08004081
Michael Wright9d744c72014-02-18 21:27:42 -08004082 @Override
4083 protected void onDeliverToNext(QueuedInputEvent q) {
4084 if (mUnbufferedInputDispatch
4085 && q.mEvent instanceof MotionEvent
4086 && ((MotionEvent)q.mEvent).isTouchEvent()
4087 && isTerminalInputEvent(q.mEvent)) {
4088 mUnbufferedInputDispatch = false;
4089 scheduleConsumeBatchedInput();
4090 }
4091 super.onDeliverToNext(q);
4092 }
4093
Jeff Brownf9e989d2013-04-04 23:04:03 -07004094 private int processKeyEvent(QueuedInputEvent q) {
4095 final KeyEvent event = (KeyEvent)q.mEvent;
4096
4097 // Deliver the key to the view hierarchy.
4098 if (mView.dispatchKeyEvent(event)) {
4099 return FINISH_HANDLED;
Jeff Brown21bc5c92011-02-28 18:27:14 -08004100 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004101
Michael Wright17d28ca2013-10-31 17:47:45 -07004102 if (shouldDropInputEvent(q)) {
4103 return FINISH_NOT_HANDLED;
4104 }
4105
Jeff Brownf9e989d2013-04-04 23:04:03 -07004106 // If the Control modifier is held, try to interpret the key as a shortcut.
4107 if (event.getAction() == KeyEvent.ACTION_DOWN
4108 && event.isCtrlPressed()
4109 && event.getRepeatCount() == 0
4110 && !KeyEvent.isModifierKey(event.getKeyCode())) {
4111 if (mView.dispatchKeyShortcutEvent(event)) {
4112 return FINISH_HANDLED;
4113 }
Michael Wright17d28ca2013-10-31 17:47:45 -07004114 if (shouldDropInputEvent(q)) {
4115 return FINISH_NOT_HANDLED;
4116 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004117 }
4118
4119 // Apply the fallback event policy.
4120 if (mFallbackEventHandler.dispatchKeyEvent(event)) {
4121 return FINISH_HANDLED;
4122 }
Michael Wright17d28ca2013-10-31 17:47:45 -07004123 if (shouldDropInputEvent(q)) {
4124 return FINISH_NOT_HANDLED;
4125 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004126
4127 // Handle automatic focus changes.
4128 if (event.getAction() == KeyEvent.ACTION_DOWN) {
4129 int direction = 0;
4130 switch (event.getKeyCode()) {
4131 case KeyEvent.KEYCODE_DPAD_LEFT:
4132 if (event.hasNoModifiers()) {
4133 direction = View.FOCUS_LEFT;
4134 }
4135 break;
4136 case KeyEvent.KEYCODE_DPAD_RIGHT:
4137 if (event.hasNoModifiers()) {
4138 direction = View.FOCUS_RIGHT;
4139 }
4140 break;
4141 case KeyEvent.KEYCODE_DPAD_UP:
4142 if (event.hasNoModifiers()) {
4143 direction = View.FOCUS_UP;
4144 }
4145 break;
4146 case KeyEvent.KEYCODE_DPAD_DOWN:
4147 if (event.hasNoModifiers()) {
4148 direction = View.FOCUS_DOWN;
4149 }
4150 break;
4151 case KeyEvent.KEYCODE_TAB:
4152 if (event.hasNoModifiers()) {
4153 direction = View.FOCUS_FORWARD;
4154 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
4155 direction = View.FOCUS_BACKWARD;
4156 }
4157 break;
4158 }
4159 if (direction != 0) {
4160 View focused = mView.findFocus();
4161 if (focused != null) {
4162 View v = focused.focusSearch(direction);
4163 if (v != null && v != focused) {
4164 // do the math the get the interesting rect
4165 // of previous focused into the coord system of
4166 // newly focused view
4167 focused.getFocusedRect(mTempRect);
4168 if (mView instanceof ViewGroup) {
4169 ((ViewGroup) mView).offsetDescendantRectToMyCoords(
4170 focused, mTempRect);
4171 ((ViewGroup) mView).offsetRectIntoDescendantCoords(
4172 v, mTempRect);
4173 }
4174 if (v.requestFocus(direction, mTempRect)) {
4175 playSoundEffect(SoundEffectConstants
4176 .getContantForFocusDirection(direction));
4177 return FINISH_HANDLED;
4178 }
4179 }
4180
4181 // Give the focused view a last chance to handle the dpad key.
4182 if (mView.dispatchUnhandledMove(focused, direction)) {
4183 return FINISH_HANDLED;
4184 }
4185 } else {
4186 // find the best view to give focus to in this non-touch-mode with no-focus
4187 View v = focusSearch(null, direction);
4188 if (v != null && v.requestFocus(direction)) {
4189 return FINISH_HANDLED;
4190 }
4191 }
4192 }
4193 }
4194 return FORWARD;
Jeff Brown21bc5c92011-02-28 18:27:14 -08004195 }
4196
Jeff Brownf9e989d2013-04-04 23:04:03 -07004197 private int processPointerEvent(QueuedInputEvent q) {
4198 final MotionEvent event = (MotionEvent)q.mEvent;
4199
Jun Mukai1db53972015-09-11 18:08:31 -07004200 if (event.getPointerCount() == 1
4201 && event.isFromSource(InputDevice.SOURCE_MOUSE)) {
4202 if (event.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER
4203 || event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
4204 // Other apps or the window manager may change the icon shape outside of
4205 // this app, therefore the icon shape has to be reset on enter/exit event.
4206 mPointerIconShape = PointerIcon.STYLE_NOT_SPECIFIED;
4207 }
4208
4209 final float x = event.getX();
4210 final float y = event.getY();
Jun Mukai76c4a122015-10-19 15:51:28 -07004211 if (event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT
4212 && x >= 0 && x < mView.getWidth() && y >= 0 && y < mView.getHeight()) {
Jun Mukai1db53972015-09-11 18:08:31 -07004213 int pointerShape = mView.getPointerShape(event, x, y);
4214 if (pointerShape == PointerIcon.STYLE_NOT_SPECIFIED) {
4215 pointerShape = PointerIcon.STYLE_DEFAULT;
4216 }
4217
4218 if (mPointerIconShape != pointerShape) {
4219 mPointerIconShape = pointerShape;
Keisuke Kuroyanagi9a4450b2015-10-27 17:29:53 +09004220 final InputDevice inputDevice = event.getDevice();
4221 if (inputDevice != null) {
4222 inputDevice.setPointerShape(pointerShape);
4223 }
Jun Mukai1db53972015-09-11 18:08:31 -07004224 }
Jun Mukai41aab002015-10-01 23:18:47 -07004225 } else if (event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) {
4226 mPointerIconShape = PointerIcon.STYLE_NOT_SPECIFIED;
Jun Mukai1db53972015-09-11 18:08:31 -07004227 }
4228 }
4229
Michael Wright9d744c72014-02-18 21:27:42 -08004230 mAttachInfo.mUnbufferedDispatchRequested = false;
4231 boolean handled = mView.dispatchPointerEvent(event);
4232 if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
4233 mUnbufferedInputDispatch = true;
4234 if (mConsumeBatchedInputScheduled) {
4235 scheduleConsumeBatchedInputImmediately();
4236 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004237 }
Michael Wright9d744c72014-02-18 21:27:42 -08004238 return handled ? FINISH_HANDLED : FORWARD;
Jeff Brown3915bb82010-11-05 15:02:16 -07004239 }
4240
Jeff Brownf9e989d2013-04-04 23:04:03 -07004241 private int processTrackballEvent(QueuedInputEvent q) {
4242 final MotionEvent event = (MotionEvent)q.mEvent;
4243
4244 if (mView.dispatchTrackballEvent(event)) {
4245 return FINISH_HANDLED;
4246 }
4247 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004248 }
4249
Jeff Brownf9e989d2013-04-04 23:04:03 -07004250 private int processGenericMotionEvent(QueuedInputEvent q) {
4251 final MotionEvent event = (MotionEvent)q.mEvent;
Jeff Brown00fa7bd2010-07-02 15:37:36 -07004252
Jeff Brownf9e989d2013-04-04 23:04:03 -07004253 // Deliver the event to the view.
4254 if (mView.dispatchGenericMotionEvent(event)) {
4255 return FINISH_HANDLED;
4256 }
4257 return FORWARD;
Jeff Brown3915bb82010-11-05 15:02:16 -07004258 }
Jeff Brown00fa7bd2010-07-02 15:37:36 -07004259 }
4260
Jeff Brownf9e989d2013-04-04 23:04:03 -07004261 /**
Jeff Brown678a1252013-04-09 17:46:25 -07004262 * Performs synthesis of new input events from unhandled input events.
Jeff Brownf9e989d2013-04-04 23:04:03 -07004263 */
4264 final class SyntheticInputStage extends InputStage {
Jeff Brown678a1252013-04-09 17:46:25 -07004265 private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler();
4266 private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
4267 private final SyntheticTouchNavigationHandler mTouchNavigation =
4268 new SyntheticTouchNavigationHandler();
Michael Wright899d7052014-04-23 17:23:39 -07004269 private final SyntheticKeyboardHandler mKeyboard = new SyntheticKeyboardHandler();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004270
4271 public SyntheticInputStage() {
4272 super(null);
Jeff Brown21bc5c92011-02-28 18:27:14 -08004273 }
4274
Jeff Brownf9e989d2013-04-04 23:04:03 -07004275 @Override
4276 protected int onProcess(QueuedInputEvent q) {
4277 q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED;
4278 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07004279 final MotionEvent event = (MotionEvent)q.mEvent;
4280 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004281 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004282 mTrackball.process(event);
4283 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004284 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004285 mJoystick.process(event);
4286 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004287 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
4288 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07004289 mTouchNavigation.process(event);
4290 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004291 }
Michael Wright899d7052014-04-23 17:23:39 -07004292 } else if ((q.mFlags & QueuedInputEvent.FLAG_UNHANDLED) != 0) {
4293 mKeyboard.process((KeyEvent)q.mEvent);
4294 return FINISH_HANDLED;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004295 }
Michael Wright899d7052014-04-23 17:23:39 -07004296
Jeff Brownf9e989d2013-04-04 23:04:03 -07004297 return FORWARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004298 }
4299
Jeff Brownf9e989d2013-04-04 23:04:03 -07004300 @Override
4301 protected void onDeliverToNext(QueuedInputEvent q) {
4302 if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) {
4303 // Cancel related synthetic events if any prior stage has handled the event.
4304 if (q.mEvent instanceof MotionEvent) {
Jeff Brown678a1252013-04-09 17:46:25 -07004305 final MotionEvent event = (MotionEvent)q.mEvent;
4306 final int source = event.getSource();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004307 if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004308 mTrackball.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004309 } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004310 mJoystick.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004311 } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
4312 == InputDevice.SOURCE_TOUCH_NAVIGATION) {
Jeff Brown678a1252013-04-09 17:46:25 -07004313 mTouchNavigation.cancel(event);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004314 }
4315 }
4316 }
4317 super.onDeliverToNext(q);
4318 }
Jeff Brown678a1252013-04-09 17:46:25 -07004319 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004320
Jeff Brown678a1252013-04-09 17:46:25 -07004321 /**
4322 * Creates dpad events from unhandled trackball movements.
4323 */
4324 final class SyntheticTrackballHandler {
4325 private final TrackballAxis mX = new TrackballAxis();
4326 private final TrackballAxis mY = new TrackballAxis();
4327 private long mLastTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004328
Jeff Brown678a1252013-04-09 17:46:25 -07004329 public void process(MotionEvent event) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004330 // Translate the trackball event into DPAD keys and try to deliver those.
Jeff Brownf9e989d2013-04-04 23:04:03 -07004331 long curTime = SystemClock.uptimeMillis();
Jeff Brown678a1252013-04-09 17:46:25 -07004332 if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004333 // It has been too long since the last movement,
4334 // so restart at the beginning.
Jeff Brown678a1252013-04-09 17:46:25 -07004335 mX.reset(0);
4336 mY.reset(0);
4337 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004338 }
4339
4340 final int action = event.getAction();
4341 final int metaState = event.getMetaState();
4342 switch (action) {
4343 case MotionEvent.ACTION_DOWN:
Jeff Brown678a1252013-04-09 17:46:25 -07004344 mX.reset(2);
4345 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004346 enqueueInputEvent(new KeyEvent(curTime, curTime,
4347 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
4348 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4349 InputDevice.SOURCE_KEYBOARD));
4350 break;
4351 case MotionEvent.ACTION_UP:
Jeff Brown678a1252013-04-09 17:46:25 -07004352 mX.reset(2);
4353 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004354 enqueueInputEvent(new KeyEvent(curTime, curTime,
4355 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
4356 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4357 InputDevice.SOURCE_KEYBOARD));
4358 break;
4359 }
4360
Jeff Brown678a1252013-04-09 17:46:25 -07004361 if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + mX.position + " step="
4362 + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07004363 + " move=" + event.getX()
Jeff Brown678a1252013-04-09 17:46:25 -07004364 + " / Y=" + mY.position + " step="
4365 + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration
Jeff Brownf9e989d2013-04-04 23:04:03 -07004366 + " move=" + event.getY());
Jeff Brown678a1252013-04-09 17:46:25 -07004367 final float xOff = mX.collect(event.getX(), event.getEventTime(), "X");
4368 final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y");
Jeff Brownf9e989d2013-04-04 23:04:03 -07004369
4370 // Generate DPAD events based on the trackball movement.
4371 // We pick the axis that has moved the most as the direction of
4372 // the DPAD. When we generate DPAD events for one axis, then the
4373 // other axis is reset -- we don't want to perform DPAD jumps due
4374 // to slight movements in the trackball when making major movements
4375 // along the other axis.
4376 int keycode = 0;
4377 int movement = 0;
4378 float accel = 1;
4379 if (xOff > yOff) {
Jeff Brown678a1252013-04-09 17:46:25 -07004380 movement = mX.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004381 if (movement != 0) {
4382 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
4383 : KeyEvent.KEYCODE_DPAD_LEFT;
Jeff Brown678a1252013-04-09 17:46:25 -07004384 accel = mX.acceleration;
4385 mY.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004386 }
4387 } else if (yOff > 0) {
Jeff Brown678a1252013-04-09 17:46:25 -07004388 movement = mY.generate();
Jeff Brownf9e989d2013-04-04 23:04:03 -07004389 if (movement != 0) {
4390 keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
4391 : KeyEvent.KEYCODE_DPAD_UP;
Jeff Brown678a1252013-04-09 17:46:25 -07004392 accel = mY.acceleration;
4393 mX.reset(2);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004394 }
4395 }
4396
4397 if (keycode != 0) {
4398 if (movement < 0) movement = -movement;
4399 int accelMovement = (int)(movement * accel);
4400 if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
4401 + " accelMovement=" + accelMovement
4402 + " accel=" + accel);
4403 if (accelMovement > movement) {
4404 if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
4405 + keycode);
4406 movement--;
4407 int repeatCount = accelMovement - movement;
4408 enqueueInputEvent(new KeyEvent(curTime, curTime,
4409 KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
4410 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4411 InputDevice.SOURCE_KEYBOARD));
4412 }
4413 while (movement > 0) {
4414 if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
4415 + keycode);
4416 movement--;
4417 curTime = SystemClock.uptimeMillis();
4418 enqueueInputEvent(new KeyEvent(curTime, curTime,
4419 KeyEvent.ACTION_DOWN, keycode, 0, metaState,
4420 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4421 InputDevice.SOURCE_KEYBOARD));
4422 enqueueInputEvent(new KeyEvent(curTime, curTime,
4423 KeyEvent.ACTION_UP, keycode, 0, metaState,
4424 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
4425 InputDevice.SOURCE_KEYBOARD));
4426 }
Jeff Brown678a1252013-04-09 17:46:25 -07004427 mLastTime = curTime;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004428 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07004429 }
4430
Jeff Brown678a1252013-04-09 17:46:25 -07004431 public void cancel(MotionEvent event) {
4432 mLastTime = Integer.MIN_VALUE;
Jeff Brown3915bb82010-11-05 15:02:16 -07004433
Jeff Brownf9e989d2013-04-04 23:04:03 -07004434 // If we reach this, we consumed a trackball event.
4435 // Because we will not translate the trackball event into a key event,
4436 // touch mode will not exit, so we exit touch mode here.
4437 if (mView != null && mAdded) {
4438 ensureTouchMode(false);
Jeff Brown00fa7bd2010-07-02 15:37:36 -07004439 }
4440 }
Jeff Brown678a1252013-04-09 17:46:25 -07004441 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004442
Jeff Brown678a1252013-04-09 17:46:25 -07004443 /**
4444 * Maintains state information for a single trackball axis, generating
4445 * discrete (DPAD) movements based on raw trackball motion.
4446 */
4447 static final class TrackballAxis {
4448 /**
4449 * The maximum amount of acceleration we will apply.
4450 */
4451 static final float MAX_ACCELERATION = 20;
4452
4453 /**
4454 * The maximum amount of time (in milliseconds) between events in order
4455 * for us to consider the user to be doing fast trackball movements,
4456 * and thus apply an acceleration.
4457 */
4458 static final long FAST_MOVE_TIME = 150;
4459
4460 /**
4461 * Scaling factor to the time (in milliseconds) between events to how
4462 * much to multiple/divide the current acceleration. When movement
4463 * is < FAST_MOVE_TIME this multiplies the acceleration; when >
4464 * FAST_MOVE_TIME it divides it.
4465 */
4466 static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
4467
4468 static final float FIRST_MOVEMENT_THRESHOLD = 0.5f;
4469 static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f;
4470 static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f;
4471
4472 float position;
4473 float acceleration = 1;
4474 long lastMoveTime = 0;
4475 int step;
4476 int dir;
4477 int nonAccelMovement;
4478
4479 void reset(int _step) {
4480 position = 0;
4481 acceleration = 1;
4482 lastMoveTime = 0;
4483 step = _step;
4484 dir = 0;
Jeff Brown6f2fba42011-02-19 01:08:02 -08004485 }
4486
Jeff Brown678a1252013-04-09 17:46:25 -07004487 /**
4488 * Add trackball movement into the state. If the direction of movement
4489 * has been reversed, the state is reset before adding the
4490 * movement (so that you don't have to compensate for any previously
4491 * collected movement before see the result of the movement in the
4492 * new direction).
4493 *
4494 * @return Returns the absolute value of the amount of movement
4495 * collected so far.
4496 */
4497 float collect(float off, long time, String axis) {
4498 long normTime;
4499 if (off > 0) {
4500 normTime = (long)(off * FAST_MOVE_TIME);
4501 if (dir < 0) {
4502 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
4503 position = 0;
4504 step = 0;
4505 acceleration = 1;
4506 lastMoveTime = 0;
4507 }
4508 dir = 1;
4509 } else if (off < 0) {
4510 normTime = (long)((-off) * FAST_MOVE_TIME);
4511 if (dir > 0) {
4512 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
4513 position = 0;
4514 step = 0;
4515 acceleration = 1;
4516 lastMoveTime = 0;
4517 }
4518 dir = -1;
4519 } else {
4520 normTime = 0;
4521 }
4522
4523 // The number of milliseconds between each movement that is
4524 // considered "normal" and will not result in any acceleration
4525 // or deceleration, scaled by the offset we have here.
4526 if (normTime > 0) {
4527 long delta = time - lastMoveTime;
4528 lastMoveTime = time;
4529 float acc = acceleration;
4530 if (delta < normTime) {
4531 // The user is scrolling rapidly, so increase acceleration.
4532 float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
4533 if (scale > 1) acc *= scale;
4534 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
4535 + off + " normTime=" + normTime + " delta=" + delta
4536 + " scale=" + scale + " acc=" + acc);
4537 acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
4538 } else {
4539 // The user is scrolling slowly, so decrease acceleration.
4540 float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
4541 if (scale > 1) acc /= scale;
4542 if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
4543 + off + " normTime=" + normTime + " delta=" + delta
4544 + " scale=" + scale + " acc=" + acc);
4545 acceleration = acc > 1 ? acc : 1;
4546 }
4547 }
4548 position += off;
4549 return Math.abs(position);
Jeff Brown6f2fba42011-02-19 01:08:02 -08004550 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004551
Jeff Brown678a1252013-04-09 17:46:25 -07004552 /**
4553 * Generate the number of discrete movement events appropriate for
4554 * the currently collected trackball movement.
4555 *
4556 * @return Returns the number of discrete movements, either positive
4557 * or negative, or 0 if there is not enough trackball movement yet
4558 * for a discrete movement.
4559 */
4560 int generate() {
4561 int movement = 0;
4562 nonAccelMovement = 0;
4563 do {
4564 final int dir = position >= 0 ? 1 : -1;
4565 switch (step) {
4566 // If we are going to execute the first step, then we want
4567 // to do this as soon as possible instead of waiting for
4568 // a full movement, in order to make things look responsive.
4569 case 0:
4570 if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) {
4571 return movement;
4572 }
4573 movement += dir;
4574 nonAccelMovement += dir;
4575 step = 1;
4576 break;
4577 // If we have generated the first movement, then we need
4578 // to wait for the second complete trackball motion before
4579 // generating the second discrete movement.
4580 case 1:
4581 if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) {
4582 return movement;
4583 }
4584 movement += dir;
4585 nonAccelMovement += dir;
4586 position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir;
4587 step = 2;
4588 break;
4589 // After the first two, we generate discrete movements
4590 // consistently with the trackball, applying an acceleration
4591 // if the trackball is moving quickly. This is a simple
4592 // acceleration on top of what we already compute based
4593 // on how quickly the wheel is being turned, to apply
4594 // a longer increasing acceleration to continuous movement
4595 // in one direction.
4596 default:
4597 if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) {
4598 return movement;
4599 }
4600 movement += dir;
4601 position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD;
4602 float acc = acceleration;
4603 acc *= 1.1f;
4604 acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
4605 break;
4606 }
4607 } while (true);
4608 }
4609 }
4610
4611 /**
4612 * Creates dpad events from unhandled joystick movements.
4613 */
4614 final class SyntheticJoystickHandler extends Handler {
Michael Wright9adca062014-03-19 11:51:26 -07004615 private final static String TAG = "SyntheticJoystickHandler";
Jeff Brown678a1252013-04-09 17:46:25 -07004616 private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
4617 private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
4618
4619 private int mLastXDirection;
4620 private int mLastYDirection;
4621 private int mLastXKeyCode;
4622 private int mLastYKeyCode;
4623
4624 public SyntheticJoystickHandler() {
4625 super(true);
4626 }
4627
4628 @Override
4629 public void handleMessage(Message msg) {
4630 switch (msg.what) {
4631 case MSG_ENQUEUE_X_AXIS_KEY_REPEAT:
4632 case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: {
4633 KeyEvent oldEvent = (KeyEvent)msg.obj;
4634 KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent,
4635 SystemClock.uptimeMillis(),
4636 oldEvent.getRepeatCount() + 1);
4637 if (mAttachInfo.mHasWindowFocus) {
4638 enqueueInputEvent(e);
4639 Message m = obtainMessage(msg.what, e);
4640 m.setAsynchronous(true);
4641 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay());
4642 }
4643 } break;
4644 }
4645 }
4646
4647 public void process(MotionEvent event) {
Michael Wright9adca062014-03-19 11:51:26 -07004648 switch(event.getActionMasked()) {
4649 case MotionEvent.ACTION_CANCEL:
4650 cancel(event);
4651 break;
4652 case MotionEvent.ACTION_MOVE:
4653 update(event, true);
4654 break;
4655 default:
4656 Log.w(TAG, "Unexpected action: " + event.getActionMasked());
4657 }
Jeff Brown678a1252013-04-09 17:46:25 -07004658 }
4659
Michael Wright9adca062014-03-19 11:51:26 -07004660 private void cancel(MotionEvent event) {
4661 removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
4662 removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
Jeff Brown678a1252013-04-09 17:46:25 -07004663 update(event, false);
4664 }
4665
4666 private void update(MotionEvent event, boolean synthesizeNewKeys) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07004667 final long time = event.getEventTime();
4668 final int metaState = event.getMetaState();
4669 final int deviceId = event.getDeviceId();
4670 final int source = event.getSource();
4671
4672 int xDirection = joystickAxisValueToDirection(
4673 event.getAxisValue(MotionEvent.AXIS_HAT_X));
4674 if (xDirection == 0) {
4675 xDirection = joystickAxisValueToDirection(event.getX());
Jeff Browncb1404e2011-01-15 18:14:15 -08004676 }
4677
Jeff Brownf9e989d2013-04-04 23:04:03 -07004678 int yDirection = joystickAxisValueToDirection(
4679 event.getAxisValue(MotionEvent.AXIS_HAT_Y));
4680 if (yDirection == 0) {
4681 yDirection = joystickAxisValueToDirection(event.getY());
4682 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004683
Jeff Brown678a1252013-04-09 17:46:25 -07004684 if (xDirection != mLastXDirection) {
4685 if (mLastXKeyCode != 0) {
4686 removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004687 enqueueInputEvent(new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004688 KeyEvent.ACTION_UP, mLastXKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004689 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Brown678a1252013-04-09 17:46:25 -07004690 mLastXKeyCode = 0;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004691 }
4692
Jeff Brown678a1252013-04-09 17:46:25 -07004693 mLastXDirection = xDirection;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004694
4695 if (xDirection != 0 && synthesizeNewKeys) {
Jeff Brown678a1252013-04-09 17:46:25 -07004696 mLastXKeyCode = xDirection > 0
Jeff Brownf9e989d2013-04-04 23:04:03 -07004697 ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
4698 final KeyEvent e = new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004699 KeyEvent.ACTION_DOWN, mLastXKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004700 deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
4701 enqueueInputEvent(e);
Jeff Brown678a1252013-04-09 17:46:25 -07004702 Message m = obtainMessage(MSG_ENQUEUE_X_AXIS_KEY_REPEAT, e);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004703 m.setAsynchronous(true);
Michael Wrightb9618522013-04-10 15:20:56 -07004704 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
Jeff Brownf9e989d2013-04-04 23:04:03 -07004705 }
4706 }
4707
Jeff Brown678a1252013-04-09 17:46:25 -07004708 if (yDirection != mLastYDirection) {
4709 if (mLastYKeyCode != 0) {
4710 removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004711 enqueueInputEvent(new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004712 KeyEvent.ACTION_UP, mLastYKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004713 deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
Jeff Brown678a1252013-04-09 17:46:25 -07004714 mLastYKeyCode = 0;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004715 }
4716
Jeff Brown678a1252013-04-09 17:46:25 -07004717 mLastYDirection = yDirection;
Jeff Brownf9e989d2013-04-04 23:04:03 -07004718
4719 if (yDirection != 0 && synthesizeNewKeys) {
Jeff Brown678a1252013-04-09 17:46:25 -07004720 mLastYKeyCode = yDirection > 0
Jeff Brownf9e989d2013-04-04 23:04:03 -07004721 ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
4722 final KeyEvent e = new KeyEvent(time, time,
Jeff Brown678a1252013-04-09 17:46:25 -07004723 KeyEvent.ACTION_DOWN, mLastYKeyCode, 0, metaState,
Jeff Brownf9e989d2013-04-04 23:04:03 -07004724 deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
4725 enqueueInputEvent(e);
Jeff Brown678a1252013-04-09 17:46:25 -07004726 Message m = obtainMessage(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT, e);
Jeff Brownf9e989d2013-04-04 23:04:03 -07004727 m.setAsynchronous(true);
Jeff Brown678a1252013-04-09 17:46:25 -07004728 sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
Jeff Brownf9e989d2013-04-04 23:04:03 -07004729 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004730 }
4731 }
4732
Jeff Brownf9e989d2013-04-04 23:04:03 -07004733 private int joystickAxisValueToDirection(float value) {
4734 if (value >= 0.5f) {
4735 return 1;
4736 } else if (value <= -0.5f) {
4737 return -1;
4738 } else {
4739 return 0;
Jeff Browncb1404e2011-01-15 18:14:15 -08004740 }
4741 }
Jeff Brown678a1252013-04-09 17:46:25 -07004742 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004743
Jeff Brown678a1252013-04-09 17:46:25 -07004744 /**
4745 * Creates dpad events from unhandled touch navigation movements.
4746 */
4747 final class SyntheticTouchNavigationHandler extends Handler {
Jeff Brown4dac9012013-04-10 01:03:19 -07004748 private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler";
4749 private static final boolean LOCAL_DEBUG = false;
Jeff Brown678a1252013-04-09 17:46:25 -07004750
Jeff Brown4dac9012013-04-10 01:03:19 -07004751 // Assumed nominal width and height in millimeters of a touch navigation pad,
4752 // if no resolution information is available from the input system.
4753 private static final float DEFAULT_WIDTH_MILLIMETERS = 48;
4754 private static final float DEFAULT_HEIGHT_MILLIMETERS = 48;
Jeff Brown678a1252013-04-09 17:46:25 -07004755
Jeff Brown4dac9012013-04-10 01:03:19 -07004756 /* TODO: These constants should eventually be moved to ViewConfiguration. */
Jeff Brown678a1252013-04-09 17:46:25 -07004757
Jeff Brown4dac9012013-04-10 01:03:19 -07004758 // The nominal distance traveled to move by one unit.
4759 private static final int TICK_DISTANCE_MILLIMETERS = 12;
4760
4761 // Minimum and maximum fling velocity in ticks per second.
4762 // The minimum velocity should be set such that we perform enough ticks per
4763 // second that the fling appears to be fluid. For example, if we set the minimum
4764 // to 2 ticks per second, then there may be up to half a second delay between the next
4765 // to last and last ticks which is noticeably discrete and jerky. This value should
4766 // probably not be set to anything less than about 4.
4767 // If fling accuracy is a problem then consider tuning the tick distance instead.
4768 private static final float MIN_FLING_VELOCITY_TICKS_PER_SECOND = 6f;
4769 private static final float MAX_FLING_VELOCITY_TICKS_PER_SECOND = 20f;
4770
4771 // Fling velocity decay factor applied after each new key is emitted.
4772 // This parameter controls the deceleration and overall duration of the fling.
4773 // The fling stops automatically when its velocity drops below the minimum
4774 // fling velocity defined above.
4775 private static final float FLING_TICK_DECAY = 0.8f;
4776
4777 /* The input device that we are tracking. */
4778
4779 private int mCurrentDeviceId = -1;
4780 private int mCurrentSource;
4781 private boolean mCurrentDeviceSupported;
4782
4783 /* Configuration for the current input device. */
4784
Jeff Brown4dac9012013-04-10 01:03:19 -07004785 // The scaled tick distance. A movement of this amount should generally translate
4786 // into a single dpad event in a given direction.
4787 private float mConfigTickDistance;
4788
4789 // The minimum and maximum scaled fling velocity.
4790 private float mConfigMinFlingVelocity;
4791 private float mConfigMaxFlingVelocity;
4792
4793 /* Tracking state. */
4794
4795 // The velocity tracker for detecting flings.
4796 private VelocityTracker mVelocityTracker;
4797
4798 // The active pointer id, or -1 if none.
4799 private int mActivePointerId = -1;
4800
John Reck79d81e62013-11-05 13:26:57 -08004801 // Location where tracking started.
Jeff Brown4dac9012013-04-10 01:03:19 -07004802 private float mStartX;
4803 private float mStartY;
4804
4805 // Most recently observed position.
4806 private float mLastX;
4807 private float mLastY;
4808
4809 // Accumulated movement delta since the last direction key was sent.
Jeff Brown678a1252013-04-09 17:46:25 -07004810 private float mAccumulatedX;
4811 private float mAccumulatedY;
4812
Jeff Brown4dac9012013-04-10 01:03:19 -07004813 // Set to true if any movement was delivered to the app.
4814 // Implies that tap slop was exceeded.
4815 private boolean mConsumedMovement;
Jeff Brown678a1252013-04-09 17:46:25 -07004816
Jeff Brown4dac9012013-04-10 01:03:19 -07004817 // The most recently sent key down event.
4818 // The keycode remains set until the direction changes or a fling ends
4819 // so that repeated key events may be generated as required.
4820 private long mPendingKeyDownTime;
4821 private int mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
4822 private int mPendingKeyRepeatCount;
4823 private int mPendingKeyMetaState;
Jeff Brown678a1252013-04-09 17:46:25 -07004824
Jeff Brown4dac9012013-04-10 01:03:19 -07004825 // The current fling velocity while a fling is in progress.
4826 private boolean mFlinging;
4827 private float mFlingVelocity;
Jeff Brown678a1252013-04-09 17:46:25 -07004828
4829 public SyntheticTouchNavigationHandler() {
4830 super(true);
Jeff Brown678a1252013-04-09 17:46:25 -07004831 }
4832
4833 public void process(MotionEvent event) {
Jeff Brown4dac9012013-04-10 01:03:19 -07004834 // Update the current device information.
4835 final long time = event.getEventTime();
4836 final int deviceId = event.getDeviceId();
4837 final int source = event.getSource();
4838 if (mCurrentDeviceId != deviceId || mCurrentSource != source) {
4839 finishKeys(time);
4840 finishTracking(time);
4841 mCurrentDeviceId = deviceId;
4842 mCurrentSource = source;
4843 mCurrentDeviceSupported = false;
4844 InputDevice device = event.getDevice();
4845 if (device != null) {
4846 // In order to support an input device, we must know certain
4847 // characteristics about it, such as its size and resolution.
4848 InputDevice.MotionRange xRange = device.getMotionRange(MotionEvent.AXIS_X);
4849 InputDevice.MotionRange yRange = device.getMotionRange(MotionEvent.AXIS_Y);
4850 if (xRange != null && yRange != null) {
4851 mCurrentDeviceSupported = true;
Jeff Brown678a1252013-04-09 17:46:25 -07004852
Jeff Brown4dac9012013-04-10 01:03:19 -07004853 // Infer the resolution if it not actually known.
4854 float xRes = xRange.getResolution();
4855 if (xRes <= 0) {
4856 xRes = xRange.getRange() / DEFAULT_WIDTH_MILLIMETERS;
4857 }
4858 float yRes = yRange.getResolution();
4859 if (yRes <= 0) {
4860 yRes = yRange.getRange() / DEFAULT_HEIGHT_MILLIMETERS;
4861 }
4862 float nominalRes = (xRes + yRes) * 0.5f;
Jeff Brown678a1252013-04-09 17:46:25 -07004863
Jeff Brown4dac9012013-04-10 01:03:19 -07004864 // Precompute all of the configuration thresholds we will need.
Jeff Brown4dac9012013-04-10 01:03:19 -07004865 mConfigTickDistance = TICK_DISTANCE_MILLIMETERS * nominalRes;
4866 mConfigMinFlingVelocity =
4867 MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
4868 mConfigMaxFlingVelocity =
4869 MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
4870
4871 if (LOCAL_DEBUG) {
4872 Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId
4873 + " (" + Integer.toHexString(mCurrentSource) + "): "
Jeff Brown4dac9012013-04-10 01:03:19 -07004874 + ", mConfigTickDistance=" + mConfigTickDistance
4875 + ", mConfigMinFlingVelocity=" + mConfigMinFlingVelocity
4876 + ", mConfigMaxFlingVelocity=" + mConfigMaxFlingVelocity);
4877 }
4878 }
4879 }
Jeff Brown678a1252013-04-09 17:46:25 -07004880 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004881 if (!mCurrentDeviceSupported) {
Jeff Brown678a1252013-04-09 17:46:25 -07004882 return;
4883 }
4884
Jeff Brown4dac9012013-04-10 01:03:19 -07004885 // Handle the event.
4886 final int action = event.getActionMasked();
4887 switch (action) {
Jeff Brown678a1252013-04-09 17:46:25 -07004888 case MotionEvent.ACTION_DOWN: {
Jeff Brown4dac9012013-04-10 01:03:19 -07004889 boolean caughtFling = mFlinging;
4890 finishKeys(time);
4891 finishTracking(time);
4892 mActivePointerId = event.getPointerId(0);
4893 mVelocityTracker = VelocityTracker.obtain();
4894 mVelocityTracker.addMovement(event);
Jeff Brown4dac9012013-04-10 01:03:19 -07004895 mStartX = event.getX();
4896 mStartY = event.getY();
4897 mLastX = mStartX;
4898 mLastY = mStartY;
Jeff Brown678a1252013-04-09 17:46:25 -07004899 mAccumulatedX = 0;
4900 mAccumulatedY = 0;
Jeff Brown4dac9012013-04-10 01:03:19 -07004901
4902 // If we caught a fling, then pretend that the tap slop has already
4903 // been exceeded to suppress taps whose only purpose is to stop the fling.
4904 mConsumedMovement = caughtFling;
Jeff Brown678a1252013-04-09 17:46:25 -07004905 break;
4906 }
4907
Jeff Brown4dac9012013-04-10 01:03:19 -07004908 case MotionEvent.ACTION_MOVE:
Jeff Brown678a1252013-04-09 17:46:25 -07004909 case MotionEvent.ACTION_UP: {
Jeff Brown4dac9012013-04-10 01:03:19 -07004910 if (mActivePointerId < 0) {
4911 break;
4912 }
4913 final int index = event.findPointerIndex(mActivePointerId);
4914 if (index < 0) {
4915 finishKeys(time);
4916 finishTracking(time);
4917 break;
4918 }
Jeff Brown678a1252013-04-09 17:46:25 -07004919
Jeff Brown4dac9012013-04-10 01:03:19 -07004920 mVelocityTracker.addMovement(event);
4921 final float x = event.getX(index);
4922 final float y = event.getY(index);
4923 mAccumulatedX += x - mLastX;
4924 mAccumulatedY += y - mLastY;
4925 mLastX = x;
4926 mLastY = y;
4927
4928 // Consume any accumulated movement so far.
4929 final int metaState = event.getMetaState();
4930 consumeAccumulatedMovement(time, metaState);
4931
4932 // Detect taps and flings.
4933 if (action == MotionEvent.ACTION_UP) {
Michael Wright88d7f792013-08-27 15:45:42 -07004934 if (mConsumedMovement && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
Jeff Brown4dac9012013-04-10 01:03:19 -07004935 // It might be a fling.
4936 mVelocityTracker.computeCurrentVelocity(1000, mConfigMaxFlingVelocity);
4937 final float vx = mVelocityTracker.getXVelocity(mActivePointerId);
4938 final float vy = mVelocityTracker.getYVelocity(mActivePointerId);
4939 if (!startFling(time, vx, vy)) {
4940 finishKeys(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004941 }
4942 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004943 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004944 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004945 break;
4946 }
4947
4948 case MotionEvent.ACTION_CANCEL: {
4949 finishKeys(time);
4950 finishTracking(time);
Jeff Brown678a1252013-04-09 17:46:25 -07004951 break;
4952 }
4953 }
Jeff Browncb1404e2011-01-15 18:14:15 -08004954 }
Jeff Brown4dac9012013-04-10 01:03:19 -07004955
4956 public void cancel(MotionEvent event) {
4957 if (mCurrentDeviceId == event.getDeviceId()
4958 && mCurrentSource == event.getSource()) {
4959 final long time = event.getEventTime();
4960 finishKeys(time);
4961 finishTracking(time);
4962 }
4963 }
4964
4965 private void finishKeys(long time) {
4966 cancelFling();
4967 sendKeyUp(time);
4968 }
4969
4970 private void finishTracking(long time) {
4971 if (mActivePointerId >= 0) {
4972 mActivePointerId = -1;
4973 mVelocityTracker.recycle();
4974 mVelocityTracker = null;
4975 }
4976 }
4977
4978 private void consumeAccumulatedMovement(long time, int metaState) {
4979 final float absX = Math.abs(mAccumulatedX);
4980 final float absY = Math.abs(mAccumulatedY);
4981 if (absX >= absY) {
4982 if (absX >= mConfigTickDistance) {
4983 mAccumulatedX = consumeAccumulatedMovement(time, metaState, mAccumulatedX,
4984 KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT);
4985 mAccumulatedY = 0;
4986 mConsumedMovement = true;
4987 }
4988 } else {
4989 if (absY >= mConfigTickDistance) {
4990 mAccumulatedY = consumeAccumulatedMovement(time, metaState, mAccumulatedY,
4991 KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN);
4992 mAccumulatedX = 0;
4993 mConsumedMovement = true;
4994 }
4995 }
4996 }
4997
4998 private float consumeAccumulatedMovement(long time, int metaState,
4999 float accumulator, int negativeKeyCode, int positiveKeyCode) {
5000 while (accumulator <= -mConfigTickDistance) {
5001 sendKeyDownOrRepeat(time, negativeKeyCode, metaState);
5002 accumulator += mConfigTickDistance;
5003 }
5004 while (accumulator >= mConfigTickDistance) {
5005 sendKeyDownOrRepeat(time, positiveKeyCode, metaState);
5006 accumulator -= mConfigTickDistance;
5007 }
5008 return accumulator;
5009 }
5010
5011 private void sendKeyDownOrRepeat(long time, int keyCode, int metaState) {
5012 if (mPendingKeyCode != keyCode) {
5013 sendKeyUp(time);
5014 mPendingKeyDownTime = time;
5015 mPendingKeyCode = keyCode;
5016 mPendingKeyRepeatCount = 0;
5017 } else {
5018 mPendingKeyRepeatCount += 1;
5019 }
5020 mPendingKeyMetaState = metaState;
5021
5022 // Note: Normally we would pass FLAG_LONG_PRESS when the repeat count is 1
5023 // but it doesn't quite make sense when simulating the events in this way.
5024 if (LOCAL_DEBUG) {
5025 Log.d(LOCAL_TAG, "Sending key down: keyCode=" + mPendingKeyCode
5026 + ", repeatCount=" + mPendingKeyRepeatCount
5027 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
5028 }
5029 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
5030 KeyEvent.ACTION_DOWN, mPendingKeyCode, mPendingKeyRepeatCount,
5031 mPendingKeyMetaState, mCurrentDeviceId,
5032 KeyEvent.FLAG_FALLBACK, mCurrentSource));
5033 }
5034
5035 private void sendKeyUp(long time) {
5036 if (mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
5037 if (LOCAL_DEBUG) {
5038 Log.d(LOCAL_TAG, "Sending key up: keyCode=" + mPendingKeyCode
5039 + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
5040 }
5041 enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
5042 KeyEvent.ACTION_UP, mPendingKeyCode, 0, mPendingKeyMetaState,
5043 mCurrentDeviceId, 0, KeyEvent.FLAG_FALLBACK,
5044 mCurrentSource));
5045 mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
5046 }
5047 }
5048
5049 private boolean startFling(long time, float vx, float vy) {
5050 if (LOCAL_DEBUG) {
5051 Log.d(LOCAL_TAG, "Considering fling: vx=" + vx + ", vy=" + vy
5052 + ", min=" + mConfigMinFlingVelocity);
5053 }
5054
5055 // Flings must be oriented in the same direction as the preceding movements.
5056 switch (mPendingKeyCode) {
5057 case KeyEvent.KEYCODE_DPAD_LEFT:
5058 if (-vx >= mConfigMinFlingVelocity
5059 && Math.abs(vy) < mConfigMinFlingVelocity) {
5060 mFlingVelocity = -vx;
5061 break;
5062 }
5063 return false;
5064
5065 case KeyEvent.KEYCODE_DPAD_RIGHT:
5066 if (vx >= mConfigMinFlingVelocity
5067 && Math.abs(vy) < mConfigMinFlingVelocity) {
5068 mFlingVelocity = vx;
5069 break;
5070 }
5071 return false;
5072
5073 case KeyEvent.KEYCODE_DPAD_UP:
5074 if (-vy >= mConfigMinFlingVelocity
5075 && Math.abs(vx) < mConfigMinFlingVelocity) {
5076 mFlingVelocity = -vy;
5077 break;
5078 }
5079 return false;
5080
5081 case KeyEvent.KEYCODE_DPAD_DOWN:
5082 if (vy >= mConfigMinFlingVelocity
5083 && Math.abs(vx) < mConfigMinFlingVelocity) {
5084 mFlingVelocity = vy;
5085 break;
5086 }
5087 return false;
5088 }
5089
5090 // Post the first fling event.
5091 mFlinging = postFling(time);
5092 return mFlinging;
5093 }
5094
5095 private boolean postFling(long time) {
5096 // The idea here is to estimate the time when the pointer would have
5097 // traveled one tick distance unit given the current fling velocity.
5098 // This effect creates continuity of motion.
5099 if (mFlingVelocity >= mConfigMinFlingVelocity) {
5100 long delay = (long)(mConfigTickDistance / mFlingVelocity * 1000);
5101 postAtTime(mFlingRunnable, time + delay);
5102 if (LOCAL_DEBUG) {
5103 Log.d(LOCAL_TAG, "Posted fling: velocity="
5104 + mFlingVelocity + ", delay=" + delay
5105 + ", keyCode=" + mPendingKeyCode);
5106 }
5107 return true;
5108 }
5109 return false;
5110 }
5111
5112 private void cancelFling() {
5113 if (mFlinging) {
5114 removeCallbacks(mFlingRunnable);
5115 mFlinging = false;
5116 }
5117 }
5118
5119 private final Runnable mFlingRunnable = new Runnable() {
5120 @Override
5121 public void run() {
5122 final long time = SystemClock.uptimeMillis();
5123 sendKeyDownOrRepeat(time, mPendingKeyCode, mPendingKeyMetaState);
5124 mFlingVelocity *= FLING_TICK_DECAY;
5125 if (!postFling(time)) {
5126 mFlinging = false;
5127 finishKeys(time);
5128 }
5129 }
5130 };
Jeff Browncb1404e2011-01-15 18:14:15 -08005131 }
5132
Michael Wright899d7052014-04-23 17:23:39 -07005133 final class SyntheticKeyboardHandler {
5134 public void process(KeyEvent event) {
5135 if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
5136 return;
5137 }
5138
5139 final KeyCharacterMap kcm = event.getKeyCharacterMap();
5140 final int keyCode = event.getKeyCode();
5141 final int metaState = event.getMetaState();
5142
5143 // Check for fallback actions specified by the key character map.
5144 KeyCharacterMap.FallbackAction fallbackAction =
5145 kcm.getFallbackAction(keyCode, metaState);
5146 if (fallbackAction != null) {
5147 final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
5148 KeyEvent fallbackEvent = KeyEvent.obtain(
5149 event.getDownTime(), event.getEventTime(),
5150 event.getAction(), fallbackAction.keyCode,
5151 event.getRepeatCount(), fallbackAction.metaState,
5152 event.getDeviceId(), event.getScanCode(),
5153 flags, event.getSource(), null);
5154 fallbackAction.recycle();
5155 enqueueInputEvent(fallbackEvent);
5156 }
5157 }
5158 }
5159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005160 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08005161 * Returns true if the key is used for keyboard navigation.
5162 * @param keyEvent The key event.
5163 * @return True if the key is used for keyboard navigation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005164 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08005165 private static boolean isNavigationKey(KeyEvent keyEvent) {
5166 switch (keyEvent.getKeyCode()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005167 case KeyEvent.KEYCODE_DPAD_LEFT:
5168 case KeyEvent.KEYCODE_DPAD_RIGHT:
5169 case KeyEvent.KEYCODE_DPAD_UP:
5170 case KeyEvent.KEYCODE_DPAD_DOWN:
Jeff Brown4e6319b2010-12-13 10:36:51 -08005171 case KeyEvent.KEYCODE_DPAD_CENTER:
5172 case KeyEvent.KEYCODE_PAGE_UP:
5173 case KeyEvent.KEYCODE_PAGE_DOWN:
5174 case KeyEvent.KEYCODE_MOVE_HOME:
5175 case KeyEvent.KEYCODE_MOVE_END:
5176 case KeyEvent.KEYCODE_TAB:
5177 case KeyEvent.KEYCODE_SPACE:
5178 case KeyEvent.KEYCODE_ENTER:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005179 return true;
5180 }
5181 return false;
5182 }
5183
5184 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08005185 * Returns true if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005186 * @param keyEvent The key event.
Jeff Brown4e6319b2010-12-13 10:36:51 -08005187 * @return True if the key is used for typing.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005188 */
Jeff Brown4e6319b2010-12-13 10:36:51 -08005189 private static boolean isTypingKey(KeyEvent keyEvent) {
5190 return keyEvent.getUnicodeChar() > 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005191 }
5192
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005193 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08005194 * 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 -08005195 * @param event The key event.
5196 * @return Whether this key event should be consumed (meaning the act of
5197 * leaving touch mode alone is considered the event).
5198 */
5199 private boolean checkForLeavingTouchModeAndConsume(KeyEvent event) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08005200 // Only relevant in touch mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005201 if (!mAttachInfo.mInTouchMode) {
5202 return false;
5203 }
5204
Jeff Brown4e6319b2010-12-13 10:36:51 -08005205 // Only consider leaving touch mode on DOWN or MULTIPLE actions, never on UP.
5206 final int action = event.getAction();
5207 if (action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_MULTIPLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005208 return false;
5209 }
5210
Jeff Brown4e6319b2010-12-13 10:36:51 -08005211 // Don't leave touch mode if the IME told us not to.
5212 if ((event.getFlags() & KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
5213 return false;
5214 }
5215
5216 // If the key can be used for keyboard navigation then leave touch mode
5217 // and select a focused view if needed (in ensureTouchMode).
5218 // When a new focused view is selected, we consume the navigation key because
5219 // navigation doesn't make much sense unless a view already has focus so
5220 // the key's purpose is to set focus.
5221 if (isNavigationKey(event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005222 return ensureTouchMode(false);
5223 }
Jeff Brown4e6319b2010-12-13 10:36:51 -08005224
5225 // If the key can be used for typing then leave touch mode
5226 // and select a focused view if needed (in ensureTouchMode).
5227 // Always allow the view to process the typing key.
5228 if (isTypingKey(event)) {
5229 ensureTouchMode(false);
5230 return false;
5231 }
5232
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005233 return false;
5234 }
5235
Christopher Tatea53146c2010-09-07 11:57:52 -07005236 /* drag/drop */
Christopher Tate407b4e92010-11-30 17:14:08 -08005237 void setLocalDragState(Object obj) {
5238 mLocalDragState = obj;
5239 }
5240
Christopher Tatea53146c2010-09-07 11:57:52 -07005241 private void handleDragEvent(DragEvent event) {
5242 // From the root, only drag start/end/location are dispatched. entered/exited
5243 // are determined and dispatched by the viewgroup hierarchy, who then report
5244 // that back here for ultimate reporting back to the framework.
5245 if (mView != null && mAdded) {
5246 final int what = event.mAction;
5247
5248 if (what == DragEvent.ACTION_DRAG_EXITED) {
5249 // A direct EXITED event means that the window manager knows we've just crossed
5250 // a window boundary, so the current drag target within this one must have
5251 // just been exited. Send it the usual notifications and then we're done
5252 // for now.
Chris Tate9d1ab882010-11-02 15:55:39 -07005253 mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07005254 } else {
5255 // Cache the drag description when the operation starts, then fill it in
5256 // on subsequent calls as a convenience
5257 if (what == DragEvent.ACTION_DRAG_STARTED) {
Chris Tate9d1ab882010-11-02 15:55:39 -07005258 mCurrentDragView = null; // Start the current-recipient tracking
Christopher Tatea53146c2010-09-07 11:57:52 -07005259 mDragDescription = event.mClipDescription;
5260 } else {
5261 event.mClipDescription = mDragDescription;
5262 }
5263
5264 // For events with a [screen] location, translate into window coordinates
5265 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
5266 mDragPoint.set(event.mX, event.mY);
5267 if (mTranslator != null) {
5268 mTranslator.translatePointInScreenToAppWindow(mDragPoint);
5269 }
5270
5271 if (mCurScrollY != 0) {
5272 mDragPoint.offset(0, mCurScrollY);
5273 }
5274
5275 event.mX = mDragPoint.x;
5276 event.mY = mDragPoint.y;
5277 }
5278
5279 // Remember who the current drag target is pre-dispatch
5280 final View prevDragView = mCurrentDragView;
5281
5282 // Now dispatch the drag/drop event
Chris Tated4533f12010-10-19 15:15:08 -07005283 boolean result = mView.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07005284
5285 // If we changed apparent drag target, tell the OS about it
5286 if (prevDragView != mCurrentDragView) {
5287 try {
5288 if (prevDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07005289 mWindowSession.dragRecipientExited(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07005290 }
5291 if (mCurrentDragView != null) {
Jeff Brown98365d72012-08-19 20:30:52 -07005292 mWindowSession.dragRecipientEntered(mWindow);
Christopher Tatea53146c2010-09-07 11:57:52 -07005293 }
5294 } catch (RemoteException e) {
5295 Slog.e(TAG, "Unable to note drag target change");
5296 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005297 }
Chris Tated4533f12010-10-19 15:15:08 -07005298
Christopher Tate407b4e92010-11-30 17:14:08 -08005299 // Report the drop result when we're done
Chris Tated4533f12010-10-19 15:15:08 -07005300 if (what == DragEvent.ACTION_DROP) {
Christopher Tate1fc014f2011-01-19 12:56:26 -08005301 mDragDescription = null;
Chris Tated4533f12010-10-19 15:15:08 -07005302 try {
5303 Log.i(TAG, "Reporting drop result: " + result);
Jeff Brown98365d72012-08-19 20:30:52 -07005304 mWindowSession.reportDropResult(mWindow, result);
Chris Tated4533f12010-10-19 15:15:08 -07005305 } catch (RemoteException e) {
5306 Log.e(TAG, "Unable to report drop result");
5307 }
5308 }
Christopher Tate407b4e92010-11-30 17:14:08 -08005309
5310 // When the drag operation ends, release any local state object
5311 // that may have been in use
5312 if (what == DragEvent.ACTION_DRAG_ENDED) {
5313 setLocalDragState(null);
5314 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005315 }
5316 }
5317 event.recycle();
5318 }
5319
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005320 public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
5321 if (mSeq != args.seq) {
5322 // The sequence has changed, so we need to update our value and make
5323 // sure to do a traversal afterward so the window manager is given our
5324 // most recent data.
5325 mSeq = args.seq;
5326 mAttachInfo.mForceReportNewAttributes = true;
Igor Murashkina86ab6402013-08-30 12:58:36 -07005327 scheduleTraversals();
Joe Onorato14782f72011-01-25 19:53:17 -08005328 }
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005329 if (mView == null) return;
5330 if (args.localChanges != 0) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005331 mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005332 }
Chris Craikd36a81f2014-07-17 10:16:51 -07005333
5334 int visibility = args.globalVisibility&View.SYSTEM_UI_CLEARABLE_FLAGS;
5335 if (visibility != mAttachInfo.mGlobalSystemUiVisibility) {
5336 mAttachInfo.mGlobalSystemUiVisibility = visibility;
5337 mView.dispatchSystemUiVisibilityChanged(visibility);
Dianne Hackborncf675782012-05-10 15:07:24 -07005338 }
Joe Onorato664644d2011-01-23 17:53:23 -08005339 }
5340
Craig Mautner9c795042014-10-28 19:59:59 -07005341 public void handleDispatchWindowShown() {
5342 mAttachInfo.mTreeObserver.dispatchOnWindowShown();
5343 }
5344
Christopher Tate2c095f32010-10-04 14:13:40 -07005345 public void getLastTouchPoint(Point outLocation) {
5346 outLocation.x = (int) mLastTouchPoint.x;
5347 outLocation.y = (int) mLastTouchPoint.y;
5348 }
5349
Chris Tate9d1ab882010-11-02 15:55:39 -07005350 public void setDragFocus(View newDragTarget) {
Christopher Tatea53146c2010-09-07 11:57:52 -07005351 if (mCurrentDragView != newDragTarget) {
Chris Tate048691c2010-10-12 17:39:18 -07005352 mCurrentDragView = newDragTarget;
Christopher Tatea53146c2010-09-07 11:57:52 -07005353 }
Christopher Tatea53146c2010-09-07 11:57:52 -07005354 }
5355
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005356 private AudioManager getAudioManager() {
5357 if (mView == null) {
5358 throw new IllegalStateException("getAudioManager called when there is no mView");
5359 }
5360 if (mAudioManager == null) {
5361 mAudioManager = (AudioManager) mView.getContext().getSystemService(Context.AUDIO_SERVICE);
5362 }
5363 return mAudioManager;
5364 }
5365
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005366 public AccessibilityInteractionController getAccessibilityInteractionController() {
5367 if (mView == null) {
5368 throw new IllegalStateException("getAccessibilityInteractionController"
5369 + " called when there is no mView");
5370 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07005371 if (mAccessibilityInteractionController == null) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07005372 mAccessibilityInteractionController = new AccessibilityInteractionController(this);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005373 }
Gilles Debunne5ac84422011-10-19 09:35:58 -07005374 return mAccessibilityInteractionController;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005375 }
5376
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07005377 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
5378 boolean insetsPending) throws RemoteException {
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005379
5380 float appScale = mAttachInfo.mApplicationScale;
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005381 boolean restore = false;
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005382 if (params != null && mTranslator != null) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005383 restore = true;
5384 params.backup();
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005385 mTranslator.translateWindowLayout(params);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005386 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005387 if (params != null) {
5388 if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params);
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005389 }
Dianne Hackborn694f79b2010-03-17 19:44:59 -07005390 mPendingConfiguration.seq = 0;
Dianne Hackbornf123e492010-09-24 11:16:23 -07005391 //Log.d(TAG, ">>>>>> CALLING relayout");
Dianne Hackborn180c4842011-09-13 12:39:25 -07005392 if (params != null && mOrigWindowType != params.type) {
5393 // For compatibility with old apps, don't crash here.
Michael Wright5bd69e62015-05-14 14:48:08 +01005394 if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
Dianne Hackborn180c4842011-09-13 12:39:25 -07005395 Slog.w(TAG, "Window type can not be changed after "
5396 + "the window is added; ignoring change of " + mView);
5397 params.type = mOrigWindowType;
5398 }
5399 }
Jeff Brown98365d72012-08-19 20:30:52 -07005400 int relayoutResult = mWindowSession.relayout(
Dianne Hackborn9a230e02011-10-06 11:51:27 -07005401 mWindow, mSeq, params,
Dianne Hackborn189ee182010-12-02 21:48:53 -08005402 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
5403 (int) (mView.getMeasuredHeight() * appScale + 0.5f),
Jeff Brown98365d72012-08-19 20:30:52 -07005404 viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005405 mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
Filip Gruszczynski2217f612015-05-26 11:32:08 -07005406 mPendingStableInsets, mPendingOutsets, mPendingConfiguration, mSurface);
Dianne Hackbornf123e492010-09-24 11:16:23 -07005407 //Log.d(TAG, "<<<<<< BACK FROM relayout");
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005408 if (restore) {
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07005409 params.restore();
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005410 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07005411
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005412 if (mTranslator != null) {
5413 mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005414 mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005415 mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
5416 mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
Adrian Roosfa104232014-06-20 16:10:14 -07005417 mTranslator.translateRectInScreenToAppWindow(mPendingStableInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005418 }
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07005419 return relayoutResult;
5420 }
Romain Guy8506ab42009-06-11 17:35:47 -07005421
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005422 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005423 * {@inheritDoc}
5424 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005425 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005426 public void playSoundEffect(int effectId) {
5427 checkThread();
5428
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005429 try {
5430 final AudioManager audioManager = getAudioManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005431
Jean-Michel Trivi13b18fd2010-05-05 09:18:15 -07005432 switch (effectId) {
5433 case SoundEffectConstants.CLICK:
5434 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
5435 return;
5436 case SoundEffectConstants.NAVIGATION_DOWN:
5437 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
5438 return;
5439 case SoundEffectConstants.NAVIGATION_LEFT:
5440 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
5441 return;
5442 case SoundEffectConstants.NAVIGATION_RIGHT:
5443 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
5444 return;
5445 case SoundEffectConstants.NAVIGATION_UP:
5446 audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
5447 return;
5448 default:
5449 throw new IllegalArgumentException("unknown effect id " + effectId +
5450 " not defined in " + SoundEffectConstants.class.getCanonicalName());
5451 }
5452 } catch (IllegalStateException e) {
5453 // Exception thrown by getAudioManager() when mView is null
5454 Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e);
5455 e.printStackTrace();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005456 }
5457 }
5458
5459 /**
5460 * {@inheritDoc}
5461 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005462 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005463 public boolean performHapticFeedback(int effectId, boolean always) {
5464 try {
Jeff Brown98365d72012-08-19 20:30:52 -07005465 return mWindowSession.performHapticFeedback(mWindow, effectId, always);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005466 } catch (RemoteException e) {
5467 return false;
5468 }
5469 }
5470
5471 /**
5472 * {@inheritDoc}
5473 */
Igor Murashkina86ab6402013-08-30 12:58:36 -07005474 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005475 public View focusSearch(View focused, int direction) {
5476 checkThread();
5477 if (!(mView instanceof ViewGroup)) {
5478 return null;
5479 }
5480 return FocusFinder.getInstance().findNextFocus((ViewGroup) mView, focused, direction);
5481 }
5482
5483 public void debug() {
5484 mView.debug();
5485 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07005486
Jeff Brown5182c782013-10-15 20:31:52 -07005487 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
5488 String innerPrefix = prefix + " ";
5489 writer.print(prefix); writer.println("ViewRoot:");
5490 writer.print(innerPrefix); writer.print("mAdded="); writer.print(mAdded);
5491 writer.print(" mRemoved="); writer.println(mRemoved);
5492 writer.print(innerPrefix); writer.print("mConsumeBatchedInputScheduled=");
5493 writer.println(mConsumeBatchedInputScheduled);
Michael Wright9d744c72014-02-18 21:27:42 -08005494 writer.print(innerPrefix); writer.print("mConsumeBatchedInputImmediatelyScheduled=");
5495 writer.println(mConsumeBatchedInputImmediatelyScheduled);
Jeff Brown5182c782013-10-15 20:31:52 -07005496 writer.print(innerPrefix); writer.print("mPendingInputEventCount=");
5497 writer.println(mPendingInputEventCount);
5498 writer.print(innerPrefix); writer.print("mProcessInputEventsScheduled=");
5499 writer.println(mProcessInputEventsScheduled);
5500 writer.print(innerPrefix); writer.print("mTraversalScheduled=");
5501 writer.print(mTraversalScheduled);
5502 if (mTraversalScheduled) {
5503 writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
5504 } else {
5505 writer.println();
5506 }
5507 mFirstInputStage.dump(innerPrefix, writer);
5508
5509 mChoreographer.dump(prefix, writer);
5510
5511 writer.print(prefix); writer.println("View Hierarchy:");
5512 dumpViewHierarchy(innerPrefix, writer, mView);
5513 }
5514
5515 private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) {
5516 writer.print(prefix);
5517 if (view == null) {
5518 writer.println("null");
5519 return;
5520 }
5521 writer.println(view.toString());
5522 if (!(view instanceof ViewGroup)) {
5523 return;
5524 }
5525 ViewGroup grp = (ViewGroup)view;
5526 final int N = grp.getChildCount();
5527 if (N <= 0) {
5528 return;
5529 }
5530 prefix = prefix + " ";
5531 for (int i=0; i<N; i++) {
5532 dumpViewHierarchy(prefix, writer, grp.getChildAt(i));
5533 }
5534 }
5535
Romain Guy211370f2012-02-01 16:10:55 -08005536 public void dumpGfxInfo(int[] info) {
Romain Guy54ab3472012-06-14 12:52:53 -07005537 info[0] = info[1] = 0;
Romain Guy65b345f2011-07-27 18:51:50 -07005538 if (mView != null) {
5539 getGfxInfo(mView, info);
Romain Guy65b345f2011-07-27 18:51:50 -07005540 }
5541 }
5542
Romain Guya998dff2012-03-23 18:58:36 -07005543 private static void getGfxInfo(View view, int[] info) {
Chris Craik64a12e12014-03-28 18:12:12 -07005544 RenderNode renderNode = view.mRenderNode;
Romain Guy65b345f2011-07-27 18:51:50 -07005545 info[0]++;
Chris Craik64a12e12014-03-28 18:12:12 -07005546 if (renderNode != null) {
John Reckfe5e7b72014-05-23 17:42:28 -07005547 info[1] += renderNode.getDebugSize();
Romain Guy65b345f2011-07-27 18:51:50 -07005548 }
5549
5550 if (view instanceof ViewGroup) {
5551 ViewGroup group = (ViewGroup) view;
5552
5553 int count = group.getChildCount();
5554 for (int i = 0; i < count; i++) {
5555 getGfxInfo(group.getChildAt(i), info);
5556 }
5557 }
5558 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005559
Craig Mautner8f303ad2013-06-14 11:32:22 -07005560 /**
5561 * @param immediate True, do now if not in traversal. False, put on queue and do later.
5562 * @return True, request has been queued. False, request has been completed.
5563 */
5564 boolean die(boolean immediate) {
Craig Mautnerdf2390a2012-08-29 20:59:22 -07005565 // Make sure we do execute immediately if we are in the middle of a traversal or the damage
5566 // done by dispatchDetachedFromWindow will cause havoc on return.
5567 if (immediate && !mIsInTraversal) {
Dianne Hackborn94d69142009-09-28 22:14:42 -07005568 doDie();
Craig Mautner8f303ad2013-06-14 11:32:22 -07005569 return false;
Dianne Hackborn94d69142009-09-28 22:14:42 -07005570 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07005571
5572 if (!mIsDrawing) {
5573 destroyHardwareRenderer();
5574 } else {
5575 Log.e(TAG, "Attempting to destroy the window while drawing!\n" +
5576 " window=" + this + ", title=" + mWindowAttributes.getTitle());
5577 }
5578 mHandler.sendEmptyMessage(MSG_DIE);
5579 return true;
Dianne Hackborn94d69142009-09-28 22:14:42 -07005580 }
5581
5582 void doDie() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005583 checkThread();
Jeff Brownb75fa302010-07-15 23:47:29 -07005584 if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005585 synchronized (this) {
Craig Mautner8f303ad2013-06-14 11:32:22 -07005586 if (mRemoved) {
5587 return;
5588 }
5589 mRemoved = true;
Romain Guy16260e72011-09-01 14:26:11 -07005590 if (mAdded) {
Romain Guy16260e72011-09-01 14:26:11 -07005591 dispatchDetachedFromWindow();
5592 }
5593
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005594 if (mAdded && !mFirst) {
Romain Guy29d89972010-09-22 16:10:57 -07005595 destroyHardwareRenderer();
5596
Romain Guyedbca122012-04-04 18:25:53 -07005597 if (mView != null) {
5598 int viewVisibility = mView.getVisibility();
5599 boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
5600 if (mWindowAttributesChanged || viewVisibilityChanged) {
5601 // If layout params have been changed, first give them
5602 // to the window manager to make sure it has the correct
5603 // animation info.
5604 try {
5605 if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
Jeff Brown98365d72012-08-19 20:30:52 -07005606 & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
5607 mWindowSession.finishDrawing(mWindow);
Romain Guyedbca122012-04-04 18:25:53 -07005608 }
5609 } catch (RemoteException e) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005610 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005611 }
Craig Mautner8f303ad2013-06-14 11:32:22 -07005612
Romain Guyedbca122012-04-04 18:25:53 -07005613 mSurface.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005614 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005615 }
Romain Guyedbca122012-04-04 18:25:53 -07005616
5617 mAdded = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005618 }
Craig Mautner05eb7302013-06-03 17:24:21 -07005619 WindowManagerGlobal.getInstance().doRemoveView(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005620 }
5621
Dianne Hackborn5fd21692011-06-07 14:09:47 -07005622 public void requestUpdateConfiguration(Configuration config) {
Jeff Browna175a5b2012-02-15 19:18:31 -08005623 Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
5624 mHandler.sendMessage(msg);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07005625 }
5626
Dianne Hackborna53de062012-05-08 18:53:51 -07005627 public void loadSystemProperties() {
Romain Guy5bb3c732012-11-29 17:52:58 -08005628 mHandler.post(new Runnable() {
5629 @Override
5630 public void run() {
5631 // Profiling
5632 mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false);
5633 profileRendering(mAttachInfo.mHasWindowFocus);
5634
5635 // Hardware rendering
5636 if (mAttachInfo.mHardwareRenderer != null) {
John Reckcec24ae2013-11-05 13:27:50 -08005637 if (mAttachInfo.mHardwareRenderer.loadSystemProperties()) {
Romain Guy5bb3c732012-11-29 17:52:58 -08005638 invalidate();
5639 }
5640 }
5641
5642 // Layout debugging
5643 boolean layout = SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false);
5644 if (layout != mAttachInfo.mDebugLayout) {
5645 mAttachInfo.mDebugLayout = layout;
5646 if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
5647 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
5648 }
5649 }
Dianne Hackborna53de062012-05-08 18:53:51 -07005650 }
Romain Guy5bb3c732012-11-29 17:52:58 -08005651 });
Dianne Hackborna53de062012-05-08 18:53:51 -07005652 }
5653
Romain Guy29d89972010-09-22 16:10:57 -07005654 private void destroyHardwareRenderer() {
Chris Craikd36a81f2014-07-17 10:16:51 -07005655 HardwareRenderer hardwareRenderer = mAttachInfo.mHardwareRenderer;
Romain Guya998dff2012-03-23 18:58:36 -07005656
5657 if (hardwareRenderer != null) {
5658 if (mView != null) {
5659 hardwareRenderer.destroyHardwareResources(mView);
5660 }
John Reckf47a5942014-06-30 16:20:04 -07005661 hardwareRenderer.destroy();
Romain Guya998dff2012-03-23 18:58:36 -07005662 hardwareRenderer.setRequested(false);
5663
Chris Craikd36a81f2014-07-17 10:16:51 -07005664 mAttachInfo.mHardwareRenderer = null;
5665 mAttachInfo.mHardwareAccelerated = false;
Romain Guy29d89972010-09-22 16:10:57 -07005666 }
5667 }
5668
Jeff Browna175a5b2012-02-15 19:18:31 -08005669 public void dispatchFinishInputConnection(InputConnection connection) {
5670 Message msg = mHandler.obtainMessage(MSG_FINISH_INPUT_CONNECTION, connection);
5671 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005672 }
Mitsuru Oshima3d914922009-05-13 22:29:15 -07005673
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005674 public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Filip Gruszczynski2217f612015-05-26 11:32:08 -07005675 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
Jorim Jaggi253a20f2015-11-03 12:38:42 +01005676 Configuration newConfig, Rect backDropFrame) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005677 if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": frame=" + frame.toShortString()
5678 + " contentInsets=" + contentInsets.toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005679 + " visibleInsets=" + visibleInsets.toShortString()
Chong Zhangd153c4f2015-11-06 20:26:40 -08005680 + " reportDraw=" + reportDraw
5681 + " backDropFrame=" + backDropFrame);
Chong Zhangdcee1de2015-10-06 10:26:00 -07005682
5683 // Tell all listeners that we are resizing the window so that the chrome can get
5684 // updated as fast as possible on a separate thread,
5685 if (mDragResizing) {
5686 synchronized (mWindowCallbacks) {
5687 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
Jorim Jaggi253a20f2015-11-03 12:38:42 +01005688 mWindowCallbacks.get(i).onWindowSizeIsChanging(backDropFrame);
Chong Zhangdcee1de2015-10-06 10:26:00 -07005689 }
5690 }
5691 }
5692
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005693 Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005694 if (mTranslator != null) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005695 mTranslator.translateRectInScreenToAppWindow(frame);
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005696 mTranslator.translateRectInScreenToAppWindow(overscanInsets);
Dianne Hackborn3556c9a2012-05-04 16:31:25 -07005697 mTranslator.translateRectInScreenToAppWindow(contentInsets);
Mitsuru Oshima64f59342009-06-21 00:03:11 -07005698 mTranslator.translateRectInScreenToAppWindow(visibleInsets);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07005699 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005700 SomeArgs args = SomeArgs.obtain();
5701 final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
5702 args.arg1 = sameProcessCall ? new Rect(frame) : frame;
5703 args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets;
5704 args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
5705 args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig;
Dianne Hackbornc4aad012013-02-22 15:05:25 -08005706 args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
Adrian Roosfa104232014-06-20 16:10:14 -07005707 args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
Filip Gruszczynski2217f612015-05-26 11:32:08 -07005708 args.arg7 = sameProcessCall ? new Rect(outsets) : outsets;
Jorim Jaggia7262a82015-11-03 15:15:40 +01005709 args.arg8 = sameProcessCall ? new Rect(backDropFrame) : backDropFrame;
Svetoslav Ganov758143e2012-08-06 16:40:27 -07005710 msg.obj = args;
Jeff Browna175a5b2012-02-15 19:18:31 -08005711 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005712 }
Chet Haase1f4786b2011-11-02 10:51:52 -07005713
Craig Mautner5702d4d2012-06-30 14:10:16 -07005714 public void dispatchMoved(int newX, int newY) {
5715 if (DEBUG_LAYOUT) Log.v(TAG, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
5716 if (mTranslator != null) {
5717 PointF point = new PointF(newX, newY);
5718 mTranslator.translatePointInScreenToAppWindow(point);
5719 newX = (int) (point.x + 0.5);
5720 newY = (int) (point.y + 0.5);
5721 }
5722 Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY);
5723 mHandler.sendMessage(msg);
5724 }
5725
Jeff Brown4952dfd2011-11-30 19:23:22 -08005726 /**
5727 * Represents a pending input event that is waiting in a queue.
5728 *
5729 * Input events are processed in serial order by the timestamp specified by
Romain Guy211370f2012-02-01 16:10:55 -08005730 * {@link InputEvent#getEventTimeNano()}. In general, the input dispatcher delivers
Jeff Brown4952dfd2011-11-30 19:23:22 -08005731 * one input event to the application at a time and waits for the application
5732 * to finish handling it before delivering the next one.
5733 *
5734 * However, because the application or IME can synthesize and inject multiple
5735 * key events at a time without going through the input dispatcher, we end up
5736 * needing a queue on the application's side.
5737 */
5738 private static final class QueuedInputEvent {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005739 public static final int FLAG_DELIVER_POST_IME = 1 << 0;
5740 public static final int FLAG_DEFERRED = 1 << 1;
5741 public static final int FLAG_FINISHED = 1 << 2;
5742 public static final int FLAG_FINISHED_HANDLED = 1 << 3;
5743 public static final int FLAG_RESYNTHESIZED = 1 << 4;
Michael Wright899d7052014-04-23 17:23:39 -07005744 public static final int FLAG_UNHANDLED = 1 << 5;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005745
5746 public QueuedInputEvent mNext;
5747
5748 public InputEvent mEvent;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005749 public InputEventReceiver mReceiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005750 public int mFlags;
Jeff Brownf9e989d2013-04-04 23:04:03 -07005751
5752 public boolean shouldSkipIme() {
5753 if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
5754 return true;
5755 }
5756 return mEvent instanceof MotionEvent
5757 && mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER);
5758 }
Michael Wright899d7052014-04-23 17:23:39 -07005759
5760 public boolean shouldSendToSynthesizer() {
5761 if ((mFlags & FLAG_UNHANDLED) != 0) {
5762 return true;
5763 }
5764
5765 return false;
5766 }
Michael Wright06a79252014-05-05 17:45:29 -07005767
5768 @Override
5769 public String toString() {
5770 StringBuilder sb = new StringBuilder("QueuedInputEvent{flags=");
5771 boolean hasPrevious = false;
5772 hasPrevious = flagToString("DELIVER_POST_IME", FLAG_DELIVER_POST_IME, hasPrevious, sb);
5773 hasPrevious = flagToString("DEFERRED", FLAG_DEFERRED, hasPrevious, sb);
5774 hasPrevious = flagToString("FINISHED", FLAG_FINISHED, hasPrevious, sb);
5775 hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb);
5776 hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb);
5777 hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb);
5778 if (!hasPrevious) {
5779 sb.append("0");
5780 }
5781 sb.append(", hasNextQueuedEvent=" + (mEvent != null ? "true" : "false"));
5782 sb.append(", hasInputEventReceiver=" + (mReceiver != null ? "true" : "false"));
5783 sb.append(", mEvent=" + mEvent + "}");
5784 return sb.toString();
5785 }
5786
5787 private boolean flagToString(String name, int flag,
5788 boolean hasPrevious, StringBuilder sb) {
5789 if ((mFlags & flag) != 0) {
5790 if (hasPrevious) {
5791 sb.append("|");
5792 }
5793 sb.append(name);
5794 return true;
5795 }
5796 return hasPrevious;
5797 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005798 }
5799
5800 private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
Jeff Brown32cbc38552011-12-01 14:01:49 -08005801 InputEventReceiver receiver, int flags) {
Jeff Brown4952dfd2011-11-30 19:23:22 -08005802 QueuedInputEvent q = mQueuedInputEventPool;
5803 if (q != null) {
5804 mQueuedInputEventPoolSize -= 1;
5805 mQueuedInputEventPool = q.mNext;
5806 q.mNext = null;
5807 } else {
5808 q = new QueuedInputEvent();
Jeff Brown46b9ac02010-04-22 18:58:52 -07005809 }
5810
Jeff Brown4952dfd2011-11-30 19:23:22 -08005811 q.mEvent = event;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005812 q.mReceiver = receiver;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005813 q.mFlags = flags;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005814 return q;
5815 }
5816
5817 private void recycleQueuedInputEvent(QueuedInputEvent q) {
5818 q.mEvent = null;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005819 q.mReceiver = null;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005820
5821 if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
5822 mQueuedInputEventPoolSize += 1;
5823 q.mNext = mQueuedInputEventPool;
5824 mQueuedInputEventPool = q;
5825 }
5826 }
5827
Jeff Brownf9261d22012-02-03 13:49:15 -08005828 void enqueueInputEvent(InputEvent event) {
5829 enqueueInputEvent(event, null, 0, false);
5830 }
5831
Jeff Brown4952dfd2011-11-30 19:23:22 -08005832 void enqueueInputEvent(InputEvent event,
Jeff Brownf9261d22012-02-03 13:49:15 -08005833 InputEventReceiver receiver, int flags, boolean processImmediately) {
Michael Wright5bd69e62015-05-14 14:48:08 +01005834 adjustInputEventForCompatibility(event);
Jeff Brown32cbc38552011-12-01 14:01:49 -08005835 QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005836
Jeff Brown4952dfd2011-11-30 19:23:22 -08005837 // Always enqueue the input event in order, regardless of its time stamp.
5838 // We do this because the application or the IME may inject key events
5839 // in response to touch events and we want to ensure that the injected keys
5840 // are processed in the order they were received and we cannot trust that
5841 // the time stamp of injected events are monotonic.
Michael Wrightc8a7e542013-03-20 17:58:33 -07005842 QueuedInputEvent last = mPendingInputEventTail;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005843 if (last == null) {
Michael Wrightc8a7e542013-03-20 17:58:33 -07005844 mPendingInputEventHead = q;
5845 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005846 } else {
Jeff Brown4952dfd2011-11-30 19:23:22 -08005847 last.mNext = q;
Michael Wrightc8a7e542013-03-20 17:58:33 -07005848 mPendingInputEventTail = q;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005849 }
Michael Wright95ae9422013-03-14 10:58:50 -07005850 mPendingInputEventCount += 1;
5851 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
5852 mPendingInputEventCount);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005853
Jeff Brownf9261d22012-02-03 13:49:15 -08005854 if (processImmediately) {
5855 doProcessInputEvents();
5856 } else {
5857 scheduleProcessInputEvents();
5858 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005859 }
5860
5861 private void scheduleProcessInputEvents() {
Jeff Brown96e942d2011-11-30 19:55:01 -08005862 if (!mProcessInputEventsScheduled) {
5863 mProcessInputEventsScheduled = true;
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005864 Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
5865 msg.setAsynchronous(true);
5866 mHandler.sendMessage(msg);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005867 }
5868 }
5869
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005870 void doProcessInputEvents() {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005871 // Deliver all pending input events in the queue.
Michael Wrightc8a7e542013-03-20 17:58:33 -07005872 while (mPendingInputEventHead != null) {
5873 QueuedInputEvent q = mPendingInputEventHead;
5874 mPendingInputEventHead = q.mNext;
5875 if (mPendingInputEventHead == null) {
5876 mPendingInputEventTail = null;
5877 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005878 q.mNext = null;
Jeff Brown29c0ed22013-01-14 13:50:37 -08005879
Michael Wright95ae9422013-03-14 10:58:50 -07005880 mPendingInputEventCount -= 1;
5881 Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
5882 mPendingInputEventCount);
5883
John Reckba6adf62015-02-19 14:36:50 -08005884 long eventTime = q.mEvent.getEventTimeNano();
5885 long oldestEventTime = eventTime;
5886 if (q.mEvent instanceof MotionEvent) {
5887 MotionEvent me = (MotionEvent)q.mEvent;
5888 if (me.getHistorySize() > 0) {
5889 oldestEventTime = me.getHistoricalEventTimeNano(0);
5890 }
5891 }
5892 mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
5893
Jeff Brownf9e989d2013-04-04 23:04:03 -07005894 deliverInputEvent(q);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005895 }
5896
5897 // We are done processing all input events that we can process right now
5898 // so we can clear the pending flag immediately.
Jeff Brown96e942d2011-11-30 19:55:01 -08005899 if (mProcessInputEventsScheduled) {
5900 mProcessInputEventsScheduled = false;
Jeff Browna175a5b2012-02-15 19:18:31 -08005901 mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
Jeff Brown4952dfd2011-11-30 19:23:22 -08005902 }
5903 }
5904
Jeff Brownf9e989d2013-04-04 23:04:03 -07005905 private void deliverInputEvent(QueuedInputEvent q) {
Michael Wrightd2c3adc2014-02-18 22:50:50 -08005906 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
5907 q.mEvent.getSequenceNumber());
5908 if (mInputEventConsistencyVerifier != null) {
5909 mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
5910 }
Michael Wrightc8a7e542013-03-20 17:58:33 -07005911
Michael Wright899d7052014-04-23 17:23:39 -07005912 InputStage stage;
5913 if (q.shouldSendToSynthesizer()) {
5914 stage = mSyntheticInputStage;
5915 } else {
5916 stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
5917 }
5918
Michael Wrightd2c3adc2014-02-18 22:50:50 -08005919 if (stage != null) {
5920 stage.deliver(q);
5921 } else {
5922 finishInputEvent(q);
Michael Wrightbf020962013-03-28 17:27:50 -07005923 }
Michael Wrightbf020962013-03-28 17:27:50 -07005924 }
5925
Jeff Brownf9e989d2013-04-04 23:04:03 -07005926 private void finishInputEvent(QueuedInputEvent q) {
Michael Wrightd2c3adc2014-02-18 22:50:50 -08005927 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
5928 q.mEvent.getSequenceNumber());
Michael Wright9d744c72014-02-18 21:27:42 -08005929
Jeff Brown32cbc38552011-12-01 14:01:49 -08005930 if (q.mReceiver != null) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07005931 boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
Jeff Brown32cbc38552011-12-01 14:01:49 -08005932 q.mReceiver.finishInputEvent(q.mEvent, handled);
Jeff Brown92cc2d82011-12-02 01:19:47 -08005933 } else {
5934 q.mEvent.recycleIfNeededAfterDispatch();
Jeff Brown4952dfd2011-11-30 19:23:22 -08005935 }
5936
5937 recycleQueuedInputEvent(q);
Jeff Brown29c0ed22013-01-14 13:50:37 -08005938 }
Jeff Brown4952dfd2011-11-30 19:23:22 -08005939
Michael Wright5bd69e62015-05-14 14:48:08 +01005940 private void adjustInputEventForCompatibility(InputEvent e) {
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -07005941 if (mTargetSdkVersion < Build.VERSION_CODES.M && e instanceof MotionEvent) {
Michael Wright5bd69e62015-05-14 14:48:08 +01005942 MotionEvent motion = (MotionEvent) e;
5943 final int mask =
5944 MotionEvent.BUTTON_STYLUS_PRIMARY | MotionEvent.BUTTON_STYLUS_SECONDARY;
5945 final int buttonState = motion.getButtonState();
5946 final int compatButtonState = (buttonState & mask) >> 4;
5947 if (compatButtonState != 0) {
5948 motion.setButtonState(buttonState | compatButtonState);
5949 }
5950 }
5951 }
5952
Jeff Brownf9e989d2013-04-04 23:04:03 -07005953 static boolean isTerminalInputEvent(InputEvent event) {
Jeff Brown29c0ed22013-01-14 13:50:37 -08005954 if (event instanceof KeyEvent) {
5955 final KeyEvent keyEvent = (KeyEvent)event;
5956 return keyEvent.getAction() == KeyEvent.ACTION_UP;
5957 } else {
5958 final MotionEvent motionEvent = (MotionEvent)event;
5959 final int action = motionEvent.getAction();
5960 return action == MotionEvent.ACTION_UP
5961 || action == MotionEvent.ACTION_CANCEL
5962 || action == MotionEvent.ACTION_HOVER_EXIT;
Jeff Brown4952dfd2011-11-30 19:23:22 -08005963 }
5964 }
5965
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005966 void scheduleConsumeBatchedInput() {
5967 if (!mConsumeBatchedInputScheduled) {
5968 mConsumeBatchedInputScheduled = true;
5969 mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
5970 mConsumedBatchedInputRunnable, null);
Jeff Brown4a06c802012-02-15 15:06:01 -08005971 }
5972 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005973
5974 void unscheduleConsumeBatchedInput() {
5975 if (mConsumeBatchedInputScheduled) {
5976 mConsumeBatchedInputScheduled = false;
5977 mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT,
5978 mConsumedBatchedInputRunnable, null);
5979 }
5980 }
5981
Michael Wright9d744c72014-02-18 21:27:42 -08005982 void scheduleConsumeBatchedInputImmediately() {
5983 if (!mConsumeBatchedInputImmediatelyScheduled) {
5984 unscheduleConsumeBatchedInput();
5985 mConsumeBatchedInputImmediatelyScheduled = true;
5986 mHandler.post(mConsumeBatchedInputImmediatelyRunnable);
5987 }
5988 }
5989
Jeff Brown771526c2012-04-27 15:13:25 -07005990 void doConsumeBatchedInput(long frameTimeNanos) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07005991 if (mConsumeBatchedInputScheduled) {
5992 mConsumeBatchedInputScheduled = false;
Jeff Brown330314c2012-04-27 02:20:22 -07005993 if (mInputEventReceiver != null) {
Michael Wright9d744c72014-02-18 21:27:42 -08005994 if (mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos)
5995 && frameTimeNanos != -1) {
Michael Wright62ce65d2013-10-25 14:50:36 -07005996 // If we consumed a batch here, we want to go ahead and schedule the
5997 // consumption of batched input events on the next frame. Otherwise, we would
5998 // wait until we have more input events pending and might get starved by other
Michael Wright9d744c72014-02-18 21:27:42 -08005999 // things occurring in the process. If the frame time is -1, however, then
6000 // we're in a non-batching mode, so there's no need to schedule this.
Michael Wright62ce65d2013-10-25 14:50:36 -07006001 scheduleConsumeBatchedInput();
6002 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006003 }
Jeff Brown330314c2012-04-27 02:20:22 -07006004 doProcessInputEvents();
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006005 }
6006 }
6007
6008 final class TraversalRunnable implements Runnable {
6009 @Override
6010 public void run() {
6011 doTraversal();
6012 }
6013 }
6014 final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
Jeff Brown4a06c802012-02-15 15:06:01 -08006015
Jeff Brown32cbc38552011-12-01 14:01:49 -08006016 final class WindowInputEventReceiver extends InputEventReceiver {
6017 public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
6018 super(inputChannel, looper);
Jeff Brown46b9ac02010-04-22 18:58:52 -07006019 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08006020
6021 @Override
6022 public void onInputEvent(InputEvent event) {
Jeff Brownf9261d22012-02-03 13:49:15 -08006023 enqueueInputEvent(event, this, 0, true);
Jeff Brown32cbc38552011-12-01 14:01:49 -08006024 }
Jeff Brown072ec962012-02-07 14:46:57 -08006025
6026 @Override
6027 public void onBatchedInputEventPending() {
Michael Wright9d744c72014-02-18 21:27:42 -08006028 if (mUnbufferedInputDispatch) {
6029 super.onBatchedInputEventPending();
6030 } else {
6031 scheduleConsumeBatchedInput();
6032 }
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006033 }
6034
6035 @Override
6036 public void dispose() {
6037 unscheduleConsumeBatchedInput();
6038 super.dispose();
Jeff Brown072ec962012-02-07 14:46:57 -08006039 }
Jeff Brown32cbc38552011-12-01 14:01:49 -08006040 }
6041 WindowInputEventReceiver mInputEventReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006042
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006043 final class ConsumeBatchedInputRunnable implements Runnable {
6044 @Override
6045 public void run() {
Jeff Brown771526c2012-04-27 15:13:25 -07006046 doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006047 }
6048 }
6049 final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =
6050 new ConsumeBatchedInputRunnable();
6051 boolean mConsumeBatchedInputScheduled;
6052
Michael Wright9d744c72014-02-18 21:27:42 -08006053 final class ConsumeBatchedInputImmediatelyRunnable implements Runnable {
6054 @Override
6055 public void run() {
6056 doConsumeBatchedInput(-1);
6057 }
6058 }
6059 final ConsumeBatchedInputImmediatelyRunnable mConsumeBatchedInputImmediatelyRunnable =
6060 new ConsumeBatchedInputImmediatelyRunnable();
6061 boolean mConsumeBatchedInputImmediatelyScheduled;
6062
Jeff Brown6cb7b462012-03-05 13:21:17 -08006063 final class InvalidateOnAnimationRunnable implements Runnable {
6064 private boolean mPosted;
Igor Murashkina86ab6402013-08-30 12:58:36 -07006065 private final ArrayList<View> mViews = new ArrayList<View>();
6066 private final ArrayList<AttachInfo.InvalidateInfo> mViewRects =
Jeff Brown6cb7b462012-03-05 13:21:17 -08006067 new ArrayList<AttachInfo.InvalidateInfo>();
6068 private View[] mTempViews;
6069 private AttachInfo.InvalidateInfo[] mTempViewRects;
6070
6071 public void addView(View view) {
6072 synchronized (this) {
6073 mViews.add(view);
6074 postIfNeededLocked();
6075 }
6076 }
6077
6078 public void addViewRect(AttachInfo.InvalidateInfo info) {
6079 synchronized (this) {
6080 mViewRects.add(info);
6081 postIfNeededLocked();
6082 }
6083 }
6084
6085 public void removeView(View view) {
6086 synchronized (this) {
6087 mViews.remove(view);
6088
6089 for (int i = mViewRects.size(); i-- > 0; ) {
6090 AttachInfo.InvalidateInfo info = mViewRects.get(i);
6091 if (info.target == view) {
6092 mViewRects.remove(i);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08006093 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08006094 }
6095 }
6096
6097 if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006098 mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08006099 mPosted = false;
6100 }
6101 }
6102 }
6103
6104 @Override
6105 public void run() {
6106 final int viewCount;
6107 final int viewRectCount;
6108 synchronized (this) {
6109 mPosted = false;
6110
6111 viewCount = mViews.size();
6112 if (viewCount != 0) {
6113 mTempViews = mViews.toArray(mTempViews != null
6114 ? mTempViews : new View[viewCount]);
6115 mViews.clear();
6116 }
6117
6118 viewRectCount = mViewRects.size();
6119 if (viewRectCount != 0) {
6120 mTempViewRects = mViewRects.toArray(mTempViewRects != null
6121 ? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]);
6122 mViewRects.clear();
6123 }
6124 }
6125
6126 for (int i = 0; i < viewCount; i++) {
6127 mTempViews[i].invalidate();
Adam Powell3e3c4ee2012-05-16 17:34:21 -07006128 mTempViews[i] = null;
Jeff Brown6cb7b462012-03-05 13:21:17 -08006129 }
6130
6131 for (int i = 0; i < viewRectCount; i++) {
6132 final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
6133 info.target.invalidate(info.left, info.top, info.right, info.bottom);
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08006134 info.recycle();
Jeff Brown6cb7b462012-03-05 13:21:17 -08006135 }
6136 }
6137
6138 private void postIfNeededLocked() {
6139 if (!mPosted) {
Jeff Brownebb2d8d2012-03-23 17:14:34 -07006140 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
Jeff Brown6cb7b462012-03-05 13:21:17 -08006141 mPosted = true;
6142 }
6143 }
6144 }
6145 final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
6146 new InvalidateOnAnimationRunnable();
6147
Jeff Browna175a5b2012-02-15 19:18:31 -08006148 public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
6149 Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
6150 mHandler.sendMessageDelayed(msg, delayMilliseconds);
6151 }
6152
Jeff Browna175a5b2012-02-15 19:18:31 -08006153 public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
6154 long delayMilliseconds) {
6155 final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
6156 mHandler.sendMessageDelayed(msg, delayMilliseconds);
6157 }
6158
Jeff Brown6cb7b462012-03-05 13:21:17 -08006159 public void dispatchInvalidateOnAnimation(View view) {
6160 mInvalidateOnAnimationRunnable.addView(view);
6161 }
6162
6163 public void dispatchInvalidateRectOnAnimation(AttachInfo.InvalidateInfo info) {
6164 mInvalidateOnAnimationRunnable.addViewRect(info);
6165 }
6166
6167 public void cancelInvalidate(View view) {
6168 mHandler.removeMessages(MSG_INVALIDATE, view);
6169 // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning
6170 // them to the pool
6171 mHandler.removeMessages(MSG_INVALIDATE_RECT, view);
6172 mInvalidateOnAnimationRunnable.removeView(view);
6173 }
6174
keunyoung30f420f2013-08-02 14:23:10 -07006175 public void dispatchInputEvent(InputEvent event) {
Jae Seo6a6059a2014-04-17 21:35:29 -07006176 dispatchInputEvent(event, null);
6177 }
6178
6179 public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
6180 SomeArgs args = SomeArgs.obtain();
6181 args.arg1 = event;
6182 args.arg2 = receiver;
6183 Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
Jeff Browne0dbd002012-02-15 19:34:58 -08006184 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08006185 mHandler.sendMessage(msg);
6186 }
6187
Michael Wright899d7052014-04-23 17:23:39 -07006188 public void synthesizeInputEvent(InputEvent event) {
6189 Message msg = mHandler.obtainMessage(MSG_SYNTHESIZE_INPUT_EVENT, event);
6190 msg.setAsynchronous(true);
6191 mHandler.sendMessage(msg);
6192 }
6193
Jeff Browna175a5b2012-02-15 19:18:31 -08006194 public void dispatchKeyFromIme(KeyEvent event) {
6195 Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
Jeff Browne0dbd002012-02-15 19:34:58 -08006196 msg.setAsynchronous(true);
Jeff Browna175a5b2012-02-15 19:18:31 -08006197 mHandler.sendMessage(msg);
Jeff Browncb1404e2011-01-15 18:14:15 -08006198 }
6199
Michael Wright899d7052014-04-23 17:23:39 -07006200 /**
6201 * Reinject unhandled {@link InputEvent}s in order to synthesize fallbacks events.
6202 *
6203 * Note that it is the responsibility of the caller of this API to recycle the InputEvent it
6204 * passes in.
6205 */
Michael Wright3da28342014-04-22 17:00:11 -07006206 public void dispatchUnhandledInputEvent(InputEvent event) {
Michael Wright899d7052014-04-23 17:23:39 -07006207 if (event instanceof MotionEvent) {
6208 event = MotionEvent.obtain((MotionEvent) event);
Michael Wright3da28342014-04-22 17:00:11 -07006209 }
Michael Wright899d7052014-04-23 17:23:39 -07006210 synthesizeInputEvent(event);
Michael Wright3da28342014-04-22 17:00:11 -07006211 }
6212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006213 public void dispatchAppVisibility(boolean visible) {
Jeff Browna175a5b2012-02-15 19:18:31 -08006214 Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006215 msg.arg1 = visible ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08006216 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006217 }
6218
6219 public void dispatchGetNewSurface() {
Jeff Browna175a5b2012-02-15 19:18:31 -08006220 Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
6221 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006222 }
6223
6224 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
6225 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08006226 msg.what = MSG_WINDOW_FOCUS_CHANGED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006227 msg.arg1 = hasFocus ? 1 : 0;
6228 msg.arg2 = inTouchMode ? 1 : 0;
Jeff Browna175a5b2012-02-15 19:18:31 -08006229 mHandler.sendMessage(msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006230 }
6231
Craig Mautner9c795042014-10-28 19:59:59 -07006232 public void dispatchWindowShown() {
6233 mHandler.sendEmptyMessage(MSG_DISPATCH_WINDOW_SHOWN);
6234 }
6235
Dianne Hackbornffa42482009-09-23 22:20:11 -07006236 public void dispatchCloseSystemDialogs(String reason) {
6237 Message msg = Message.obtain();
Jeff Browna175a5b2012-02-15 19:18:31 -08006238 msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
Dianne Hackbornffa42482009-09-23 22:20:11 -07006239 msg.obj = reason;
Jeff Browna175a5b2012-02-15 19:18:31 -08006240 mHandler.sendMessage(msg);
Dianne Hackbornffa42482009-09-23 22:20:11 -07006241 }
Christopher Tatea53146c2010-09-07 11:57:52 -07006242
6243 public void dispatchDragEvent(DragEvent event) {
Chris Tate91e9bb32010-10-12 12:58:43 -07006244 final int what;
6245 if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
Jeff Browna175a5b2012-02-15 19:18:31 -08006246 what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
6247 mHandler.removeMessages(what);
Chris Tate91e9bb32010-10-12 12:58:43 -07006248 } else {
Jeff Browna175a5b2012-02-15 19:18:31 -08006249 what = MSG_DISPATCH_DRAG_EVENT;
Chris Tate91e9bb32010-10-12 12:58:43 -07006250 }
Jeff Browna175a5b2012-02-15 19:18:31 -08006251 Message msg = mHandler.obtainMessage(what, event);
6252 mHandler.sendMessage(msg);
Christopher Tatea53146c2010-09-07 11:57:52 -07006253 }
6254
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006255 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
6256 int localValue, int localChanges) {
6257 SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
6258 args.seq = seq;
6259 args.globalVisibility = globalVisibility;
6260 args.localValue = localValue;
6261 args.localChanges = localChanges;
Jeff Browna175a5b2012-02-15 19:18:31 -08006262 mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
6263 }
6264
6265 public void dispatchCheckFocus() {
6266 if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
6267 // This will result in a call to checkFocus() below.
6268 mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
6269 }
Joe Onorato664644d2011-01-23 17:53:23 -08006270 }
6271
svetoslavganov75986cf2009-05-14 22:28:01 -07006272 /**
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006273 * Post a callback to send a
6274 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
Svetoslav Ganova0156172011-06-26 17:55:44 -07006275 * This event is send at most once every
6276 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}.
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006277 */
Alan Viverette77e9a282013-09-12 17:16:09 -07006278 private void postSendWindowContentChangedCallback(View source, int changeType) {
Svetoslav Ganova0156172011-06-26 17:55:44 -07006279 if (mSendWindowContentChangedAccessibilityEvent == null) {
6280 mSendWindowContentChangedAccessibilityEvent =
6281 new SendWindowContentChangedAccessibilityEvent();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006282 }
Alan Viverette77e9a282013-09-12 17:16:09 -07006283 mSendWindowContentChangedAccessibilityEvent.runOrPost(source, changeType);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006284 }
6285
6286 /**
6287 * Remove a posted callback to send a
6288 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
6289 */
6290 private void removeSendWindowContentChangedCallback() {
Svetoslav Ganova0156172011-06-26 17:55:44 -07006291 if (mSendWindowContentChangedAccessibilityEvent != null) {
Jeff Browna175a5b2012-02-15 19:18:31 -08006292 mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07006293 }
6294 }
6295
Igor Murashkina86ab6402013-08-30 12:58:36 -07006296 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006297 public boolean showContextMenuForChild(View originalView) {
6298 return false;
6299 }
6300
Igor Murashkina86ab6402013-08-30 12:58:36 -07006301 @Override
Oren Blasberged391262015-09-01 12:12:51 -07006302 public boolean showContextMenuForChild(View originalView, float x, float y) {
6303 return false;
6304 }
6305
6306 @Override
Adam Powell6e346362010-07-23 10:18:23 -07006307 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
6308 return null;
6309 }
6310
Igor Murashkina86ab6402013-08-30 12:58:36 -07006311 @Override
Clara Bayarri4423d912015-03-02 19:42:48 +00006312 public ActionMode startActionModeForChild(
6313 View originalView, ActionMode.Callback callback, int type) {
6314 return null;
6315 }
6316
6317 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006318 public void createContextMenu(ContextMenu menu) {
6319 }
6320
Igor Murashkina86ab6402013-08-30 12:58:36 -07006321 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006322 public void childDrawableStateChanged(View child) {
6323 }
6324
Igor Murashkina86ab6402013-08-30 12:58:36 -07006325 @Override
Svetoslav Ganov736c2752011-04-22 18:30:36 -07006326 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
George Mount41725de2015-04-09 08:23:05 -07006327 if (mView == null || mStopped || mPausedForTransition) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -07006328 return false;
6329 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006330 // Intercept accessibility focus events fired by virtual nodes to keep
6331 // track of accessibility focus position in such nodes.
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006332 final int eventType = event.getEventType();
6333 switch (eventType) {
6334 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006335 final long sourceNodeId = event.getSourceNodeId();
6336 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
6337 sourceNodeId);
6338 View source = mView.findViewByAccessibilityId(accessibilityViewId);
6339 if (source != null) {
6340 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
6341 if (provider != null) {
Svetoslavb3ba1d42014-09-26 15:20:40 -07006342 final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
6343 sourceNodeId);
6344 final AccessibilityNodeInfo node;
6345 if (virtualNodeId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
6346 node = provider.createAccessibilityNodeInfo(
6347 AccessibilityNodeProvider.HOST_VIEW_ID);
6348 } else {
6349 node = provider.createAccessibilityNodeInfo(virtualNodeId);
6350 }
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006351 setAccessibilityFocus(source, node);
6352 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006353 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006354 } break;
6355 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
Svetoslav Ganov45a02e02012-06-17 15:07:29 -07006356 final long sourceNodeId = event.getSourceNodeId();
6357 final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
6358 sourceNodeId);
6359 View source = mView.findViewByAccessibilityId(accessibilityViewId);
6360 if (source != null) {
6361 AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
6362 if (provider != null) {
6363 setAccessibilityFocus(null, null);
6364 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006365 }
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006366 } break;
Svetoslavf0c758b2014-09-03 17:47:37 -07006367
6368
6369 case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: {
Alan Viverette34457f52015-03-25 13:09:20 -07006370 handleWindowContentChangedEvent(event);
Svetoslavf0c758b2014-09-03 17:47:37 -07006371 } break;
Svetoslav Ganov791fd312012-05-14 15:12:30 -07006372 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006373 mAccessibilityManager.sendAccessibilityEvent(event);
Svetoslav Ganov736c2752011-04-22 18:30:36 -07006374 return true;
6375 }
6376
Alan Viverette34457f52015-03-25 13:09:20 -07006377 /**
6378 * Updates the focused virtual view, when necessary, in response to a
6379 * content changed event.
6380 * <p>
6381 * This is necessary to get updated bounds after a position change.
6382 *
6383 * @param event an accessibility event of type
6384 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}
6385 */
6386 private void handleWindowContentChangedEvent(AccessibilityEvent event) {
Alan Viverette25acc7e2015-05-19 11:32:08 -07006387 final View focusedHost = mAccessibilityFocusedHost;
6388 if (focusedHost == null || mAccessibilityFocusedVirtualView == null) {
6389 // No virtual view focused, nothing to do here.
Alan Viverette34457f52015-03-25 13:09:20 -07006390 return;
6391 }
6392
Alan Viverette25acc7e2015-05-19 11:32:08 -07006393 final AccessibilityNodeProvider provider = focusedHost.getAccessibilityNodeProvider();
Alan Viverette34457f52015-03-25 13:09:20 -07006394 if (provider == null) {
Alan Viverette25acc7e2015-05-19 11:32:08 -07006395 // Error state: virtual view with no provider. Clear focus.
6396 mAccessibilityFocusedHost = null;
6397 mAccessibilityFocusedVirtualView = null;
6398 focusedHost.clearAccessibilityFocusNoCallbacks();
Alan Viverette34457f52015-03-25 13:09:20 -07006399 return;
6400 }
6401
6402 // We only care about change types that may affect the bounds of the
6403 // focused virtual view.
6404 final int changes = event.getContentChangeTypes();
6405 if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) == 0
6406 && changes != AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) {
6407 return;
6408 }
6409
6410 final long eventSourceNodeId = event.getSourceNodeId();
6411 final int changedViewId = AccessibilityNodeInfo.getAccessibilityViewId(eventSourceNodeId);
6412
6413 // Search up the tree for subtree containment.
6414 boolean hostInSubtree = false;
6415 View root = mAccessibilityFocusedHost;
6416 while (root != null && !hostInSubtree) {
6417 if (changedViewId == root.getAccessibilityViewId()) {
6418 hostInSubtree = true;
6419 } else {
6420 final ViewParent parent = root.getParent();
6421 if (parent instanceof View) {
6422 root = (View) parent;
6423 } else {
6424 root = null;
6425 }
6426 }
6427 }
6428
6429 // We care only about changes in subtrees containing the host view.
6430 if (!hostInSubtree) {
6431 return;
6432 }
6433
6434 final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId();
6435 int focusedChildId = AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId);
6436 if (focusedChildId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
6437 // TODO: Should we clear the focused virtual view?
6438 focusedChildId = AccessibilityNodeProvider.HOST_VIEW_ID;
6439 }
6440
6441 // Refresh the node for the focused virtual view.
Alan Viverettea7ea65e2015-05-15 11:30:21 -07006442 final Rect oldBounds = mTempRect;
6443 mAccessibilityFocusedVirtualView.getBoundsInScreen(oldBounds);
Alan Viverette34457f52015-03-25 13:09:20 -07006444 mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo(focusedChildId);
Alan Viverette25acc7e2015-05-19 11:32:08 -07006445 if (mAccessibilityFocusedVirtualView == null) {
6446 // Error state: The node no longer exists. Clear focus.
6447 mAccessibilityFocusedHost = null;
6448 focusedHost.clearAccessibilityFocusNoCallbacks();
6449
6450 // This will probably fail, but try to keep the provider's internal
6451 // state consistent by clearing focus.
6452 provider.performAction(focusedChildId,
6453 AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(), null);
Alan Viverettea7ea65e2015-05-15 11:30:21 -07006454 invalidateRectOnScreen(oldBounds);
Alan Viverette25acc7e2015-05-19 11:32:08 -07006455 } else {
6456 // The node was refreshed, invalidate bounds if necessary.
6457 final Rect newBounds = mAccessibilityFocusedVirtualView.getBoundsInScreen();
6458 if (!oldBounds.equals(newBounds)) {
6459 oldBounds.union(newBounds);
6460 invalidateRectOnScreen(oldBounds);
6461 }
Alan Viverettea7ea65e2015-05-15 11:30:21 -07006462 }
Alan Viverette34457f52015-03-25 13:09:20 -07006463 }
6464
Svetoslav Ganov42138042012-03-20 11:51:39 -07006465 @Override
Alan Viverette77e9a282013-09-12 17:16:09 -07006466 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
6467 postSendWindowContentChangedCallback(source, changeType);
Svetoslav Ganov42138042012-03-20 11:51:39 -07006468 }
6469
Fabrice Di Meglio9dd4c5c2013-02-08 18:15:07 -08006470 @Override
6471 public boolean canResolveLayoutDirection() {
6472 return true;
6473 }
6474
6475 @Override
6476 public boolean isLayoutDirectionResolved() {
6477 return true;
6478 }
6479
6480 @Override
6481 public int getLayoutDirection() {
6482 return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT;
6483 }
6484
6485 @Override
6486 public boolean canResolveTextDirection() {
6487 return true;
6488 }
6489
6490 @Override
6491 public boolean isTextDirectionResolved() {
6492 return true;
6493 }
6494
6495 @Override
6496 public int getTextDirection() {
6497 return View.TEXT_DIRECTION_RESOLVED_DEFAULT;
6498 }
6499
6500 @Override
6501 public boolean canResolveTextAlignment() {
6502 return true;
6503 }
6504
6505 @Override
6506 public boolean isTextAlignmentResolved() {
6507 return true;
6508 }
6509
6510 @Override
6511 public int getTextAlignment() {
6512 return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT;
6513 }
6514
Svetoslav Ganov42138042012-03-20 11:51:39 -07006515 private View getCommonPredecessor(View first, View second) {
Chris Craikd36a81f2014-07-17 10:16:51 -07006516 if (mTempHashSet == null) {
6517 mTempHashSet = new HashSet<View>();
Svetoslav Ganov42138042012-03-20 11:51:39 -07006518 }
Chris Craikd36a81f2014-07-17 10:16:51 -07006519 HashSet<View> seen = mTempHashSet;
6520 seen.clear();
6521 View firstCurrent = first;
6522 while (firstCurrent != null) {
6523 seen.add(firstCurrent);
6524 ViewParent firstCurrentParent = firstCurrent.mParent;
6525 if (firstCurrentParent instanceof View) {
6526 firstCurrent = (View) firstCurrentParent;
6527 } else {
6528 firstCurrent = null;
6529 }
6530 }
6531 View secondCurrent = second;
6532 while (secondCurrent != null) {
6533 if (seen.contains(secondCurrent)) {
6534 seen.clear();
6535 return secondCurrent;
6536 }
6537 ViewParent secondCurrentParent = secondCurrent.mParent;
6538 if (secondCurrentParent instanceof View) {
6539 secondCurrent = (View) secondCurrentParent;
6540 } else {
6541 secondCurrent = null;
6542 }
6543 }
6544 seen.clear();
Svetoslav Ganov42138042012-03-20 11:51:39 -07006545 return null;
6546 }
6547
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006548 void checkThread() {
6549 if (mThread != Thread.currentThread()) {
6550 throw new CalledFromWrongThreadException(
6551 "Only the original thread that created a view hierarchy can touch its views.");
6552 }
6553 }
6554
Igor Murashkina86ab6402013-08-30 12:58:36 -07006555 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006556 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Joe Onoratoc6cc0f82011-04-12 11:53:13 -07006557 // ViewAncestor never intercepts touch event, so this can be a no-op
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006558 }
6559
Igor Murashkina86ab6402013-08-30 12:58:36 -07006560 @Override
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07006561 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
6562 final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
6563 if (rectangle != null) {
6564 mTempRect.set(rectangle);
6565 mTempRect.offset(0, -mCurScrollY);
6566 mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
6567 try {
Svetoslavf7174e82014-06-12 11:29:35 -07006568 mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect);
Svetoslav Ganov1cf70bb2012-08-06 10:53:34 -07006569 } catch (RemoteException re) {
6570 /* ignore */
6571 }
6572 }
6573 return scrolled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006574 }
Romain Guy8506ab42009-06-11 17:35:47 -07006575
Igor Murashkina86ab6402013-08-30 12:58:36 -07006576 @Override
Adam Powell539ee872012-02-03 19:00:49 -08006577 public void childHasTransientStateChanged(View child, boolean hasTransientState) {
6578 // Do nothing.
6579 }
6580
Adam Powell10ba2772014-04-15 09:46:51 -07006581 @Override
6582 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
6583 return false;
6584 }
6585
6586 @Override
6587 public void onStopNestedScroll(View target) {
6588 }
6589
6590 @Override
6591 public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
6592 }
6593
6594 @Override
6595 public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
6596 int dxUnconsumed, int dyUnconsumed) {
6597 }
6598
6599 @Override
6600 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
6601 }
6602
6603 @Override
Adam Powellb36e4f92014-05-01 10:23:33 -07006604 public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
Adam Powell10ba2772014-04-15 09:46:51 -07006605 return false;
6606 }
6607
Adam Powellb72be592014-07-16 21:41:31 -07006608 @Override
6609 public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
6610 return false;
6611 }
6612
Adam Powellb6ab0982015-01-07 17:00:12 -08006613 @Override
6614 public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
6615 return false;
6616 }
6617
Jorim Jaggib774e552015-08-24 14:52:45 -07006618 /**
6619 * Force the window to report its next draw.
6620 * <p>
6621 * This method is only supposed to be used to speed up the interaction from SystemUI and window
6622 * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE
6623 * unless you fully understand this interaction.
6624 * @hide
6625 */
6626 public void setReportNextDraw() {
6627 mReportNextDraw = true;
6628 invalidate();
6629 }
6630
Craig Mautnerbc57cd12013-08-19 15:47:42 -07006631 void changeCanvasOpacity(boolean opaque) {
Craig Mautnerbc57cd12013-08-19 15:47:42 -07006632 Log.d(TAG, "changeCanvasOpacity: opaque=" + opaque);
John Reck63a06672014-05-07 13:45:54 -07006633 if (mAttachInfo.mHardwareRenderer != null) {
6634 mAttachInfo.mHardwareRenderer.setOpaque(opaque);
6635 }
Craig Mautnerbc57cd12013-08-19 15:47:42 -07006636 }
6637
Rob Carr64e516f2015-10-29 00:20:45 +00006638 long getNextFrameNumber() {
6639 long frameNumber = -1;
6640 if (mSurfaceHolder != null) {
6641 mSurfaceHolder.mSurfaceLock.lock();
6642 }
6643 if (mSurface.isValid()) {
6644 frameNumber = mSurface.getNextFrameNumber();
6645 }
6646 if (mSurfaceHolder != null) {
6647 mSurfaceHolder.mSurfaceLock.unlock();
6648 }
6649 return frameNumber;
6650 }
6651
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006652 class TakenSurfaceHolder extends BaseSurfaceHolder {
6653 @Override
6654 public boolean onAllowLockCanvas() {
6655 return mDrawingAllowed;
6656 }
6657
6658 @Override
6659 public void onRelayoutContainer() {
6660 // Not currently interesting -- from changing between fixed and layout size.
6661 }
6662
Igor Murashkina86ab6402013-08-30 12:58:36 -07006663 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006664 public void setFormat(int format) {
6665 ((RootViewSurfaceTaker)mView).setSurfaceFormat(format);
6666 }
6667
Igor Murashkina86ab6402013-08-30 12:58:36 -07006668 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006669 public void setType(int type) {
6670 ((RootViewSurfaceTaker)mView).setSurfaceType(type);
6671 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006672
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006673 @Override
6674 public void onUpdateSurface() {
6675 // We take care of format and type changes on our own.
6676 throw new IllegalStateException("Shouldn't be here");
6677 }
6678
Igor Murashkina86ab6402013-08-30 12:58:36 -07006679 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006680 public boolean isCreating() {
6681 return mIsCreating;
6682 }
6683
6684 @Override
6685 public void setFixedSize(int width, int height) {
6686 throw new UnsupportedOperationException(
6687 "Currently only support sizing from layout");
6688 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006689
6690 @Override
Dianne Hackborndc8a7f62010-05-10 11:29:34 -07006691 public void setKeepScreenOn(boolean screenOn) {
6692 ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
6693 }
6694 }
Romain Guy8506ab42009-06-11 17:35:47 -07006695
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006696 static class W extends IWindow.Stub {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006697 private final WeakReference<ViewRootImpl> mViewAncestor;
Jeff Brown98365d72012-08-19 20:30:52 -07006698 private final IWindowSession mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006699
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006700 W(ViewRootImpl viewAncestor) {
6701 mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
Jeff Brown98365d72012-08-19 20:30:52 -07006702 mWindowSession = viewAncestor.mWindowSession;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006703 }
6704
Igor Murashkina86ab6402013-08-30 12:58:36 -07006705 @Override
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006706 public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Filip Gruszczynski2217f612015-05-26 11:32:08 -07006707 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
Jorim Jaggi253a20f2015-11-03 12:38:42 +01006708 Configuration newConfig, Rect backDropFrame) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006709 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006710 if (viewAncestor != null) {
Dianne Hackbornc4aad012013-02-22 15:05:25 -08006711 viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
Jorim Jaggi253a20f2015-11-03 12:38:42 +01006712 visibleInsets, stableInsets, outsets, reportDraw, newConfig, backDropFrame);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006713 }
6714 }
6715
Craig Mautner5702d4d2012-06-30 14:10:16 -07006716 @Override
6717 public void moved(int newX, int newY) {
6718 final ViewRootImpl viewAncestor = mViewAncestor.get();
6719 if (viewAncestor != null) {
6720 viewAncestor.dispatchMoved(newX, newY);
6721 }
6722 }
6723
Igor Murashkina86ab6402013-08-30 12:58:36 -07006724 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006725 public void dispatchAppVisibility(boolean visible) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006726 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006727 if (viewAncestor != null) {
6728 viewAncestor.dispatchAppVisibility(visible);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006729 }
6730 }
6731
Igor Murashkina86ab6402013-08-30 12:58:36 -07006732 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006733 public void dispatchGetNewSurface() {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006734 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006735 if (viewAncestor != null) {
6736 viewAncestor.dispatchGetNewSurface();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006737 }
6738 }
6739
Igor Murashkina86ab6402013-08-30 12:58:36 -07006740 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006741 public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006742 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006743 if (viewAncestor != null) {
6744 viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006745 }
6746 }
6747
6748 private static int checkCallingPermission(String permission) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006749 try {
6750 return ActivityManagerNative.getDefault().checkPermission(
6751 permission, Binder.getCallingPid(), Binder.getCallingUid());
6752 } catch (RemoteException e) {
6753 return PackageManager.PERMISSION_DENIED;
6754 }
6755 }
6756
Igor Murashkina86ab6402013-08-30 12:58:36 -07006757 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006758 public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006759 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006760 if (viewAncestor != null) {
6761 final View view = viewAncestor.mView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006762 if (view != null) {
6763 if (checkCallingPermission(Manifest.permission.DUMP) !=
6764 PackageManager.PERMISSION_GRANTED) {
6765 throw new SecurityException("Insufficient permissions to invoke"
6766 + " executeCommand() from pid=" + Binder.getCallingPid()
6767 + ", uid=" + Binder.getCallingUid());
6768 }
6769
6770 OutputStream clientStream = null;
6771 try {
6772 clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);
6773 ViewDebug.dispatchCommand(view, command, parameters, clientStream);
6774 } catch (IOException e) {
6775 e.printStackTrace();
6776 } finally {
6777 if (clientStream != null) {
6778 try {
6779 clientStream.close();
6780 } catch (IOException e) {
6781 e.printStackTrace();
6782 }
6783 }
6784 }
6785 }
6786 }
6787 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006788
6789 @Override
Dianne Hackbornffa42482009-09-23 22:20:11 -07006790 public void closeSystemDialogs(String reason) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006791 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006792 if (viewAncestor != null) {
6793 viewAncestor.dispatchCloseSystemDialogs(reason);
Dianne Hackbornffa42482009-09-23 22:20:11 -07006794 }
6795 }
Igor Murashkina86ab6402013-08-30 12:58:36 -07006796
6797 @Override
Marco Nelissenbf6956b2009-11-09 15:21:13 -08006798 public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
6799 boolean sync) {
Dianne Hackborn19382ac2009-09-11 21:13:37 -07006800 if (sync) {
6801 try {
Jeff Brown98365d72012-08-19 20:30:52 -07006802 mWindowSession.wallpaperOffsetsComplete(asBinder());
Dianne Hackborn19382ac2009-09-11 21:13:37 -07006803 } catch (RemoteException e) {
6804 }
6805 }
Dianne Hackborn72c82ab2009-08-11 21:13:54 -07006806 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006807
Igor Murashkina86ab6402013-08-30 12:58:36 -07006808 @Override
Dianne Hackborn75804932009-10-20 20:15:20 -07006809 public void dispatchWallpaperCommand(String action, int x, int y,
6810 int z, Bundle extras, boolean sync) {
6811 if (sync) {
6812 try {
Jeff Brown98365d72012-08-19 20:30:52 -07006813 mWindowSession.wallpaperCommandComplete(asBinder(), null);
Dianne Hackborn75804932009-10-20 20:15:20 -07006814 } catch (RemoteException e) {
6815 }
6816 }
6817 }
Christopher Tatea53146c2010-09-07 11:57:52 -07006818
6819 /* Drag/drop */
Igor Murashkina86ab6402013-08-30 12:58:36 -07006820 @Override
Christopher Tatea53146c2010-09-07 11:57:52 -07006821 public void dispatchDragEvent(DragEvent event) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006822 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006823 if (viewAncestor != null) {
6824 viewAncestor.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07006825 }
6826 }
Joe Onorato664644d2011-01-23 17:53:23 -08006827
Igor Murashkina86ab6402013-08-30 12:58:36 -07006828 @Override
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006829 public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
6830 int localValue, int localChanges) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006831 final ViewRootImpl viewAncestor = mViewAncestor.get();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006832 if (viewAncestor != null) {
Dianne Hackborn9a230e02011-10-06 11:51:27 -07006833 viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility,
6834 localValue, localChanges);
Joe Onorato664644d2011-01-23 17:53:23 -08006835 }
6836 }
Dianne Hackborn12d3a942012-04-27 14:16:30 -07006837
Igor Murashkina86ab6402013-08-30 12:58:36 -07006838 @Override
Craig Mautner9c795042014-10-28 19:59:59 -07006839 public void dispatchWindowShown() {
6840 final ViewRootImpl viewAncestor = mViewAncestor.get();
6841 if (viewAncestor != null) {
6842 viewAncestor.dispatchWindowShown();
6843 }
6844 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006845 }
6846
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006847 public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
6848 public CalledFromWrongThreadException(String msg) {
6849 super(msg);
6850 }
6851 }
6852
Alan Viverettebea0c7da2015-09-01 16:00:20 -04006853 static HandlerActionQueue getRunQueue() {
6854 HandlerActionQueue rq = sRunQueues.get();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006855 if (rq != null) {
6856 return rq;
6857 }
Alan Viverettebea0c7da2015-09-01 16:00:20 -04006858 rq = new HandlerActionQueue();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006859 sRunQueues.set(rq);
6860 return rq;
6861 }
Romain Guy8506ab42009-06-11 17:35:47 -07006862
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006863 /**
Skuhneb8160872015-09-22 09:51:39 -07006864 * Start a drag resizing which will inform all listeners that a window resize is taking place.
6865 */
6866 private void startDragResizing(Rect initialBounds) {
6867 if (!mDragResizing) {
6868 mDragResizing = true;
Chong Zhangdcee1de2015-10-06 10:26:00 -07006869 synchronized (mWindowCallbacks) {
6870 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
6871 mWindowCallbacks.get(i).onWindowDragResizeStart(initialBounds);
Skuhneb8160872015-09-22 09:51:39 -07006872 }
6873 }
6874 mFullRedrawNeeded = true;
6875 }
6876 }
6877
6878 /**
6879 * End a drag resize which will inform all listeners that a window resize has ended.
6880 */
6881 private void endDragResizing() {
6882 if (mDragResizing) {
6883 mDragResizing = false;
Chong Zhangdcee1de2015-10-06 10:26:00 -07006884 synchronized (mWindowCallbacks) {
6885 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
6886 mWindowCallbacks.get(i).onWindowDragResizeEnd();
Skuhneb8160872015-09-22 09:51:39 -07006887 }
6888 }
6889 mFullRedrawNeeded = true;
6890 }
6891 }
6892
Chong Zhang8dbd9ad2015-10-09 10:06:11 -07006893 private boolean updateContentDrawBounds() {
6894 boolean updated = false;
6895 synchronized (mWindowCallbacks) {
6896 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
6897 updated |= mWindowCallbacks.get(i).onContentDrawn(
6898 mWindowAttributes.surfaceInsets.left,
6899 mWindowAttributes.surfaceInsets.top,
6900 mWidth, mHeight);
6901 }
6902 }
6903 return updated | (mDragResizing && mReportNextDraw);
6904 }
6905
6906 private void requestDrawWindow() {
6907 if (mReportNextDraw) {
6908 mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size());
6909 }
6910 synchronized (mWindowCallbacks) {
6911 for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
6912 mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw);
6913 }
6914 }
6915 }
6916
Skuhneb8160872015-09-22 09:51:39 -07006917 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006918 * Class for managing the accessibility interaction connection
6919 * based on the global accessibility state.
6920 */
6921 final class AccessibilityInteractionConnectionManager
6922 implements AccessibilityStateChangeListener {
Igor Murashkina86ab6402013-08-30 12:58:36 -07006923 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006924 public void onAccessibilityStateChanged(boolean enabled) {
6925 if (enabled) {
6926 ensureConnection();
Chris Craikcce47eb2014-07-16 15:12:15 -07006927 if (mAttachInfo.mHasWindowFocus) {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006928 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
6929 View focusedView = mView.findFocus();
6930 if (focusedView != null && focusedView != mView) {
6931 focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
6932 }
6933 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006934 } else {
6935 ensureNoConnection();
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07006936 mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006937 }
6938 }
6939
6940 public void ensureConnection() {
Chris Craikcce47eb2014-07-16 15:12:15 -07006941 final boolean registered =
Svetoslav8e3feb12014-02-24 13:46:47 -08006942 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
Chris Craikcce47eb2014-07-16 15:12:15 -07006943 if (!registered) {
6944 mAttachInfo.mAccessibilityWindowId =
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006945 mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
6946 new AccessibilityInteractionConnection(ViewRootImpl.this));
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006947 }
6948 }
6949
6950 public void ensureNoConnection() {
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08006951 final boolean registered =
Svetoslav8e3feb12014-02-24 13:46:47 -08006952 mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006953 if (registered) {
Svetoslav8e3feb12014-02-24 13:46:47 -08006954 mAttachInfo.mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006955 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
6956 }
6957 }
6958 }
6959
Chris Craikcce47eb2014-07-16 15:12:15 -07006960 final class HighContrastTextManager implements HighTextContrastChangeListener {
6961 HighContrastTextManager() {
6962 mAttachInfo.mHighContrastText = mAccessibilityManager.isHighTextContrastEnabled();
6963 }
6964 @Override
6965 public void onHighTextContrastStateChanged(boolean enabled) {
6966 mAttachInfo.mHighContrastText = enabled;
6967
6968 // Destroy Displaylists so they can be recreated with high contrast recordings
6969 destroyHardwareResources();
Chris Craikd36a81f2014-07-17 10:16:51 -07006970
6971 // Schedule redraw, which will rerecord + redraw all text
6972 invalidate();
Chris Craikcce47eb2014-07-16 15:12:15 -07006973 }
6974 }
6975
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006976 /**
6977 * This class is an interface this ViewAncestor provides to the
6978 * AccessibilityManagerService to the latter can interact with
6979 * the view hierarchy in this ViewAncestor.
6980 */
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006981 static final class AccessibilityInteractionConnection
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006982 extends IAccessibilityInteractionConnection.Stub {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006983 private final WeakReference<ViewRootImpl> mViewRootImpl;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006984
Svetoslav Ganovf79f4762011-10-28 15:40:32 -07006985 AccessibilityInteractionConnection(ViewRootImpl viewRootImpl) {
6986 mViewRootImpl = new WeakReference<ViewRootImpl>(viewRootImpl);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07006987 }
6988
Svetoslav Ganov42138042012-03-20 11:51:39 -07006989 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07006990 public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07006991 Region interactiveRegion, int interactionId,
6992 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07006993 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07006994 ViewRootImpl viewRootImpl = mViewRootImpl.get();
6995 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07006996 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov02107852011-10-03 17:06:56 -07006997 .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07006998 interactiveRegion, interactionId, callback, flags, interrogatingPid,
6999 interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007000 } else {
7001 // We cannot make the call and notify the caller so it does not wait.
7002 try {
7003 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
7004 } catch (RemoteException re) {
7005 /* best effort - ignore */
7006 }
Svetoslav Ganov601ad802011-06-09 14:47:38 -07007007 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007008 }
7009
Svetoslav Ganov42138042012-03-20 11:51:39 -07007010 @Override
Svetoslav Ganov02107852011-10-03 17:06:56 -07007011 public void performAccessibilityAction(long accessibilityNodeId, int action,
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07007012 Bundle arguments, int interactionId,
7013 IAccessibilityInteractionConnectionCallback callback, int flags,
Svet Ganov7498efd2014-09-03 21:33:00 -07007014 int interrogatingPid, long interrogatingTid) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07007015 ViewRootImpl viewRootImpl = mViewRootImpl.get();
7016 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07007017 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07007018 .performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
Svet Ganov7498efd2014-09-03 21:33:00 -07007019 interactionId, callback, flags, interrogatingPid, interrogatingTid);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007020 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007021 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007022 try {
7023 callback.setPerformAccessibilityActionResult(false, interactionId);
7024 } catch (RemoteException re) {
7025 /* best effort - ignore */
7026 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007027 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007028 }
7029
Svetoslav Ganov42138042012-03-20 11:51:39 -07007030 @Override
Svetoslav Ganov80943d82013-01-02 10:25:37 -08007031 public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07007032 String viewId, Region interactiveRegion, int interactionId,
Svetoslav Ganov80943d82013-01-02 10:25:37 -08007033 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07007034 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07007035 ViewRootImpl viewRootImpl = mViewRootImpl.get();
7036 if (viewRootImpl != null && viewRootImpl.mView != null) {
Svetoslav Ganovaf5b4f42011-10-28 12:41:38 -07007037 viewRootImpl.getAccessibilityInteractionController()
Svetoslav Ganov80943d82013-01-02 10:25:37 -08007038 .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId,
Svetoslav9ae9ed22014-09-02 16:36:35 -07007039 viewId, interactiveRegion, interactionId, callback, flags,
7040 interrogatingPid, interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007041 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007042 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007043 try {
7044 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
7045 } catch (RemoteException re) {
7046 /* best effort - ignore */
7047 }
7048 }
7049 }
7050
Svetoslav Ganov42138042012-03-20 11:51:39 -07007051 @Override
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007052 public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
Svetoslav9ae9ed22014-09-02 16:36:35 -07007053 Region interactiveRegion, int interactionId,
7054 IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07007055 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007056 ViewRootImpl viewRootImpl = mViewRootImpl.get();
7057 if (viewRootImpl != null && viewRootImpl.mView != null) {
7058 viewRootImpl.getAccessibilityInteractionController()
7059 .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
Svetoslav9ae9ed22014-09-02 16:36:35 -07007060 interactiveRegion, interactionId, callback, flags, interrogatingPid,
7061 interrogatingTid, spec);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007062 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007063 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007064 try {
7065 callback.setFindAccessibilityNodeInfosResult(null, interactionId);
7066 } catch (RemoteException re) {
7067 /* best effort - ignore */
7068 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007069 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007070 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007071
Svetoslav Ganov42138042012-03-20 11:51:39 -07007072 @Override
Svetoslav9ae9ed22014-09-02 16:36:35 -07007073 public void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion,
7074 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07007075 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007076 ViewRootImpl viewRootImpl = mViewRootImpl.get();
7077 if (viewRootImpl != null && viewRootImpl.mView != null) {
7078 viewRootImpl.getAccessibilityInteractionController()
Svetoslav9ae9ed22014-09-02 16:36:35 -07007079 .findFocusClientThread(accessibilityNodeId, focusType, interactiveRegion,
7080 interactionId, callback, flags, interrogatingPid, interrogatingTid,
7081 spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07007082 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007083 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007084 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007085 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007086 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007087 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007088 }
7089 }
7090 }
7091
Svetoslav Ganov42138042012-03-20 11:51:39 -07007092 @Override
Svetoslav9ae9ed22014-09-02 16:36:35 -07007093 public void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion,
7094 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
Svetoslav Ganov152e9bb2012-10-12 20:15:29 -07007095 int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007096 ViewRootImpl viewRootImpl = mViewRootImpl.get();
7097 if (viewRootImpl != null && viewRootImpl.mView != null) {
7098 viewRootImpl.getAccessibilityInteractionController()
Svetoslav9ae9ed22014-09-02 16:36:35 -07007099 .focusSearchClientThread(accessibilityNodeId, direction, interactiveRegion,
7100 interactionId, callback, flags, interrogatingPid, interrogatingTid,
7101 spec);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07007102 } else {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007103 // We cannot make the call and notify the caller so it does not wait.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007104 try {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007105 callback.setFindAccessibilityNodeInfoResult(null, interactionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007106 } catch (RemoteException re) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007107 /* best effort - ignore */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007108 }
7109 }
7110 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07007111 }
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07007112
Svetoslav Ganova0156172011-06-26 17:55:44 -07007113 private class SendWindowContentChangedAccessibilityEvent implements Runnable {
Alan Viverette77e9a282013-09-12 17:16:09 -07007114 private int mChangeTypes = 0;
7115
Svetoslav Ganov42138042012-03-20 11:51:39 -07007116 public View mSource;
Svetoslav6254f482013-06-04 17:22:14 -07007117 public long mLastEventTimeMillis;
Svetoslav Ganova0156172011-06-26 17:55:44 -07007118
Igor Murashkina86ab6402013-08-30 12:58:36 -07007119 @Override
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07007120 public void run() {
Svetoslav8d820ecf2013-07-15 17:12:41 -07007121 // The accessibility may be turned off while we were waiting so check again.
7122 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
7123 mLastEventTimeMillis = SystemClock.uptimeMillis();
7124 AccessibilityEvent event = AccessibilityEvent.obtain();
7125 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
Alan Viverette77e9a282013-09-12 17:16:09 -07007126 event.setContentChangeTypes(mChangeTypes);
Svetoslav8d820ecf2013-07-15 17:12:41 -07007127 mSource.sendAccessibilityEventUnchecked(event);
7128 } else {
7129 mLastEventTimeMillis = 0;
7130 }
7131 // In any case reset to initial state.
Svetoslav6254f482013-06-04 17:22:14 -07007132 mSource.resetSubtreeAccessibilityStateChanged();
7133 mSource = null;
Alan Viverette77e9a282013-09-12 17:16:09 -07007134 mChangeTypes = 0;
Svetoslav6254f482013-06-04 17:22:14 -07007135 }
7136
Alan Viverette77e9a282013-09-12 17:16:09 -07007137 public void runOrPost(View source, int changeType) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007138 if (mSource != null) {
Svetoslav9dafebb2013-06-18 16:29:25 -07007139 // If there is no common predecessor, then mSource points to
7140 // a removed view, hence in this case always prefer the source.
7141 View predecessor = getCommonPredecessor(mSource, source);
7142 mSource = (predecessor != null) ? predecessor : source;
Alan Viverette77e9a282013-09-12 17:16:09 -07007143 mChangeTypes |= changeType;
Svetoslav6254f482013-06-04 17:22:14 -07007144 return;
7145 }
7146 mSource = source;
Alan Viverette77e9a282013-09-12 17:16:09 -07007147 mChangeTypes = changeType;
Svetoslav6254f482013-06-04 17:22:14 -07007148 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
7149 final long minEventIntevalMillis =
7150 ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
7151 if (timeSinceLastMillis >= minEventIntevalMillis) {
Svetoslav9dafebb2013-06-18 16:29:25 -07007152 mSource.removeCallbacks(this);
Svetoslav6254f482013-06-04 17:22:14 -07007153 run();
7154 } else {
7155 mSource.postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
Svetoslav Ganov79311c42012-01-17 20:24:26 -08007156 }
7157 }
7158 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007159}